-
Notifications
You must be signed in to change notification settings - Fork 0
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
Anthony Hayward
committed
May 15, 2020
1 parent
7932081
commit 9b39650
Showing
6 changed files
with
442 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,5 @@ | ||
*.beam | ||
*.exe | ||
*.pdb | ||
*.pyc | ||
target |
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,24 @@ | ||
``` | ||
erl | ||
``` | ||
|
||
then | ||
|
||
``` | ||
c("computer"). | ||
c("day11_robot_part_1"). | ||
day11_robot_part_1:paint_hull(). | ||
# 1747 | ||
c("day11_robot_part_2"). | ||
day11_robot_part_2:paint_hull(). | ||
XXXXXXXX XXXX XXXX XXXXXX XX XX XX XX XX XXXXXX | ||
XX XX XX XX XX XX XX XX XX XX XX XX XX XX | ||
XX XX XX XX XX XXXXXXXX XXXX XX XXXXXX | ||
XX XX XX XXXX XXXXXX XX XX XX XX XX XX XX | ||
XX XX XX XX XX XX XX XX XX XX XX XX XX XX | ||
XXXXXXXX XXXX XXXXXX XX XX XX XX XX XX XXXXXXXX XXXXXX | ||
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,173 @@ | ||
-module(computer). | ||
|
||
-export([load_program/1, set_inputs/2, exec/1, get_outputs/1, clear_outputs/1, get_state/1]). | ||
|
||
|
||
-record(computer, { | ||
mem, % memory contents | ||
ip, % instruction pointer | ||
relative_base, % base for relative mode access | ||
state, % waiting for input or halted? | ||
inputs, % list of available input values | ||
outputs, % list of available output values | ||
output_connections | ||
}). | ||
|
||
|
||
peek(Mem, Address) when Address < length(Mem) -> | ||
lists:nth(Address + 1, Mem); | ||
peek(_, _) -> | ||
0. | ||
|
||
|
||
read(Mem, Address, RelativeBase, Mode) -> | ||
Index = peek(Mem, Address), | ||
case Mode of | ||
indirect -> peek(Mem, Index); | ||
direct -> Index; | ||
relative -> peek(Mem, RelativeBase + Index) | ||
end. | ||
|
||
|
||
address_from(Mem, Address, RelativeBase, Mode) -> | ||
Index = peek(Mem, Address), | ||
case Mode of | ||
indirect -> Index; | ||
direct -> error; | ||
relative -> RelativeBase + Index | ||
end. | ||
|
||
|
||
poke(Mem, Address, Value) when Address < length(Mem) -> | ||
lists:sublist(Mem, Address) ++ [Value] ++ lists:nthtail(Address + 1, Mem); | ||
poke(Mem, Address, Value) when Address =:= length(Mem) -> | ||
Mem ++ [Value]; | ||
poke(Mem, Address, Value) -> | ||
poke(Mem ++ [0], Address, Value). | ||
|
||
|
||
param_mode(ParamSpec) -> | ||
case ParamSpec of | ||
0 -> indirect; | ||
1 -> direct; | ||
2 -> relative | ||
end. | ||
|
||
|
||
read_param_1(#computer{mem=Mem, ip=IP, relative_base=RelativeBase}) -> | ||
read(Mem, IP + 1, RelativeBase, param_mode((peek(Mem, IP) div 100) rem 10)). | ||
|
||
|
||
read_param_2(#computer{mem=Mem, ip=IP, relative_base=RelativeBase}) -> | ||
read(Mem, IP + 2, RelativeBase, param_mode((peek(Mem, IP) div 1000) rem 10)). | ||
|
||
|
||
address_from_param_1(#computer{mem=Mem, ip=IP, relative_base=RelativeBase}) -> | ||
address_from(Mem, IP + 1, RelativeBase, param_mode((peek(Mem, IP) div 100) rem 10)). | ||
|
||
|
||
address_from_param_3(#computer{mem=Mem, ip=IP, relative_base=RelativeBase}) -> | ||
address_from(Mem, IP + 3, RelativeBase, param_mode((peek(Mem, IP) div 10000) rem 10)). | ||
|
||
|
||
exec(Computer) -> | ||
Mem = Computer#computer.mem, | ||
IP = Computer#computer.ip, | ||
Cmd = peek(Mem, IP), | ||
case Cmd rem 100 of | ||
1 -> % add | ||
A = read_param_1(Computer), | ||
B = read_param_2(Computer), | ||
ResultAddress = address_from_param_3(Computer), | ||
exec(Computer#computer{mem=poke(Mem, ResultAddress, A + B), ip=IP + 4}); | ||
2 -> % mul | ||
A = read_param_1(Computer), | ||
B = read_param_2(Computer), | ||
ResultAddress = address_from_param_3(Computer), | ||
exec(Computer#computer{mem=poke(Mem, ResultAddress, A * B), ip=IP + 4}); | ||
3 -> % input | ||
ResultAddress = address_from_param_1(Computer), | ||
case Computer#computer.inputs of | ||
[InputValue|Rest] -> | ||
exec(Computer#computer{mem=poke(Mem, ResultAddress, InputValue), ip=IP + 2, inputs=Rest}); | ||
[] -> | ||
Computer#computer{state=waiting_for_input} | ||
end; | ||
4 -> % output | ||
A = read_param_1(Computer), | ||
exec(Computer#computer{ip=IP + 2, outputs=Computer#computer.outputs ++ [A]}); | ||
5 -> % jump if true | ||
A = read_param_1(Computer), | ||
B = read_param_2(Computer), | ||
case A of | ||
0 -> | ||
exec(Computer#computer{ip=IP + 3}); | ||
_ -> | ||
exec(Computer#computer{ip=B}) | ||
end; | ||
6 -> % jump if false | ||
A = read_param_1(Computer), | ||
B = read_param_2(Computer), | ||
case A of | ||
0 -> | ||
exec(Computer#computer{ip=B}); | ||
_ -> | ||
exec(Computer#computer{ip=IP + 3}) | ||
end; | ||
7 -> % less than | ||
A = read_param_1(Computer), | ||
B = read_param_2(Computer), | ||
ResultAddress = address_from_param_3(Computer), | ||
R = if A < B -> 1; true -> 0 end, | ||
exec(Computer#computer{mem=poke(Mem, ResultAddress, R), ip=IP + 4}); | ||
8 -> % equals | ||
A = read_param_1(Computer), | ||
B = read_param_2(Computer), | ||
ResultAddress = address_from_param_3(Computer), | ||
R = if A =:= B -> 1; true -> 0 end, | ||
exec(Computer#computer{mem=poke(Mem, ResultAddress, R), ip=IP + 4}); | ||
9 -> % add to relative base | ||
A = read_param_1(Computer), | ||
exec(Computer#computer{relative_base=Computer#computer.relative_base + A, ip=IP + 2}); | ||
99 -> % halt | ||
Computer#computer{state=halted} | ||
end. | ||
|
||
|
||
parse_line(CurrentInstruction, [$,|Rest]) -> | ||
[list_to_integer(CurrentInstruction)] ++ parse_line("", Rest); | ||
parse_line(CurrentInstruction, "\n") -> | ||
[list_to_integer(CurrentInstruction)]; | ||
parse_line(CurrentInstruction, "") -> | ||
[list_to_integer(CurrentInstruction)]; | ||
parse_line(CurrentInstruction, [A|Rest]) -> | ||
parse_line(CurrentInstruction ++ [A], Rest). | ||
|
||
|
||
load_program(Device) -> | ||
case io:get_line(Device, "") of | ||
eof -> | ||
error; | ||
Line -> | ||
#computer{ | ||
mem=parse_line("", Line), ip=0, relative_base=0, state=ready, | ||
inputs=[], | ||
outputs=[], output_connections=output | ||
} | ||
end. | ||
|
||
|
||
set_inputs(Computer, Inputs) -> | ||
Computer#computer{inputs=Inputs}. | ||
|
||
|
||
get_outputs(#computer{outputs=Outputs}) -> | ||
Outputs. | ||
|
||
|
||
clear_outputs(Computer) -> | ||
Computer#computer{outputs=[]}. | ||
|
||
|
||
get_state(#computer{state=State}) -> | ||
State. |
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,48 @@ | ||
-module(day11_robot_part_1). | ||
|
||
-import(computer, [load_program/1, set_inputs/2, exec/1, get_outputs/1, clear_outputs/1, get_state/1]). | ||
-export([paint_hull/0]). | ||
|
||
|
||
-record(robot, { | ||
x, | ||
y, | ||
xd, | ||
yd | ||
}). | ||
|
||
|
||
paint_hull() -> | ||
{ok, Device} = file:open("../data/puzzle_input.csv", [read]), | ||
Computer = try computer:load_program(Device) | ||
after file:close(Device) | ||
end, | ||
map_size(do_paint_hull(Computer, #robot{x=0, y=0, xd=0, yd=-1}, #{})). | ||
|
||
|
||
get_panel_colour(Hull, X, Y) -> | ||
try maps:get({X, Y}, Hull) | ||
catch | ||
error:_ -> 0 | ||
end. | ||
|
||
|
||
paint_panel(Hull, X, Y, Colour) -> | ||
maps:put({X, Y}, Colour, Hull). | ||
|
||
|
||
do_paint_hull(Computer, #robot{x=X, y=Y, xd=XD, yd=YD}, Hull) -> | ||
Colour = get_panel_colour(Hull, X, Y), | ||
NewComputer = computer:exec(computer:set_inputs(Computer, [Colour])), | ||
case computer:get_state(NewComputer) of | ||
halted -> | ||
Hull; | ||
_ -> | ||
[NewColour, Turn] = computer:get_outputs(NewComputer), | ||
NewHull = paint_panel(Hull, X, Y, NewColour), | ||
NewRobot = case Turn of | ||
0 -> #robot{x=X + YD, y=Y - XD, xd=YD, yd=-XD}; | ||
1 -> #robot{x=X - YD, y=Y + XD, xd=-YD, yd=XD} | ||
end, | ||
do_paint_hull(computer:clear_outputs(NewComputer), NewRobot, NewHull) | ||
end. |
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,92 @@ | ||
-module(day11_robot_part_2). | ||
|
||
-import(computer, [load_program/1, set_inputs/2, exec/1, get_outputs/1, clear_outputs/1, get_state/1]). | ||
-export([paint_hull/0]). | ||
|
||
|
||
-record(robot, { | ||
x, | ||
y, | ||
xd, | ||
yd | ||
}). | ||
|
||
|
||
paint_hull() -> | ||
{ok, Device} = file:open("../data/puzzle_input.csv", [read]), | ||
Computer = try computer:load_program(Device) | ||
after file:close(Device) | ||
end, | ||
Hull = do_paint_hull(Computer, #robot{x=0, y=0, xd=0, yd=-1}, | ||
paint_panel(#{}, 0, 0, 1)), | ||
print_hull_panel_pattern(Hull). | ||
|
||
|
||
get_panel_colour(Hull, X, Y) -> | ||
try maps:get({X, Y}, Hull) | ||
catch | ||
error:_ -> 0 | ||
end. | ||
|
||
|
||
paint_panel(Hull, X, Y, Colour) -> | ||
maps:put({X, Y}, Colour, Hull). | ||
|
||
|
||
do_paint_hull(Computer, #robot{x=X, y=Y, xd=XD, yd=YD}, Hull) -> | ||
Colour = get_panel_colour(Hull, X, Y), | ||
NewComputer = computer:exec(computer:set_inputs(Computer, [Colour])), | ||
case computer:get_state(NewComputer) of | ||
halted -> | ||
Hull; | ||
_ -> | ||
[NewColour, Turn] = computer:get_outputs(NewComputer), | ||
NewHull = paint_panel(Hull, X, Y, NewColour), | ||
NewRobot = case Turn of | ||
0 -> #robot{x=X + YD, y=Y - XD, xd=YD, yd=-XD}; | ||
1 -> #robot{x=X - YD, y=Y + XD, xd=-YD, yd=XD} | ||
end, | ||
do_paint_hull(computer:clear_outputs(NewComputer), NewRobot, NewHull) | ||
end. | ||
|
||
|
||
print_hull_panel_pattern(Hull) -> | ||
{_, _, MinY, _} = Extent = find_pattern_extent({0, 0, 0, 0}, maps:to_list(Hull)), | ||
print_next_hull_row(MinY, Extent, Hull). | ||
|
||
|
||
find_pattern_extent({MinX, MaxX, MinY, MaxY}, [{{X, Y}, _}|Rest]) -> | ||
find_pattern_extent({ | ||
if X < MinX -> X; true -> MinX end, | ||
if X > MaxX -> X; true -> MaxX end, | ||
if Y < MinY -> Y; true -> MinY end, | ||
if Y > MaxY -> Y; true -> MaxY end | ||
}, Rest); | ||
find_pattern_extent(Extent, []) -> | ||
Extent. | ||
|
||
|
||
print_next_hull_row(Y, {MinX, MaxX, _, MaxY} = Extent, Hull) -> | ||
print_hull_row(MinX, Y, MaxX, Hull), | ||
io:fwrite("~n"), | ||
if | ||
Y < MaxY -> | ||
print_next_hull_row(Y + 1, Extent, Hull); | ||
true -> | ||
{} | ||
end. | ||
|
||
|
||
print_hull_row(X, Y, MaxX, Hull) -> | ||
io:fwrite("~s", [ | ||
case get_panel_colour(Hull, X, Y) of | ||
0 -> " "; | ||
1 -> "XX" | ||
end | ||
]), | ||
if | ||
X < MaxX -> | ||
print_hull_row(X + 1, Y, MaxX, Hull); | ||
true -> | ||
{} | ||
end. |
Oops, something went wrong.