Commiting, things aren't quite right yet
This commit is contained in:
parent
88bea1705d
commit
529cd54788
BIN
day13/day13
Executable file
BIN
day13/day13
Executable file
Binary file not shown.
317
day13/main.go
Normal file
317
day13/main.go
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Puzzle 1 Input: 1364 31 39
|
||||||
|
// Puzzle 1 Test Input: 10 7 4
|
||||||
|
// Puzzle 2: 101 < x < 128 ?? 103
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) < 4 {
|
||||||
|
fmt.Println("Usage: day13 <seed> <dest-x> <dest-y>")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
seed := atoi(os.Args[1])
|
||||||
|
destX, destY := atoi(os.Args[2]), atoi(os.Args[3])
|
||||||
|
f := CreateFloor(1, 1, destX, destY, seed)
|
||||||
|
|
||||||
|
//f.Print()
|
||||||
|
//SolveMaze(f)
|
||||||
|
fmt.Println("WalkFloor(50):", f.player.WalkFloor(50))
|
||||||
|
f.Print()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SolveMaze finds a solution to the maze
|
||||||
|
func SolveMaze(f *Floor) {
|
||||||
|
for !f.player.FoundExit() {
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
ClearScreen()
|
||||||
|
f.player.MoveToExit()
|
||||||
|
f.Print()
|
||||||
|
}
|
||||||
|
fmt.Println("Found the exit in", f.player.NumSteps(), "steps")
|
||||||
|
}
|
||||||
|
|
||||||
|
type Coord struct {
|
||||||
|
x, y int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Coord) Is(x, y int) bool {
|
||||||
|
return c.x == x && c.y == y
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Coord) Equals(t *Coord) bool {
|
||||||
|
return c.x == t.x && c.y == t.y
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCoord(x, y int) *Coord {
|
||||||
|
return &Coord{x, y}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Player struct {
|
||||||
|
pos *Coord
|
||||||
|
currentFloor *Floor
|
||||||
|
visited []Coord
|
||||||
|
path Path
|
||||||
|
}
|
||||||
|
|
||||||
|
// WalkFloor determines how many places you can get to by taking
|
||||||
|
// <dist> steps
|
||||||
|
func (p *Player) WalkFloor(dist int) int {
|
||||||
|
if dist <= 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
fmt.Println("WalkFloor(", dist, ")")
|
||||||
|
var ret int
|
||||||
|
tryX, tryY := p.pos.x+1, p.pos.y
|
||||||
|
if !p.HasBeenAt(tryX, tryY) && !p.currentFloor.IsWall(tryX, tryY) {
|
||||||
|
ret++
|
||||||
|
p.WalkEast()
|
||||||
|
fmt.Println(" Walking East")
|
||||||
|
ret += p.WalkFloor(dist - 1)
|
||||||
|
p.WalkWest()
|
||||||
|
}
|
||||||
|
tryX, tryY = p.pos.x-1, p.pos.y
|
||||||
|
if !p.HasBeenAt(tryX, tryY) && !p.currentFloor.IsWall(tryX, tryY) {
|
||||||
|
ret++
|
||||||
|
p.WalkWest()
|
||||||
|
fmt.Println(" Walking West")
|
||||||
|
ret += p.WalkFloor(dist - 1)
|
||||||
|
p.WalkEast()
|
||||||
|
}
|
||||||
|
tryX, tryY = p.pos.x, p.pos.y+1
|
||||||
|
if !p.HasBeenAt(tryX, tryY) && !p.currentFloor.IsWall(tryX, tryY) {
|
||||||
|
ret++
|
||||||
|
p.WalkSouth()
|
||||||
|
fmt.Println(" Walking South")
|
||||||
|
ret += p.WalkFloor(dist - 1)
|
||||||
|
p.WalkNorth()
|
||||||
|
}
|
||||||
|
tryX, tryY = p.pos.x, p.pos.y-1
|
||||||
|
if !p.HasBeenAt(tryX, tryY) && !p.currentFloor.IsWall(tryX, tryY) {
|
||||||
|
ret++
|
||||||
|
p.WalkNorth()
|
||||||
|
fmt.Println(" Walking North")
|
||||||
|
ret += p.WalkFloor(dist - 1)
|
||||||
|
p.WalkSouth()
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Player) NumSteps() int {
|
||||||
|
return len(p.path.coords)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Player) MoveToExit() bool {
|
||||||
|
// First try to move closer to the goal
|
||||||
|
// Horizontally, then Vertically
|
||||||
|
if p.pos.x < p.currentFloor.end.x {
|
||||||
|
if !p.HasBeenAt(p.pos.x+1, p.pos.y) && p.WalkEast() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.pos.x > p.currentFloor.end.x {
|
||||||
|
if !p.HasBeenAt(p.pos.x-1, p.pos.y) && p.WalkWest() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.pos.y < p.currentFloor.end.y {
|
||||||
|
if !p.HasBeenAt(p.pos.x, p.pos.y+1) && p.WalkSouth() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.pos.y > p.currentFloor.end.y {
|
||||||
|
if !p.HasBeenAt(p.pos.x, p.pos.y-1) && p.WalkNorth() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Couldn't move towards it, can we move anywhere?
|
||||||
|
if !p.HasBeenAt(p.pos.x+1, p.pos.y) && p.WalkEast() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !p.HasBeenAt(p.pos.x-1, p.pos.y) && p.WalkWest() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !p.HasBeenAt(p.pos.x, p.pos.y+1) && p.WalkSouth() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !p.HasBeenAt(p.pos.x, p.pos.y-1) && p.WalkNorth() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Couldn't do any of those. Pop the path
|
||||||
|
if !p.Backtrack() {
|
||||||
|
// Couldn't backtrack! Game over man!
|
||||||
|
fmt.Println("Error! Couldn't find valid path!")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Player) Backtrack() bool {
|
||||||
|
if len(p.path.coords) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
p.path.Pop()
|
||||||
|
p.pos = &p.path.coords[len(p.path.coords)-1]
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Player) WalkEast() bool {
|
||||||
|
if !p.currentFloor.IsWall(p.pos.x+1, p.pos.y) {
|
||||||
|
p.pos.x++
|
||||||
|
p.path.Append(*p.pos)
|
||||||
|
p.visited = append(p.visited, *p.pos)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Player) WalkWest() bool {
|
||||||
|
if !p.currentFloor.IsWall(p.pos.x-1, p.pos.y) && p.pos.x > 0 {
|
||||||
|
p.pos.x--
|
||||||
|
p.path.Append(*p.pos)
|
||||||
|
p.visited = append(p.visited, *p.pos)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Player) WalkNorth() bool {
|
||||||
|
if !p.currentFloor.IsWall(p.pos.x, p.pos.y-1) && p.pos.y > 0 {
|
||||||
|
p.pos.y--
|
||||||
|
p.path.Append(*p.pos)
|
||||||
|
p.visited = append(p.visited, *p.pos)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Player) WalkSouth() bool {
|
||||||
|
if !p.currentFloor.IsWall(p.pos.x, p.pos.y+1) {
|
||||||
|
p.pos.y++
|
||||||
|
p.path.Append(*p.pos)
|
||||||
|
p.visited = append(p.visited, *p.pos)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Player) HasBeenAt(x, y int) bool {
|
||||||
|
for i := range p.visited {
|
||||||
|
if p.visited[i].Is(x, y) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Player) FoundExit() bool {
|
||||||
|
return p.pos.Equals(p.currentFloor.end)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Path struct {
|
||||||
|
coords []Coord
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Path) Append(c Coord) {
|
||||||
|
p.coords = append(p.coords, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Path) Pop() Coord {
|
||||||
|
var ret Coord
|
||||||
|
ret, p.coords = p.coords[len(p.coords)-1], p.coords[:len(p.coords)-1]
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Path) ContainsCoord(c *Coord) bool {
|
||||||
|
for i := range p.coords {
|
||||||
|
if p.coords[i].Equals(c) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type Floor struct {
|
||||||
|
player *Player
|
||||||
|
start *Coord
|
||||||
|
end *Coord
|
||||||
|
seed int
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateFloor(stX, stY, endX, endY, seed int) *Floor {
|
||||||
|
f := Floor{
|
||||||
|
start: NewCoord(stX, stY),
|
||||||
|
end: NewCoord(endX, endY),
|
||||||
|
seed: seed,
|
||||||
|
}
|
||||||
|
f.player = &Player{pos: f.start}
|
||||||
|
f.player.currentFloor = &f
|
||||||
|
return &f
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Floor) IsWall(x, y int) bool {
|
||||||
|
sum := (x*x + 3*x + 2*x*y + y + y*y + f.seed)
|
||||||
|
s := fmt.Sprintf("%b", sum)
|
||||||
|
if strings.Count(s, "1")%2 == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Floor) Print() {
|
||||||
|
wall := color.New(color.BgWhite)
|
||||||
|
space := color.New(color.FgWhite)
|
||||||
|
g := color.New(color.BgGreen).Add(color.FgBlack)
|
||||||
|
g.Add(color.Bold)
|
||||||
|
r := color.New(color.BgRed)
|
||||||
|
topY, topX := f.end.y+10, f.end.x+10
|
||||||
|
if f.player.pos.y > f.end.y {
|
||||||
|
topY = f.player.pos.y + 5
|
||||||
|
}
|
||||||
|
if f.player.pos.x > f.end.x {
|
||||||
|
topX = f.player.pos.x + 5
|
||||||
|
}
|
||||||
|
for y := 0; y < topY; y++ {
|
||||||
|
for x := 0; x < topX; x++ {
|
||||||
|
if f.player.pos.Is(x, y) {
|
||||||
|
g.Print("O")
|
||||||
|
} else if f.player.path.ContainsCoord(&Coord{x, y}) {
|
||||||
|
g.Print(".")
|
||||||
|
} else if f.player.HasBeenAt(x, y) {
|
||||||
|
r.Print(" ")
|
||||||
|
} else {
|
||||||
|
if f.end.Is(x, y) {
|
||||||
|
space.Print("X")
|
||||||
|
} else if f.IsWall(x, y) {
|
||||||
|
wall.Print(" ")
|
||||||
|
} else {
|
||||||
|
space.Print(".")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClearScreen() {
|
||||||
|
fmt.Print("\033[H\033[2J")
|
||||||
|
}
|
||||||
|
|
||||||
|
func atoi(i string) int {
|
||||||
|
var ret int
|
||||||
|
var err error
|
||||||
|
if ret, err = strconv.Atoi(i); err != nil {
|
||||||
|
log.Fatal("Invalid Atoi")
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user