阴极射线管
废话似乎是我们昨天的绳索物理学知识没有帮助,我们在河里结束了...
精灵无处可寻,我们的通信系统吐出奇怪的信号和噪音
幸运的是,我们可能只需要立即启动并运行该设备,我们只需要对设备的视频系统进行替换。
为此,我们需要从CPU和寄存器值进行解码
我们获得了CPU输出,并告诉每个操作需要Y
循环完成,例如:
noop
addx 3
addx -5
- addx-进行两轮,将右手值添加到x
- noop-一轮,什么都不做
解析
首先,创建一个新的Instruction
struct
type Instruction struct {
cycles int
value int
}
与前几天相比,这里的解析是一块蛋糕
func parse(raw string) (instructions []*Instruction) {
lines := strings.Split(string(raw), "\n")
for _, l := range lines {
if strings.Contains(l, "noop") {
instructions = append(instructions, &Instruction{cycles: 1, value: 0})
} else {
parts := strings.Split(l, " ")
instructions = append(instructions, &Instruction{cycles: 2, value: util.ParseInt(parts[1])})
}
}
return
}
您可能会注意到我们的函数签名有点怪异,它以(instructions []Instruction)
结尾,并且在功能末尾什么也没返回。
该语法在我们函数的顶部创建一个变量,最后一个返回语句称为“裸”返回,默认情况下返回instructions
。
我认为,它不应用于具有超过几行代码的任何功能,而是应该使用命名变量和return instructions
,但是为了学习新事物,我们将坚持使用“裸”返回(我有点喜欢那个术语)
第1部分
我们需要在各种CPU周期中的寄存器x*中进行采样,更精确地是在20th, 60th, 100th, 140th, 180th, and 220th
周期期间
在此类问题中没有某种陷阱(通常),大多数模拟问题只需要仔细阅读,然后直接应用代码中的说明
直接来自AOC
addx V需要两个循环完成。 两个周期后,值V增加了X寄存器。(V可能为负。
noop需要一个周期来完成。它没有其他效果。
这里要注意的是,指令值仅在之后才生效特定的周期数已通过
那么我们的解决方案需要做什么?
- 遍历每个指令
- 跟踪系统
ticks
(与周期不同) - 跟踪X
- 每个间隔中的x样品x
- 运行每个指令y周期数
- 每次指令后更新X
我们正在添加一个ticks
的概念,每次运行中都会发生滴答
func Part1(raw string) int {
instructions := parse(raw)
x := 1
result := 0
ticks := 0
for _, ci := range instructions {
for j := 0; j < ci.cycles; j++ {
ticks++ // updating ticks on every cycle
if ticks%20 == 0 && ticks%40 != 0 {
result += x * ticks
}
}
x += ci.value
}
return result
}
第2部分
使用x的值在每个滴答过程中我们需要在屏幕上画一些东西
我们的屏幕宽40像素,其高度为6像素
没有垂直位置的概念,这意味着我们的x值需要翻译成我们在40*6
上定义的范围我们被告知有一个sprite
3像素长,而x
值决定了她的中心位置。
在每个周期中,我们在屏幕中碰到我们的位置,如果当前位置包括当前绘制的像素,我们说它 lit 并绘制#
,否则它的 dark ,我们绘制.
p>
输出应该是一系列字符,这将是我们的答案!那对吗?
这个问题比第1部分更棘手,但最主要的是仔细阅读说明并将其翻译回代码
首先,让我们创建一个屏幕!
func printCrt(crt [][]string) {
for i, r := range crt {
fmt.Println(i, r)
}
}
func makeCrt() [][]string {
crt := make([][]string, 6)
for i, _ := range crt {
crt[i] = make([]string, 40)
}
return crt
}
接下来是我们的逻辑
func Part2(raw string) {
instructions := parse(raw)
crt := makeCrt()
x := 1
ticks := 0
for _, ci := range instructions {
for j := 0; j < ci.cycles; j++ {
row := int(ticks / 40)
col := ticks % 40
d := util.Abs(col - x)
if d < 2 {
crt[row][col] = "#"
} else {
crt[row][col] = "."
}
ticks++
}
x += ci.value
}
print(crt)
}
并非所有这里的一切都很明显,所以让我们逐一浏览棘手的行:
row := int(ticks / 40)
我们知道每行都是40行,因此我们可以将数字滴答除名每行的宽度以确定我们应该相对于CRT,例如30/40 -> 0, 90/40 -> 2
等。
col := ticks%40
我们有一个长度为40的“窗口”,值正在增加,但我们仍然想落入该值的较小之中,例如30%40 -> 30, 50%40 -> 10 (second row 10th pixel), 220%40 -> 20
等...
d := util.Abs(col - x)
我们的三角洲来自精灵的中心,如果它小于2(请记住x是精灵的中心),我们绘制了 lit 像素,否则我们绘制了 dark 像素
通过我的输入,我得到了以下输出,您呢?
就是今天,明天见,
您可以找到完整的代码here
感谢您的阅读!