Files

163 lines
3.6 KiB
Go
Raw Permalink Normal View History

2024-12-06 23:08:31 +01:00
package main
import (
"os"
"fmt"
"strings"
)
2024-12-06 23:08:31 +01:00
// type definitions
2024-12-06 23:08:31 +01:00
type Direction int
const (
Up Direction = iota + 1
Down
Left
Right
)
type state struct {
field *[][]rune
guard_x int
guard_y int
direction Direction
}
func new_state(text string) *state {
lines := strings.Split(text, "\n")
field := make([][]rune, len(lines))
guard := [2]int{-1,-1}
for y, line := range lines {
field[y] = []rune(line)
2024-12-06 23:08:31 +01:00
for x, r := range field[y] {
if r == '^' {
guard = [2]int{x, y}
field[y][x] = '.'
}
}
}
s := state{field: &field, guard_x: guard[0], guard_y: guard[1], direction: Up}
return &s
}
// general util
2024-12-06 23:08:31 +01:00
func check(e error) {
if e != nil { panic(e) }
}
// simulation functions
2024-12-06 23:08:31 +01:00
func iter(s *state) *state {
new_guard_x := s.guard_x
new_guard_y := s.guard_y
// try to move
switch {
case s.direction == Up:
new_guard_y--
case s.direction == Down:
new_guard_y++
case s.direction == Left:
new_guard_x--
case s.direction == Right:
new_guard_x++
}
// if guard is outside of the field
if new_guard_x < 0 || new_guard_y < 0 || new_guard_x >= len((*s.field)[0]) || new_guard_y >= len(*s.field) {
new_guard_x = -1
new_guard_y = -1
} else if (*s.field)[new_guard_y][new_guard_x] == '#' {
// correct if path is blocked
switch {
case s.direction == Up:
new_guard_y++
new_guard_x++
s.direction = Right
case s.direction == Down:
new_guard_y--
new_guard_x--
s.direction = Left
case s.direction == Left:
new_guard_x++
new_guard_y--
s.direction = Up
case s.direction == Right:
new_guard_x--
new_guard_y++
s.direction = Down
}
}
// set new guard coordinates
s.guard_x = new_guard_x
s.guard_y = new_guard_y
return s
}
func will_loop(s *state) bool {
counter := 0
2024-12-06 23:08:31 +01:00
// while guard is within the field
for s.guard_x >= 0 && counter < 10000 {
2024-12-06 23:08:31 +01:00
// iterate
s = iter(s)
counter++
}
if s.guard_x < 0 {
// the guard is no longer in the field, not a loop
return false
} else {
return true
2024-12-06 23:08:31 +01:00
}
}
func print(s *state) {
out := make([]string, 0, len(*s.field))
for line := range *s.field {
2024-12-06 23:08:31 +01:00
out = append(out, string(line))
}
fmt.Println(strings.Join(out, "\n"))
fmt.Println("guard", s.guard_x, s.guard_y)
}
// main loop
func main() {
// read in file
dat, err := os.ReadFile("data.txt")
check(err)
dat_str := strings.TrimSpace(string(dat))
stateobj := new_state(dat_str)
start_of_guard := [2]int{stateobj.guard_x, stateobj.guard_y}
// check loops
counter := 0
for y := range *stateobj.field {
for x, elem := range (*stateobj.field)[y] {
// skip already existing borders
if elem == '#' { continue }
// because the placement of the start position of the guard is not allowed
if x == start_of_guard[0] && y == start_of_guard[1] { continue }
// set border
(*stateobj.field)[y][x] = '#'
// check for loop
if will_loop(stateobj) { counter++ }
// restore state
stateobj = new_state(dat_str)
}
}
fmt.Println(counter)
}