You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
126 lines
2.6 KiB
126 lines
2.6 KiB
package main |
|
|
|
import ( |
|
"bufio" |
|
"fmt" |
|
"os" |
|
"reflect" |
|
"strings" |
|
) |
|
|
|
func main() { |
|
var scannedSeats, currentSeats [][]rune |
|
|
|
file, _ := os.Open("input.txt") |
|
defer file.Close() |
|
for scanner := bufio.NewScanner(file); scanner.Scan(); { |
|
row := []rune{} |
|
for _, r := range scanner.Text() { |
|
row = append(row, r) |
|
} |
|
scannedSeats = append(scannedSeats, row) |
|
} |
|
|
|
// Part 1 |
|
|
|
currentSeats = scannedSeats |
|
rounds: |
|
for { |
|
newSeats := [][]rune{} |
|
for i := range currentSeats { |
|
row := []rune{} |
|
for j, r := range currentSeats[i] { |
|
newRune := r |
|
if os := occupiedAdjacent(currentSeats, position{i, j}); r == 'L' && os == 0 { |
|
newRune = '#' |
|
} else if r == '#' && os >= 4 { |
|
newRune = 'L' |
|
} |
|
row = append(row, newRune) |
|
} |
|
newSeats = append(newSeats, row) |
|
} |
|
if reflect.DeepEqual(currentSeats, newSeats) { |
|
break rounds |
|
} |
|
currentSeats = newSeats |
|
} |
|
|
|
fmt.Println("Part 1:", countOccupied(currentSeats)) |
|
|
|
// Part 2 |
|
|
|
currentSeats = scannedSeats |
|
rounds2: |
|
for { |
|
newSeats := [][]rune{} |
|
for i := range currentSeats { |
|
row := []rune{} |
|
for j, r := range currentSeats[i] { |
|
newRune := r |
|
if cs := canSeeAdjacent(currentSeats, position{i, j}); r == 'L' && cs == 0 { |
|
newRune = '#' |
|
} else if r == '#' && cs >= 5 { |
|
newRune = 'L' |
|
} |
|
row = append(row, newRune) |
|
} |
|
newSeats = append(newSeats, row) |
|
} |
|
if reflect.DeepEqual(currentSeats, newSeats) { |
|
break rounds2 |
|
} |
|
currentSeats = newSeats |
|
} |
|
|
|
fmt.Println("Part 2:", countOccupied(currentSeats)) |
|
} |
|
|
|
type position struct { |
|
row, pos int |
|
} |
|
|
|
var dirs = []position{ |
|
{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}, |
|
} |
|
|
|
func direction(pos, dir position) position { |
|
return position{pos.row + dir.row, pos.pos + dir.pos} |
|
} |
|
|
|
func isSafe(seats [][]rune, p position) bool { |
|
return !(p.row < 0 || p.row >= len(seats) || p.pos < 0 || p.pos >= len(seats[p.row])) |
|
} |
|
|
|
func occupied(seats [][]rune, p position) bool { |
|
return isSafe(seats, p) && seats[p.row][p.pos] == '#' |
|
} |
|
|
|
func occupiedAdjacent(seats [][]rune, pos position) (o int) { |
|
for _, dir := range dirs { |
|
if occupied(seats, direction(pos, dir)) { |
|
o++ |
|
} |
|
} |
|
return |
|
} |
|
|
|
func canSee(seats [][]rune, p, dir position) bool { |
|
return isSafe(seats, p) && seats[p.row][p.pos] != 'L' && (seats[p.row][p.pos] == '#' || canSee(seats, direction(p, dir), dir)) |
|
} |
|
|
|
func canSeeAdjacent(seats [][]rune, pos position) (o int) { |
|
for _, dir := range dirs { |
|
if canSee(seats, direction(pos, dir), dir) { |
|
o++ |
|
} |
|
} |
|
return |
|
} |
|
|
|
func countOccupied(seats [][]rune) (o int) { |
|
for _, ro := range seats { |
|
o += strings.Count(string(ro), "#") |
|
} |
|
return |
|
}
|
|
|