package main import "core:bytes" import "core:fmt" import "core:io" import "core:os" import "core:strconv" import "core:strings" Instruction :: struct { Op: OpCode, X: int, } OpCode :: enum { Noop, AddX, } OpCycles := []int { OpCode.Noop = 1, OpCode.AddX = 2, } // NOTE: Have to free result. parse_input_file :: proc(filepath: string) -> [dynamic]Instruction { data, ok := os.read_entire_file_from_filename(filepath) if !ok { panic("oh no, could not read file") } buf: bytes.Buffer bytes.buffer_init(&buf, data) defer bytes.buffer_destroy(&buf) instructions := make([dynamic]Instruction, 0, 10) line: string err: io.Error for ; err != .EOF; line, err = bytes.buffer_read_string(&buf, '\n') { if line == "" || line == "\n" { continue } line = line[:len(line) - 1] instr := strings.split(line, " ") defer delete(instr) switch instr[0] { case "noop": append(&instructions, Instruction{Op = .Noop}) case "addx": append(&instructions, Instruction{Op = .AddX, X = strconv.atoi(instr[1])}) case: panic("unknown op") } } return instructions } task1 :: proc(instructions: []Instruction, debug := false) -> int { result := 0 x := 1 cycle: int for instruction in instructions { for i in 0 ..< OpCycles[instruction.Op] { cycle += 1 if cycle >= 20 && (cycle - 20) % 40 == 0 { result += (cycle * x) } } switch instruction.Op { case .Noop: case .AddX: x += instruction.X } if debug { fmt.printf("[%d/%d] -> %v\n", cycle, x, instruction) } } return result } task2 :: proc(instructions: []Instruction, debug := false) { x := 1 hscan := 0 for instruction in instructions { for i in 0 ..< OpCycles[instruction.Op] { if x >= hscan - 1 && x <= hscan + 1 { fmt.printf("#") } else { fmt.printf(".") } hscan = (hscan + 1) % 40 if hscan == 0 { fmt.printf("\n") } } switch instruction.Op { case .Noop: case .AddX: x += instruction.X } } } main :: proc() { instructions := parse_input_file("input.txt") defer delete(instructions) result1 := task1(instructions[:]) fmt.printf("Task 1 result: %d\n", result1) task2(instructions[:]) }