023: 「ラベル付きSSCで最大値を求める」の解答¶
難易度: ☆☆☆
方針¶
ラベルは、後ろにある番地を前から参照できるようにする仕組みです。
そのため、先にすべてのラベルと番地を集めます。
2回目の走査で、命令や Data を実際の整数に変換します。
最大値のプログラムでは、a - b が正なら a を答えにします。
正でなければ、同じか b が大きいので、b を答えにします。
実装¶
def clean_line(line):
return line.split(";", 1)[0].strip()
def split_label(line):
if ":" not in line:
return (None, line)
label, rest = line.split(":", 1)
return (label.strip(), rest.strip())
def operand_value(text, labels):
try:
return int(text)
except ValueError:
if text not in labels:
raise ValueError("undefined label: " + text)
return labels[text]
def assemble_program(lines):
labels = {}
address = 0
cleaned_lines = []
for raw_line in lines:
line = clean_line(raw_line)
if line == "":
continue
label, body = split_label(line)
if label is not None:
if label in labels:
raise ValueError("duplicate label: " + label)
labels[label] = address
if body != "":
cleaned_lines.append(body)
address += 1
program = []
for body in cleaned_lines:
if body == "Stop":
program.append(encode_instruction("Jump", 0))
continue
parts = body.split()
if parts[0] == "Data":
program.append(int(parts[1]))
else:
name = parts[0]
operand = operand_value(parts[1], labels)
program.append(encode_instruction(name, operand))
return program
def maximum_program():
return [
"Read a",
"Read b",
"Load a",
"Sub b",
"Jump use_a",
"Load b",
"Store answer",
"Load one",
"Jump output",
"use_a: Load a",
"Store answer",
"output: Write answer",
"Stop",
"a: Data 0",
"b: Data 0",
"answer: Data 0",
"one: Data 1",
]
def max_with_ssc(a, b):
program = assemble_program(maximum_program())
outputs = run(program, [a, b])
return outputs[0]
確認¶
program = assemble_program([
"Load value",
"Shift 1",
"Store value",
"Write value",
"Stop",
"value: Data 21",
])
assert run(program) == [42]
assert max_with_ssc(7, 9) == 9
assert max_with_ssc(12, 4) == 12
assert max_with_ssc(5, 5) == 5
assert max_with_ssc(-3, -8) == -3
発展¶
3つの入力に拡張するには、まず2つの最大値を求め、その結果と3つ目の値をもう一度比較します。 同じ比較ブロックをどう再利用するかが課題になります。