Skip to content

Instantly share code, notes, and snippets.

@ap29600
Last active December 23, 2022 22:40
Show Gist options
  • Save ap29600/f476231507734d2434f22debe7af2584 to your computer and use it in GitHub Desktop.
Save ap29600/f476231507734d2434f22debe7af2584 to your computer and use it in GitHub Desktop.
Advent of Code day 23 in Odin
package main
import "core:os"
import "core:strings"
import "core:fmt"
import "core:slice"
import "core:strconv"
import "core:time"
State :: enum u8 {
From_Up = 0,
From_Down = 1,
From_Left = 2,
From_Right = 3,
Free = 4,
Occupied = 6,
Moving = 7,
}
step :: proc (buffer: []State, stride: int, round: int) -> (any_moved: bool) {
buffer := buffer
n8 := [?]int{-stride-1,-stride,-stride+1, -1, 1, stride-1, stride, stride+1}
n4 := [4]int{-stride, stride, -1, 1}
b := [4][3]int{{0, 1, 2}, {5, 6, 7}, {0, 3, 5}, {2, 4, 7}}
for s, i in &buffer {
if s != .Occupied {continue}
around := [8]bool{}
any := false
for k in 0 ..< 8 {
around[k] = u8(buffer[i+n8[k]]) >= u8(State.Occupied)
any |= around[k]
}
if !any {continue}
dirs: for k in 0 ..< 4 {
k := (k + round)%4
for off in b[k] {
if around[off] { continue dirs }
}
if buffer[i+n4[k]] == .Free {
buffer[i+n4[k]] = State(k~0x1) // opposite direction to k
s = .Moving
} else {
prov := u8(buffer[i+n4[k]])
buffer[i+n4[k]+n4[prov]] = .Occupied // amend a previous move
}
break
}
}
for s, i in &buffer {
if u8(s) <= u8(State.From_Right) && buffer[i+n4[u8(s)]] == .Moving {
any_moved = true
s = .Occupied
}
}
for s in &buffer {
if s != .Occupied {
s = .Free
}
}
return
}
display :: proc (buffer: []State, stride: int) {
d := slice.mapper(
buffer,
proc(s:State)->u8{
switch s {
case .Occupied: return '#'
case .Free: return '.'
case .From_Right: return '<'
case .From_Left: return '>'
case .From_Up: return 'v'
case .From_Down: return '^'
case .Moving: return 'o'
case: os.exit(1)
}
},
context.temp_allocator,
)
for i in 1 ..= len(d)/stride {
d[i*stride-1] = '\n'
}
fmt.println(string(d))
}
covered_ground :: proc (buffer: []State, stride: int) -> int {
mini, minj, maxi, maxj := max(int), max(int), min(int), min(int)
count := 0
for s, i in buffer {
if s == .Occupied {
count += 1
mini = min(mini, i/stride)
maxi = max(maxi, i/stride)
minj = min(minj, i%stride)
maxj = max(maxj, i%stride)
}
}
return (maxi-mini+1)*(maxj-minj+1)-count
}
main :: proc () {
input := os.read_entire_file("input.txt") or_else os.exit(1)
lines := strings.split_lines(cast(string)input, context.temp_allocator)
w, h := len(lines) * 3, len(lines[0]) * 3
buffer := make([]State, w*h)
slice.fill(buffer, State.Free)
for line, i in lines {
for c, j in line {
if c == '#' {
buffer[(i+h/3)*w+j+w/3] = .Occupied
}
}
}
for i in 0 ..< max(int) {
fmt.print("\033[2K\r", i)
if i == 10 { fmt.println("\033[2K\r",covered_ground(buffer, w)) }
if !step(buffer, w, i) {
fmt.println("\033[2K\r",i+1)
break
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment