-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
276 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
asd.txt | ||
asd.png |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
For all bits except the first and the last, there are 5 logic gates. | ||
|
||
InputXor: | ||
Inputs: xnn, ynn (e.g. x05, y05) | ||
Output: 1 if exactly one input is on, 0 if neither or both | ||
|
||
InputAnd: | ||
Inputs: xnn, ynn (e.g. x05, y05) | ||
Output: 1 if both inputs are on, 0 otherwise | ||
|
||
OutputXor (missing for first bit, output taken directly from InputXor) | ||
Inputs: result of InputXor, result of previous OverflowXor | ||
Output: value of znn | ||
|
||
OverflowAnd | ||
Inputs: result of InputXor, overflow n-1 | ||
Output: 1 if we overflow with inputs 1,0 or 0,1 due to carrying | ||
0 if we either don't overflow, or the overflow doesn't involve carrying | ||
|
||
OverflowOr | ||
Inputs: result of InputAnd, result of OverflowAnd | ||
Output: 1 if we overflow, either with input 1,1 or through OverflowAnd | ||
0 if we don't overflow |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,251 @@ | ||
# The following commands can be used to create asd.png, which contains a nice | ||
# picture of the input as a graph: | ||
# | ||
# echo 'digraph G {' > asd.txt | ||
# grep -- '->' sampleinput.txt | awk '{print $1 "->" $5 " [label="$2"]\n"$3"->"$5" [label="$2"]"}' >> asd.txt | ||
# echo '}' >> asd.txt | ||
# dot -Tpng -o asd.png asd.txt | ||
|
||
|
||
import "stdlib/str.jou" | ||
import "stdlib/ascii.jou" | ||
import "stdlib/io.jou" | ||
|
||
|
||
# The sum calculator consists of 45 adders and outputs 46 bits z00,z01,...,z45. | ||
# Each adder (except the first and last) consists of the following 5 logic gates. | ||
enum GateType: | ||
# Inputs: xnn, ynn (e.g. x05 and y05) | ||
# Output: 1 if inputs are 1,0 or 0,1 | ||
# 0 if inputs are 1,1 or 0,0 | ||
# Purpose: Used for both output and overflow checking | ||
InputXor | ||
|
||
# Inputs: xnn, ynn | ||
# Output: 1 if inputs are 1,1 | ||
# 0 if inputs are anything else | ||
# Purpose: Used to detect overflow | ||
InputAnd | ||
|
||
# Inputs: result of InputXor, carry bit from previous level | ||
# Output: value of znn (the output bit of x+y) | ||
# Purpose: Calculates the sum of the two numbers | ||
OutputXor | ||
|
||
# Inputs: result of InputXor, carry bit from previous level | ||
# Output: 1 if we overflow when adding bits 1,0 or 0,1 due to carrying | ||
# 0 if there's no overflow, or the overflow happens due to input 1,1 | ||
# Purpose: Creates intermediate value used when calculating overflow/carry | ||
OverflowAnd | ||
|
||
# Inputs: result of InputAnd, result of OverflowAnd | ||
# Output: 1 if we overflow in any way, due to input 1,1 or carrying | ||
# 0 if there is no overflow | ||
# Purpose: This is the overflow/carry bit sent to the next adder | ||
OverflowOr | ||
|
||
|
||
class Gate: | ||
inputs: byte[4][2] | ||
output: byte[4] | ||
level: int | ||
gtype: GateType | ||
|
||
def print(self) -> None: | ||
if self->gtype == GateType::InputXor: | ||
printf("InputXor") | ||
elif self->gtype == GateType::InputAnd: | ||
printf("InputAnd") | ||
elif self->gtype == GateType::OutputXor: | ||
printf("OutputXor") | ||
elif self->gtype == GateType::OverflowAnd: | ||
printf("OverflowAnd") | ||
elif self->gtype == GateType::OverflowOr: | ||
printf("OverflowOr") | ||
else: | ||
assert False | ||
|
||
printf(": %s XOR %s -> %s", self->inputs[0], self->inputs[1], self->output) | ||
if self->level != -1: | ||
printf(" [level=%d]", self->level) | ||
printf("\n") | ||
|
||
|
||
def check_gtype_counts(gates: Gate*, ngates: int) -> None: | ||
counts = [0, 0, 0, 0, 0] | ||
for i = 0; i < ngates; i++: | ||
counts[gates[i].gtype as int]++ | ||
|
||
assert counts[InputXor | ||
input_xors = 0 | ||
input_ands = 0 | ||
output_xors = 0 | ||
overflow_ands = 0 | ||
overflow_ors = 0 | ||
|
||
|
||
# Due to carrying, every gate affects the last output z45 somehow. | ||
# | ||
def sort_gates_by_distance_from_z45 | ||
|
||
|
||
# Determines how badly the sum machine seems to be wired. | ||
# Zero is a machine that is working as expected. | ||
def calculate_score(gates: Gate*, ngates: int) -> int: | ||
input_xors: Gate*[45] | ||
input_ands: Gate*[45] | ||
# First adder only has input xors (used for output) and input ands (used for overflow/carry) | ||
output_xors: Gate*[44] | ||
overflow_ands: Gate*[44] | ||
overflow_ors: Gate*[44] | ||
|
||
counts = [0, 0, 0, 0, 0] | ||
for i = 0; i < ngates; i++: | ||
counts[gates[i].gtype as int]++ | ||
|
||
assert counts[InputXor as int] == 45 | ||
assert counts[InputAnd as int] == 45 | ||
assert counts[OutputXor as int] == 44 | ||
assert counts[OverflowAnd as int] == 44 | ||
assert counts[OverflowOr as int] == 44 | ||
|
||
# Just put the things to the arrays, in any order | ||
memset(counts, 0, sizeof(counts)) | ||
|
||
|
||
for i = 0; i < ngates; i++: | ||
if gates[i].gtype == GateType::InputXor: | ||
input_xors | ||
|
||
|
||
def goes_to_1_gate( | ||
gates: Gate*, | ||
ngates: int, | ||
wire: byte*, | ||
gtype: GateType, | ||
) -> bool: | ||
found = False | ||
|
||
for i = 0; i < ngates; i++: | ||
if strcmp(gates[i].inputs[0], wire) == 0 or strcmp(gates[i].inputs[1], wire) == 0: | ||
if gates[i].gtype != gtype: | ||
return False | ||
if found: | ||
# it goes to two gates, both of the given type | ||
return False | ||
found = True | ||
|
||
return found | ||
|
||
|
||
def goes_to_2_gates( | ||
gates: Gate*, | ||
ngates: int, | ||
wire: byte*, | ||
gtype1: GateType, | ||
gtype2: GateType, | ||
) -> bool: | ||
assert gtype1 != gtype2 | ||
|
||
found1 = False | ||
found2 = False | ||
|
||
for i = 0; i < ngates; i++: | ||
if strcmp(gates[i].inputs[0], wire) == 0 or strcmp(gates[i].inputs[1], wire) == 0: | ||
if gates[i].gtype == gtype1: | ||
if found1: | ||
return False | ||
found1 = True | ||
elif gates[i].gtype == gtype2: | ||
if found2: | ||
return False | ||
found2 = True | ||
else: | ||
return False | ||
|
||
return found1 and found2 | ||
|
||
|
||
def main() -> int: | ||
gates: Gate[500] | ||
ngates = 0 | ||
|
||
f = fopen("input", "r") | ||
assert f != NULL | ||
|
||
line: byte[100] | ||
while fgets(line, sizeof(line) as int, f) != NULL: | ||
trim_ascii_whitespace(line) | ||
if line[0] == '\0': | ||
# end of initial values, start of logic gates | ||
break | ||
|
||
g: Gate | ||
op: byte[4] | ||
while fscanf(f, "%3s %3s %3s -> %3s\n", &g.inputs[0], op, &g.inputs[1], &g.output) == 4: | ||
# Inputs that don't come from other gates cannot be connected wrong, so | ||
# the wiring mistakes don't mess this up. | ||
if ( | ||
(g.inputs[0][0] == 'x' and g.inputs[1][0] == 'y') | ||
or (g.inputs[0][0] == 'y' and g.inputs[1][0] == 'x') | ||
): | ||
# Handles input directly, so it must be InputXor or InputAnd | ||
if strcmp(op, "XOR") == 0: | ||
g.gtype = GateType::InputXor | ||
elif strcmp(op, "AND") == 0: | ||
g.gtype = GateType::InputAnd | ||
else: | ||
assert False | ||
g.level = atoi(&g.inputs[0][1]) # Example: x05 --> 5 | ||
else: | ||
if strcmp(op, "XOR") == 0: | ||
g.gtype = GateType::OutputXor | ||
elif strcmp(op, "AND") == 0: | ||
g.gtype = GateType::OverflowAnd | ||
elif strcmp(op, "OR") == 0: | ||
g.gtype = GateType::OverflowOr | ||
else: | ||
assert False | ||
g.level = -1 # unknown | ||
|
||
assert ngates < sizeof(gates)/sizeof(gates[0]) | ||
gates[ngates++] = g | ||
|
||
for i = 0; i < ngates; i++: | ||
# Most InputAnd gates should connect to an OverflowOr. | ||
if ( | ||
gates[i].gtype == GateType::InputAnd | ||
and gates[i].level != 0 | ||
and not goes_to_1_gate(gates, ngates, gates[i].output, GateType::OverflowOr) | ||
): | ||
printf("sus1 %s\n", gates[i].output) | ||
|
||
# First InputAnd produces the overflow bit directly, so it connects to | ||
# the next OutputXor and OverflowAnd. | ||
if ( | ||
gates[i].gtype == GateType::InputAnd | ||
and gates[i].level == 0 | ||
and not goes_to_2_gates(gates, ngates, gates[i].output, GateType::OutputXor, GateType::OverflowAnd) | ||
): | ||
printf("sus2 %s\n", gates[i].output) | ||
|
||
# Most InputXor gates should connect to an OutputXor and OverflowAnd. | ||
if ( | ||
gates[i].gtype == GateType::InputXor | ||
and gates[i].level != 0 | ||
and not goes_to_2_gates(gates, ngates, gates[i].output, GateType::OutputXor, GateType::OverflowAnd) | ||
): | ||
printf("sus3 %s\n", gates[i].output) | ||
|
||
# First InputXor gate produces the first output directly. | ||
if ( | ||
gates[i].gtype == GateType::InputXor | ||
and gates[i].level == 0 | ||
and strcmp(gates[i].output, "z00") != 0 | ||
): | ||
printf("sus4 %s\n", gates[i].output) | ||
|
||
|
||
|
||
fclose(f) | ||
return 0 |