在Advent of Code de 2022的同一天,有一个有趣的问题,可以讨论生成功能的责任分配。
第十个问题
第10天"tubo de raios catódicos"的问题包括实施简单的仿真器。在第1部分中,应执行处理器的指令进行解码和执行,而在第2部分中,应实施卷。我建议尝试先解决它。
政党决议1
第1部分要求阅读输入指令,执行它们,以考虑每种指令导致的周期数量,并且在某些周期中进行计算以获取答案,并将结果保持在累加器中。在此描述中,可以通过不同的责任来确定:阅读和处理入口的指示;控制处理器中指令的执行及其必要的周期;并控制当前周期,使所需的值。通过分开这些责任,一种写作功能的方式是使用Python Generator,因为它们允许它们执行一系列的交叉,停止和稍后返回,这使每个功能都可以专注于其责任,而无需混合。 P>
可以处理条目的功能,可以作为发电机来完成文件,该发电机将文件固定并返回每个仪器的值已转换为其值(指令具有额外的值时)。对于noop
指令,仅是Abiaoqian指令的信息。虽然addx
仪器也具有整数值,要添加到x
注册商中。这是一个示例,其中每个值由发电机返回的每个值是一个列表,其中包含第一个位置的仪器,而与之关联的整数在存在时,在第二个位置:
def ler_instrucoes(entrada):
for linha in entrada:
instrucao = linha.strip().split(' ')
if len(instrucao) >= 2:
instrucao[1] = int(instrucao[1])
yield instrucao
此生成器允许在执行指令时加载和提交输入,而不是将所有内容都带到内存,也不是首先处理整个输入,然后再进入问题的下一部分。除了简化执行操作的人的过程外,不必担心类型的对话。
也可以通过发电机执行指令。由于发电机允许您执行十字架并停止,因此可以用于模拟处理器周期,在该周期中,发电机返回的每个值代表处理器中的状态,在此问题中,这将归结为值koude寄存器2,可以作为生成函数的位置实现。以下是代码的示例:
def processador(instrucoes):
x = 1
for instrucao in instrucoes:
if instrucao[0] == 'noop':
yield x
elif instrucao[0] == 'addx':
yield x
yield x
x += instrucao[1]
此功能是ITRA,一组指令作为参数(上面介绍的生成器)并执行这些说明。在noop
仪器的情况下,什么也没做,yield x
在这一点上使生成器停止,需要读取处理器生成器以继续执行。这样,模拟了处理器周期。 addx
指令已经有两个yield x
,因此有必要更多地读取值,以便最终将指令的价值添加到x
寄存器中,模拟处理器停止了两个周期,以便在他们的末尾健康完成的指令。
通过指令和处理器进行解码,只需实例化koud10的生成器和koudde11函数之一,将第一个作为参数传递给第二个。由于第二个发电机负责迭代第一个(他在此迭代器中进行for
),因此仅在第二个迭代器中进行iTera,以模拟指令的周期和执行,以及当使用koude13â时,可以知道哪个周期可以知道执行是并执行所需的操作以计算问题要求的金额。以下是代码的示例:
p = processador(ler_instrucoes(open('entrada.txt')))
total = 0
for i, x in enumerate(p, start=1):
if (i - 20) % 40 == 0:
total += i * x
if i == 220:
break
print(total)
第2部分的解决
了解如何解码指令并控制其执行周期,第2部分要求模拟阴极射线管屏幕。该屏幕有一些规则,例如一次显示一个像素,每40个像素,都可以转到下面的行,重新启动该过程。这也可以作为生成器实现,封装了这些规则,poring而不是返回值,他必须接收值,该值也称为消费者,但具有相同的语法,有所不同,而不是使用yield x
来返回x
value,被使用x = yield
将接收到的金额存储在差异中,并且仍然具有停止代码执行的功能,在这种情况下,等待下一个值。以下是实现的示例:
def crt():
while True:
for i in range(40):
x = yield
if x - 1 <= i <= x + 1:
print('\u2588', end='')
else:
print(' ', end='')
print()
此函数是一个无限循环,它在屏幕上运行40个值打印一个bloco preenchido或一个空间(我进行了更改,因为它促进了可视化结果),根据收到的x
寄存器的值,以及之后,将线路断开。
由于函数ler_instrucoes
和processador
已经实现,并且没有必要在电线上进行更改,只需将消费者crt
附加到他们所需的结果即可。像创建发电机一样移植,没有执行相同的代码要读取,必须实例化消费者crt
并进行第一个执行,以便它停止在yield
中并准备好接收第一个值,可以使用该值来完成koude23函数,以及可以恢复发电机值的功能。这是此实现的一个示例:
tela = crt()
next(tela)
for x in processador(ler_instrucoes(open('entrada.txt'))):
tela.send(x)
考虑
使用发电机允许实现代码,除了将处理器控制规则封装在函数中,而没有另一件事,将处理器控制规则封装在函数和屏幕中,而没有混合两件事,使它们无法放置,这使得它们且屏幕均未放置,这使得它们没有放置。可以单独使用。尽管电线是分开的,但执行将它们插入它们,好像是em loop , 在屏幕上执行并显示了结果的角色,我将重复这些操作,这允许它如前所述,要有效地与内存的使用有关。
发电机也是一种作为语言功能进入python的纯腐肌蛋白或Asancroned功能的方式,我建议对该主题的Dunossauro的San©rie rie "Geradores e uma Introdução histórica à corrotinas com Python"。
。