diff --git a/day10/dayTen.go b/day10/dayTen.go index ced6b31..df9aa76 100644 --- a/day10/dayTen.go +++ b/day10/dayTen.go @@ -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 diff --git a/day10/example5 b/day10/example5 new file mode 100644 index 0000000..ac0e889 --- /dev/null +++ b/day10/example5 @@ -0,0 +1,7 @@ +....... +...F7.. +..FJ|.. +.SJ.L7. +.|F--J. +.LJ.... +....... diff --git a/day10/notes.org b/day10/notes.org index b3b7f20..6b2db93 100644 --- a/day10/notes.org +++ b/day10/notes.org @@ -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