day10, All Is Broken

This commit is contained in:
efim 2023-12-10 14:47:40 +00:00
parent 0b6c521b5b
commit e4afe55a1f
3 changed files with 207 additions and 37 deletions

View File

@ -12,7 +12,7 @@ import (
func Run() int { func Run() int {
fmt.Println("hello day 10") fmt.Println("hello day 10")
// filename := "day10/example2noisy" // filename := "day10/example2noisy"
filename := "day10/input" filename := "day10/example5"
fieldMap := Read(filename) fieldMap := Read(filename)
fmt.Println(fieldMap.BeastCoord) fmt.Println(fieldMap.BeastCoord)
// fmt.Println(fieldMap.String()) // fmt.Println(fieldMap.String())
@ -35,12 +35,15 @@ func Run() int {
} }
} }
fmt.Println("beore marking:") // fmt.Println("beore marking:")
fieldMap.markMainLoop() fieldMap.markMainLoop()
fmt.Println("after marking:") // fmt.Println("after marking loop:")
fmt.Println(fieldMap.String()) // fmt.Println(fieldMap.String())
fmt.Println("beore marking closest Outer:")
// now main loop is closed with regards to 'S' neighbors // now main loop is closed with regards to 'S' neighbors
fieldMap.initialMarkOuter()
fmt.Println("after marking closest Outer:")
fmt.Println(fieldMap.String())
return (len / 2) + (len % 2) return (len / 2) + (len % 2)
} }
@ -58,52 +61,72 @@ func Run() int {
// cell would map 'from' to 'to' // cell would map 'from' to 'to'
type Cell struct { type Cell struct {
Coord Coord Coord Coord
Tile rune Tile rune
Neighbords []Coord Neighbords []Coord
IsOnMainPath bool IsOnMainPath bool
IsOuter bool
} }
func (c *Cell)String() string {
func (c *Cell) String() string {
if c.Tile == 'S' { if c.Tile == 'S' {
return "S" return "S"
} }
if c.IsOuter {
return "O"
}
if !c.IsOnMainPath { if !c.IsOnMainPath {
return " " return " "
} }
switch c.Tile { switch c.Tile {
case '7': return "⌝" case '7':
case 'J': return "⌟" return "⌝"
case 'F': return "⌜" case 'J':
case 'L': return "⌞" return "⌟"
case '.': return " " case 'F':
default: return string(c.Tile) return "⌜"
case 'L':
return "⌞"
case '.':
return " "
default:
return string(c.Tile)
} }
} }
type Coord struct { type Coord struct {
X, Y int X, Y int
} }
func (c Coord)Equal(other Coord) bool {
func (c Coord) Equal(other Coord) bool {
return c.X == other.X && c.Y == other.Y return c.X == other.X && c.Y == other.Y
} }
type Direction int type Direction int
const (UP Direction = iota
const (
UP Direction = iota
DOWN DOWN
LEFT LEFT
RIGHT) RIGHT
)
func (d Direction)String() string {
names := []string{"UP", "DOWN", "LEFT", "RIGHT"}
return names[d]
}
func (c Coord)Shift(d Direction) Coord { func (c Coord) Shift(d Direction) Coord {
x, y := c.X, c.Y x, y := c.X, c.Y
result := Coord{} result := Coord{}
switch d { switch d {
case UP: case UP:
result = Coord{x, y-1} result = Coord{x, y - 1}
case DOWN: case DOWN:
result = Coord{x, y+1} result = Coord{x, y + 1}
case LEFT: case LEFT:
result = Coord{x-1, y} result = Coord{x - 1, y}
case RIGHT: case RIGHT:
result = Coord{x+1, y} result = Coord{x + 1, y}
} }
return result return result
} }
@ -113,7 +136,8 @@ type Map struct {
Height, Width int Height, Width int
BeastCoord Coord BeastCoord Coord
} }
func (m *Map)String() string {
func (m *Map) String() string {
result := "" result := ""
for y := 0; y < m.Height; y++ { for y := 0; y < m.Height; y++ {
for x := 0; x < m.Width; x++ { for x := 0; x < m.Width; x++ {
@ -125,7 +149,7 @@ func (m *Map)String() string {
return result return result
} }
func (m *Map)markMainLoop() { func (m *Map) markMainLoop() {
start := m.Cells[m.BeastCoord] start := m.Cells[m.BeastCoord]
start.IsOnMainPath = true start.IsOnMainPath = true
m.Cells[m.BeastCoord] = start m.Cells[m.BeastCoord] = start
@ -136,7 +160,7 @@ func (m *Map)markMainLoop() {
currentCell.IsOnMainPath = true currentCell.IsOnMainPath = true
m.Cells[currentCell.Coord] = currentCell m.Cells[currentCell.Coord] = currentCell
// log.Printf("marking loop on %+v (%s)\n", currentCell, currentCell.String()) // log.Printf("marking loop on %+v (%s)\n", currentCell, currentCell.String())
nextCoord, err := currentCell.Next(previous.Coord) nextCoord, _, err := currentCell.Next(previous.Coord)
// log.Printf("next coord will be %v %s\n", nextCoord, err) // log.Printf("next coord will be %v %s\n", nextCoord, err)
if err != nil { if err != nil {
return return
@ -146,9 +170,114 @@ func (m *Map)markMainLoop() {
} }
} }
func (m *Map) initialMarkOuter() {
// for start point let's take my highest on main path and one above
// and will have a runner pointer to the cell on the outside
var outerRunner Cell
var pathCunner Cell
outer:
for y := 0; y < m.Height; y++ {
for x := 0; x < m.Width; x++ {
if cell := m.Cells[Coord{x, y}]; cell.IsOnMainPath {
pathCunner = cell
outerRunner = m.Cells[Coord{x, y - 1}]
break outer
}
}
}
startPoint := pathCunner
previous := startPoint
firstDirection := startPoint.OutDirections()[0]
nextCoord := previous.Coord.Shift(firstDirection)
currentCell := m.Cells[nextCoord]
var exitingPreviousBy Direction = firstDirection
stepsToDo := 1
for currentCell.Coord != startPoint.Coord {
// looping once. and need to operae on the outer runner
// and i don't have the direction? well, i guess i could use direction
outerRunner = m.markOuterAndMove(previous, outerRunner, exitingPreviousBy)
var err error
nextCoord, exitingPreviousBy, err = currentCell.Next(previous.Coord)
if err != nil {
panic("initial mark cycle can't get next")
}
previous = currentCell
currentCell = m.Cells[nextCoord]
stepsToDo -= 1
if stepsToDo == 0 {
break
}
}
}
func (m *Map) markOuter(outerPointerCoord Coord) {
if !m.isValidCoord(outerPointerCoord) {
return
}
outerPointer := m.Cells[outerPointerCoord]
if outerPointer.IsOnMainPath {
return
}
outerPointer.IsOuter = true
m.Cells[outerPointer.Coord] = outerPointer
}
// move both inner path Cell and OuterCell through direction from inner path cell
// and i need to know direction from which we came into 'pathPointer'
func (m *Map) markOuterAndMove(pathPointer Cell, outerPointer Cell, exitingCurrentBy Direction) Cell {
// mark &save outer, get moves from pathPointer & direct
// do 1 or 2 moves and on each mark & save
m.markOuter(outerPointer.Coord)
outerPointerMovements := outerPointerMovements[pathPointer.Tile][exitingCurrentBy]
log.Printf("moving outer from %s exited via %s with moves %+v\n", pathPointer.String(), exitingCurrentBy.String(), outerPointerMovements)
coord := outerPointer.Coord
for _, movement := range outerPointerMovements {
coord = coord.Shift(movement)
m.markOuter(coord)
}
newPointer := m.Cells[coord]
return newPointer
}
// yeah, this is not enough. if we move down from | we could be directly up to -
// so we need TurnLeft & TurnRight things
var outerPointerMovements map[rune]map[Direction][]Direction = map[rune]map[Direction][]Direction{
'|': {
UP: {UP},
DOWN: {DOWN},
},
'-': {
LEFT: {LEFT},
RIGHT: {RIGHT},
},
'L': {
DOWN: {DOWN, RIGHT},
LEFT: {RIGHT, UP},
},
'J': {
DOWN: {DOWN, LEFT},
RIGHT: {RIGHT, UP},
},
'F': {
DOWN: {LEFT, DOWN},
RIGHT: {UP, RIGHT},
},
'7': {
RIGHT: {RIGHT, DOWN},
UP: {UP, LEFT},
},
}
// call for each direction from beast. // call for each direction from beast.
// will run the path until it loops back at best, or terminates // will run the path until it loops back at best, or terminates
func (m *Map)checkDirectionFromBeast(through Coord) (isCycle bool, len int) { func (m *Map) checkDirectionFromBeast(through Coord) (isCycle bool, len int) {
// defer log.Printf("about to return check from beast %v, isCycle : %t. len is %d", through, isCycle, len) // defer log.Printf("about to return check from beast %v, isCycle : %t. len is %d", through, isCycle, len)
len = 1 len = 1
previous := m.Cells[m.BeastCoord] previous := m.Cells[m.BeastCoord]
@ -157,7 +286,7 @@ func (m *Map)checkDirectionFromBeast(through Coord) (isCycle bool, len int) {
for found && currentCell.Tile != 'S' { for found && currentCell.Tile != 'S' {
// log.Printf("check direction loop for %+v (%s)\n", currentCell, currentCell.String()) // log.Printf("check direction loop for %+v (%s)\n", currentCell, currentCell.String())
len += 1 len += 1
nextCoord, err := currentCell.Next(previous.Coord) nextCoord, _, err := currentCell.Next(previous.Coord)
// log.Printf("next coord will be %v %s\n", nextCoord, err) // log.Printf("next coord will be %v %s\n", nextCoord, err)
if err != nil { if err != nil {
return return
@ -178,7 +307,7 @@ func (m *Map)checkDirectionFromBeast(through Coord) (isCycle bool, len int) {
return return
} }
func (m *Map)isValidCoord(c Coord) bool { func (m *Map) isValidCoord(c Coord) bool {
if c.X < 0 || c.Y < 0 || c.X >= m.Height || c.Y >= m.Width { if c.X < 0 || c.Y < 0 || c.X >= m.Height || c.Y >= m.Width {
return false return false
} }
@ -228,18 +357,25 @@ func (c *Cell) GetNeighbors() []Coord {
// - check if 'from' is in neighbors // - check if 'from' is in neighbors
// if it is - then take another neighbor // if it is - then take another neighbor
// wouldn't work for 'S' but we don't need it to // wouldn't work for 'S' but we don't need it to
func (c *Cell) Next(from Coord) (to Coord, err error) { func (c *Cell) Next(from Coord) (to Coord, cameFrom Direction, err error) {
if len(c.Neighbords) != 2 { if len(c.Neighbords) != 2 {
return Coord{}, errors.New(fmt.Sprintf("not 2 neighbors: cannot get next from %v through %c", from, c)) return Coord{}, 0, errors.New(fmt.Sprintf("not 2 neighbors: cannot get next from %v through %c", from, c))
} }
i := slices.Index(c.Neighbords, from) i := slices.Index(c.Neighbords, from)
if i == -1 { if i == -1 {
return Coord{}, errors.New(fmt.Sprintf("cannot find next from %v through %+v", from, c)) return Coord{}, 0, errors.New(fmt.Sprintf("cannot find next from %v through %+v", from, c))
}
var nextDirection Direction
for _, direction := range c.OutDirections() {
if c.Coord.Shift(direction) != from {
nextDirection = direction
}
} }
otherIndex := 1 - i otherIndex := 1 - i
return c.Neighbords[otherIndex], nil return c.Neighbords[otherIndex], nextDirection, nil
} }
// x from left to right; y from top to bottom // x from left to right; y from top to bottom

7
day10/example5 Normal file
View File

@ -0,0 +1,7 @@
.......
...F7..
..FJ|..
.SJ.L7.
.|F--J.
.LJ....
.......

View File

@ -18,3 +18,30 @@ but yeah, if i make initial filling in of the I, then i could just fill in all .
and count I and count I
sounds like a plan sounds like a plan
** allright, i found main path, display all not on main path as ' '
and the thing is a mess
i don't know how to select a point to mark as 'I'
but! if i select a point to mark as 'O'
and then go around the main path, marking things on the side as 'O'
then i would be able to fill in all which are neighbors of 'O' as 'O'
and that would leave only 'I' to be counted
so.
how would i monitor consistent 'side' of the pipe during the walkhrough?
if we go down - we color as 'O' one down.
if we go angle - color two - one down and one to the right.
and only color if it's not already on main path.
i suppose so
** so a new method for initial pass of 'O'
well, i'll need access to the direction, in which the neighbor is taken?
nooo. not direction, but the symbol. ok, this is easier
but i'll need to mutate the field
no, i do need direction.
ok, let's go lunch maybe, and maybe it will be a place with a power outlet as well