package main import "core:bytes" import "core:fmt" import "core:io" import "core:os" import "core:slice" import "core:strconv" State :: struct { columns: [dynamic][dynamic]u8, } Instruction :: struct { count: int, from: int, to: int, } parse_input_file :: proc(filepath: string) -> (State, [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) state := State { columns = make([dynamic][dynamic]u8, 0, 100), } instructions := make([dynamic]Instruction, 0, 100) line: []u8 err: io.Error for ; err != .EOF; line, err = bytes.buffer_read_bytes(&buf, '\n') { if len(line) == 0 { continue } if line[0] == '\n' { break } if bytes.index_byte(line, '[') == -1 { continue } line = line[:len(line) - 1] for i := 0; i < len(line); i += 4 { position := i / 4 if len(state.columns) < position + 1 { append(&state.columns, make([dynamic]u8, 0, 10)) } if line[i + 1] == ' ' { continue } append(&state.columns[position], line[i + 1]) } } for column in state.columns { for i := 0; i < len(column) / 2; i += 1 { column[i], column[len(column) - i - 1] = column[len(column) - i - 1], column[i] } } for ; err != .EOF; line, err = bytes.buffer_read_bytes(&buf, '\n') { if len(line) == 0 || line[0] == '\n' { continue } numbers: [3]int num_read: int line = line[:len(line) - 1] i: int for { start := bytes.index_byte(line[i:], ' ') + i end := bytes.index_byte(line[start + 1:], ' ') + start + 1 if start < 0 || end < 0 { break } if start == end { end = len(line) } numbers[num_read] = strconv.atoi(string(line[start + 1:end])) num_read += 1 i = end + 1 if i >= len(line) { break } } append(&instructions, Instruction{count = numbers[0], from = numbers[1], to = numbers[2]}) } return state, instructions } free_input_data :: proc(state: State, instructions: [dynamic]Instruction) { free_state(state) delete(instructions) } clone_state :: proc(state: State) -> State { state_clone := State { columns = make([dynamic][dynamic]u8, 0, 100), } for column in state.columns { append(&state_clone.columns, slice.clone_to_dynamic(column[:])) } return state_clone } free_state :: proc(state: State) { for column in state.columns { delete(column) } delete(state.columns) } task1 :: proc(state: State, instructions: []Instruction) -> [dynamic]u8 { state_clone := clone_state(state) defer free_state(state_clone) for instruction in instructions { for _ in 0 ..< instruction.count { from_column := state_clone.columns[instruction.from - 1] moved_char := from_column[len(from_column) - 1] state_clone.columns[instruction.from - 1] = slice.clone_to_dynamic( from_column[:len(from_column) - 1], ) delete(from_column) append(&state_clone.columns[instruction.to - 1], moved_char) } } result := make([dynamic]u8, 0, 10) for column in state_clone.columns { append(&result, column[len(column) - 1]) } return result } task2 :: proc(state: State, instructions: []Instruction) -> [dynamic]u8 { state_clone := clone_state(state) defer free_state(state_clone) for instruction in instructions { from_column := state_clone.columns[instruction.from - 1] for i in 0 ..< instruction.count { ri := instruction.count - 1 - i moved_char := from_column[len(from_column) - 1 - ri] append(&state_clone.columns[instruction.to - 1], moved_char) } state_clone.columns[instruction.from - 1] = slice.clone_to_dynamic( from_column[:len(from_column) - instruction.count], ) delete(from_column) } result := make([dynamic]u8, 0, 10) for column in state_clone.columns { append(&result, column[len(column) - 1]) } return result } main :: proc() { state, instructions := parse_input_file("input.txt") defer free_input_data(state, instructions) result1 := task1(state, instructions[:]) fmt.printf("Task 1 result: %s\n", result1) result2 := task2(state, instructions[:]) fmt.printf("Task 2 result: %s\n", result2) }