【问题标题】:Algorith problem Decode Hex to set output算法问题 Decode Hex to set output
【发布时间】:2019-08-30 03:24:52
【问题描述】:

我有一个算法需要解决。不幸的是,我什至找不到有关解决方案的线索。请帮助我了解如何解决此问题。

问题

一个虚构的笔输入设备将十六进制数据发送到设备以显示一条带颜色的线。

示例绘制简单的绿线
将颜色设置为绿色,从 (0,0) 到 (4000, 4000) 画一条线。此图中的实心圆圈表示笔向下 位置,空心圆圈表示上笔位置。

输入数据:F0A04000417F4000417FC040004000804001C05F205F20804000

输出:
CLR;一氧化碳 0 255 0 255;
MV (0, 0);
下笔;
MV (4000, 4000);
PEN UP;

我得到了关于每个输出的信息。

此代码用于将十六进制编码为二进制。我猜该解决方案会将十六进制编码为二进制,并对其进行操作以设置正确的输出。

function hex2bin(hex){
    return (parseInt(hex, 16).toString(2))}

预期结果与输入数据的示例具有相同的输出。

【问题讨论】:

  • 你了解计算机内部数据格式和人类阅读的文本表示之间的区别吗?
  • 据我了解,内部计算机数据表示为“010101”或“A0F0”,仅使用 0 和 1 或十六进制。请让我知道我是对还是错。以及如何利用这些知识来解决这个问题。
  • 有字节。我们可以看到与整数 65、十六进制 0x41、二进制 0100 0001、ASCII 字符“A”相同的字节。因此,值得指定输入数据的含义。 sends hex data???

标签: javascript algorithm bit-manipulation bitwise-operators


【解决方案1】:

首先,您的问题中缺少一些重要信息:4000 等数字(在结果中)如何以十六进制格式编码。

我想我可以从这个例子中得到它

特殊的数字编码

数字似乎每个都用 2 个字节(4 个十六进制字符)编码,其中这 2 个字节的最高有效位(第 7 位和第 15 位)对值没有贡献(它们始终为零)。

此外,剩余的 14 位在offset binary 中编码,其中 14 位的最高有效位是反转符号位。

这意味着“4000”为零,“0000”为-8192(最小值),“7F7F”为8191(最大值)。请注意,最后一个字符不能超过 7,因为这会设置此(自定义)编码中未使用的位。

这是从您提供的少量信息中得出的最难的部分。

关于例子

您提供的输入示例可以分解成这样的部分:

opcode | argument(s)
-------+----------------------------
 "F0"  |
 "A0"  | "4000" "417F" "4000" "417F"
 "C0"  | "4000" "4000" 
 "80"  | "4001" 
 "C0"  | "5F20" "5F20"
 "80"  | "4000"

使用上面讨论的数字转换,这将转化为:

opcode | argument(s)
-------+------------
  240  |
  160  | 0 255 0 255
  192  | 0 0
  128  | 1
  192  | 4000 4000
  128  | 0

然后按照说明将其转换为所需的输出即可。

因此该算法可以首先将输入字符串解码为命令,其中每个命令由一个操作码和零个或多个数字参数组成。

然后可以通过跟踪笔是否向下以及当前坐标是什么来将这些命令转换为所需的输出:

function decode(hex) {
    let commands = [];
    let command;
    for (let i = 0, len; i < hex.length; i+=len) {
        // Opcodes take 1 byte (i.e. 2 hex characters), and 
        // numbers take 2 bytes (4 characters)
        len = hex[i] >= "8" ? 2 : 4;
        let num = parseInt(hex.slice(i, i+len), 16);
        if (len === 2) { // opcode
            command = []; // start a new command
            commands.push(command);
        } else { // number
            // The encoded format is a custom one. This seems to be it:
            num = ((num & 0x7F00) >> 1) + (num & 0x7F) - 0x2000; 
        }
        command.push(num); // push opcode or argument in current command
    }
    return commands;
}

function disassemble(hex) {
    let isPenDown = false;
    let x = 0, y = 0;
    let output = "";
    let commands = decode(hex);
    for (let [opcode, ...args] of commands) {
        if (opcode === 0xF0) {
            x = y = 0;
            isPenDown = false;
            output += "CLR;\n";
        } else if (opcode === 0x80) {
            isPenDown = args[0] > 0;
            output += "PEN " + (isPenDown ? "DOWN" : "UP") + ";\n";
        } else if (opcode === 0xA0) {
            output += "CO " + args.join(" ") + ";\n";
        } else if (opcode === 0xC0) {
            let allPos = "", lastPos;
            for (let i = 0; i < args.length; i+=2) {
                x += args[i];
                y += args[i+1];
                lastPos = ` (${x}, ${y})`;
                if (isPenDown) allPos += lastPos;
            }
            output += "MV" + (allPos || lastPos) + ";\n";
        } // else: ignore unknown commands
    }
    return output;
}

// Sample:
console.log(disassemble("F0A04000417F4000417FC040004000804001C05F205F20804000"));

更多工作

在问题的屏幕截图中,接近结尾处还提到了对边界框的剪切运动。这超出了您关于解码十六进制输入的问题,所以我将保留它。有兴趣的可以查看计算线段交点的Q&A,如this one

【讨论】:

  • 感谢您的精彩评论。它对我有很大帮助。你说的对。我没有描述如何解码该值。你的假设是正确的。该数量限制为 14 位(2 个字节)。请允许我问更多问题。我应该通过操作码解析值。例如,按操作码对输入进行排序,然后将值推送到操作码之后,直到出现新的操作码。我的问题是如何对数据进行排序和解析,因为信息包含相同的十六进制范围,所以我不知道如何确定操作码的操作码或值。
  • 字节是 2 个十六进制字符。当第一个字符为 8 或更多时,它是一个操作码。您可以在我提供的代码中看到该条件...其中定义了 len
  • 很抱歉给您分配其他问题作为重复问题的麻烦。我误解了您的回答,现在认识到您的回答是解决问题的完美方案。
猜你喜欢
  • 2012-07-26
  • 2018-09-23
  • 1970-01-01
  • 1970-01-01
  • 2021-05-16
  • 1970-01-01
  • 1970-01-01
  • 2019-02-05
  • 1970-01-01
相关资源
最近更新 更多