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 {
fmt.Println("hello day 10")
// filename := "day10/example2noisy"
filename := "day10/input"
filename := "day10/example5"
fieldMap := Read(filename)
fmt.Println(fieldMap.BeastCoord)
// fmt.Println(fieldMap.String())
@ -35,12 +35,15 @@ func Run() int {
}
}
fmt.Println("beore marking:")
// fmt.Println("beore marking:")
fieldMap.markMainLoop()
fmt.Println("after marking:")
fmt.Println(fieldMap.String())
// fmt.Println("after marking loop:")
// fmt.Println(fieldMap.String())
fmt.Println("beore marking closest Outer:")
// 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)
}
@ -58,52 +61,72 @@ func Run() int {
// cell would map 'from' to 'to'
type Cell struct {
Coord Coord
Tile rune
Neighbords []Coord
Coord Coord
Tile rune
Neighbords []Coord
IsOnMainPath bool
IsOuter bool
}
func (c *Cell)String() string {
func (c *Cell) String() string {
if c.Tile == 'S' {
return "S"
}
if c.IsOuter {
return "O"
}
if !c.IsOnMainPath {
return " "
}
switch c.Tile {
case '7': return "⌝"
case 'J': return "⌟"
case 'F': return "⌜"
case 'L': return "⌞"
case '.': return " "
default: return string(c.Tile)
case '7':
return "⌝"
case 'J':
return "⌟"
case 'F':
return "⌜"
case 'L':
return "⌞"
case '.':
return " "
default:
return string(c.Tile)
}
}
type Coord struct {
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
}
type Direction int
const (UP Direction = iota
const (
UP Direction = iota
DOWN
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
result := Coord{}
switch d {
case UP:
result = Coord{x, y-1}
case DOWN:
result = Coord{x, y+1}
case LEFT:
result = Coord{x-1, y}
case RIGHT:
result = Coord{x+1, y}
case UP:
result = Coord{x, y - 1}
case DOWN:
result = Coord{x, y + 1}
case LEFT:
result = Coord{x - 1, y}
case RIGHT:
result = Coord{x + 1, y}
}
return result
}
@ -113,7 +136,8 @@ type Map struct {
Height, Width int
BeastCoord Coord
}
func (m *Map)String() string {
func (m *Map) String() string {
result := ""
for y := 0; y < m.Height; y++ {
for x := 0; x < m.Width; x++ {
@ -125,7 +149,7 @@ func (m *Map)String() string {
return result
}
func (m *Map)markMainLoop() {
func (m *Map) markMainLoop() {
start := m.Cells[m.BeastCoord]
start.IsOnMainPath = true
m.Cells[m.BeastCoord] = start
@ -136,7 +160,7 @@ func (m *Map)markMainLoop() {
currentCell.IsOnMainPath = true
m.Cells[currentCell.Coord] = currentCell
// 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)
if err != nil {
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.
// 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)
len = 1
previous := m.Cells[m.BeastCoord]
@ -157,7 +286,7 @@ func (m *Map)checkDirectionFromBeast(through Coord) (isCycle bool, len int) {
for found && currentCell.Tile != 'S' {
// log.Printf("check direction loop for %+v (%s)\n", currentCell, currentCell.String())
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)
if err != nil {
return
@ -178,7 +307,7 @@ func (m *Map)checkDirectionFromBeast(through Coord) (isCycle bool, len int) {
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 {
return false
}
@ -228,18 +357,25 @@ func (c *Cell) GetNeighbors() []Coord {
// - check if 'from' is in neighbors
// if it is - then take another neighbor
// 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 {
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)
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
return c.Neighbords[otherIndex], nil
return c.Neighbords[otherIndex], nextDirection, nil
}
// 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
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