advent-of-code

Perserverance, or the lack thereof

git clone git://git.shimmy1996.com/advent-of-code.git
commit 2c5197e02c9b7431c42a39368b0d5fc7822ec901
parent a02ab51af0f32d7be541fdc4e0cac36f24b1637b
Author: Shimmy Xu <shimmy.xu@shimmy1996.com>
Date:   Fri, 13 Dec 2019 11:28:58 -0500

Add Julia solution for day 13

Diffstat:
Aday-13/day-13.jl | 206+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 206 insertions(+), 0 deletions(-)
diff --git a/day-13/day-13.jl b/day-13/day-13.jl
@@ -0,0 +1,206 @@
+function computer_step!(program, pc, relative_base, input)
+    # Runs from given pc until completion or next request for input.
+    # Modifies program and pc.
+    # Returns if the program has terminated and the output.
+    output = []
+    function get_param(loc, mode)
+        # Loc is gauranteed to exist.
+        if mode == 0
+            # Position mode.
+            get(program, program[loc] + 1, 0)
+        elseif mode == 1
+            # Immediate mode.
+            program[loc]
+        else
+            # Relative mode.
+            get(program, relative_base + program[loc] + 1, 0)
+        end
+    end
+    function get_res_loc(loc, mode)
+        # Loc is gauranteed to exist.
+        if mode == 0
+            # Position mode.
+            program[loc] + 1
+        else
+            # Relative mode.
+            relative_base + program[loc] + 1
+        end
+    end
+    while true
+        op_code = program[pc] % 100
+        mode_1 = (program[pc] % 1000) ÷ 100
+        mode_2 = (program[pc] % 10000) ÷ 1000
+        mode_3 = (program[pc] % 100000) ÷ 10000
+        if op_code == 1
+            program[get_res_loc(pc + 3, mode_3)] = (
+                get_param(pc + 1, mode_1)
+                + get_param(pc + 2, mode_2)
+            )
+            pc += 4
+        elseif op_code == 2
+            program[get_res_loc(pc + 3, mode_3)] = (
+                get_param(pc + 1, mode_1)
+                * get_param(pc + 2, mode_2)
+            )
+            pc += 4
+        elseif op_code == 3
+            if !isnothing(input)
+                program[get_res_loc(pc + 1, mode_1)] = input
+                input = nothing
+            else
+                return (pc, relative_base, false, output)
+            end
+            pc += 2
+        elseif op_code == 4
+            push!(output, get_param(pc + 1, mode_1))
+            pc += 2
+        elseif op_code == 5
+            if get_param(pc + 1, mode_1) != 0
+                pc = get_param(pc + 2, mode_2) + 1
+            else
+                pc += 3
+            end
+        elseif op_code == 6
+            if get_param(pc + 1, mode_1) == 0
+                pc = get_param(pc + 2, mode_2) + 1
+            else
+                pc += 3
+            end
+        elseif op_code == 7
+            program[get_res_loc(pc + 3, mode_3)] = (
+                get_param(pc + 1, mode_1)
+                < get_param(pc + 2, mode_2)
+            ) ? 1 : 0
+            pc += 4
+        elseif op_code == 8
+            program[get_res_loc(pc + 3, mode_3)] = (
+                get_param(pc + 1, mode_1)
+                == get_param(pc + 2, mode_2)
+            ) ? 1 : 0
+            pc += 4
+        elseif op_code == 9
+            relative_base += get_param(pc + 1, mode_1)
+            pc += 2
+        elseif op_code == 99
+            break
+        else
+            println("Unknown op code: ", op_code)
+            break
+        end
+    end
+    (pc, relative_base, true, output)
+end
+
+function arcade(program, demo, cheat)
+    program = Dict(enumerate(copy(program)))
+    if !demo
+        program[1] = 2
+        if cheat
+            # Replace bottom opening with walls.
+            for i in 1584:1622
+                program[i] = 1
+            end
+        end
+    end
+    # Set program state.
+    pc = 1
+    relative_base = 0
+    screen = Dict()
+    command = nothing
+    # Prepare for user input.
+    while true
+        pc, relative_base, finished, step_output = computer_step!(
+            program, pc, relative_base, command
+        )
+        command = nothing
+        # Parse step_output.
+        for i in 1:3:length(step_output)
+            screen[(step_output[i], step_output[i + 1])] = step_output[i + 2]
+        end
+        if !demo
+            if cheat
+                command = -1
+                # Break when there's no block left.
+                if count_blocks(screen) == 0
+                    break
+                end
+            else
+                draw(screen)
+                # Read next input.
+                println("Move left with <h>, and move right with <l>:");
+                user_input = read(stdin, Char)
+                if user_input == 'h'
+                    command = -1
+                elseif user_input == 'l'
+                    command = 1
+                else
+                    command = 0
+                end
+            end
+        end
+        if finished
+            break
+        end
+    end
+    screen
+end
+
+function count_blocks(screen)
+    count(x -> x == 2, values(screen))
+end
+
+function draw(screen)
+    # Check max/min coordinates.
+    max_x = -Inf
+    max_y = -Inf
+    score = 0
+    for panel in keys(screen)
+        max_x = max(max_x, panel[1])
+        max_y = max(max_y, panel[2])
+        if panel == (-1, 0)
+            score = screen[panel]
+        end
+    end
+    for y in 0:max_y
+        for x in 0:max_x
+            tile = get(screen, (x, y), 0)
+            if tile == 1
+                # Wall
+                print("||")
+            elseif tile == 2
+                # Block
+                print("##")
+            elseif tile == 3
+                # Paddle
+                print("--")
+            elseif tile == 4
+                # Ball
+                print("[]")
+            else
+                # Empty
+                print("  ")
+            end
+        end
+        println()
+    end
+    # Print score.
+    println("Score: ", score)
+end
+
+function part_1(input)
+    screen = arcade(input, true, false)
+    count_blocks(screen)
+end
+
+function part_2(input)
+    # Enable cheat and draw last screen for scores.
+    screen = arcade(input, false, true)
+    draw(screen)
+end
+
+input = map(x -> parse(Int128, x), split(readlines(open("input.txt"))[1], ','))
+
+println("Julia:")
+println("Part 1: ", part_1(input))
+println("Part 2: ")
+part_2(input)