package thirteen import ( "bufio" "fmt" "os" ) type axis rune const ( x axis = 'x' y axis = 'y' ) type fold struct { axis axis index int } type manual struct { dots map[int]map[int]bool folds []fold } func (m *manual) load(filename string) error { file, err := os.Open(filename) if err != nil { return err } defer file.Close() scanner := bufio.NewScanner(file) m.dots = map[int]map[int]bool{} m.folds = []fold{} scanningDots := true for scanner.Scan() { if scanner.Text() == "" { scanningDots = false continue } if scanningDots { var dotX, dotY int if count, err := fmt.Sscanf(scanner.Text(), "%d,%d", &dotX, &dotY); count != 2 || err != nil { return fmt.Errorf("expected 2 values, found %d: %w", count, err) } if m.dots[dotX] == nil { m.dots[dotX] = map[int]bool{} } m.dots[dotX][dotY] = true } else { var foldAxis axis var foldIndex int if count, err := fmt.Sscanf(scanner.Text(), "fold along %c=%d", &foldAxis, &foldIndex); count != 2 || err != nil { return fmt.Errorf("scanning %q, expected 2 values, found %d: %w", scanner.Text(), count, err) } m.folds = append(m.folds, fold{ axis: foldAxis, index: foldIndex, }) } } return nil } func gridSize(grid map[int]map[int]bool) (xSize, ySize int) { for x, col := range grid { if x > xSize { xSize = x } for y := range col { if y > ySize { ySize = y } } } // // Increment Size to reflect 0 indexed arrays xSize++ ySize++ return xSize, ySize } func countDots(grid map[int]map[int]bool) int { dots := 0 for _, col := range grid { for _, v := range col { if v { dots++ } } } return dots } func (m *manual) fold() { grid := m.dots for _, inst := range m.folds { grid, _ = foldGrid(inst, grid) } printGrid(grid) } func foldGrid(inst fold, grid map[int]map[int]bool) (map[int]map[int]bool, int) { newGrid := map[int]map[int]bool{} maxX, maxY := gridSize(grid) if inst.axis == x { // Copy the first rows for copyX := 0; copyX < inst.index; copyX++ { if newGrid[copyX] == nil { newGrid[copyX] = map[int]bool{} } for copyY := 0; copyY < maxY; copyY++ { newGrid[copyX][copyY] = grid[copyX][copyY] } } // Copy the folded values for foldX := inst.index + 1; foldX < maxX; foldX++ { targetX := inst.index - (foldX - inst.index) for targetY := 0; targetY < maxY; targetY++ { if grid[foldX][targetY] { newGrid[targetX][targetY] = grid[foldX][targetY] } } } } else { // initialize all X maps for k := range grid { newGrid[k] = map[int]bool{} } // Copy the first rows for copyY := 0; copyY < inst.index; copyY++ { for copyX := 0; copyX < maxX; copyX++ { if newGrid[copyX] == nil { newGrid[copyX] = map[int]bool{} } newGrid[copyX][copyY] = grid[copyX][copyY] } } // Copy the folded values for foldY := inst.index + 1; foldY < maxY; foldY++ { targetY := inst.index - (foldY - inst.index) for targetX := 0; targetX < maxX; targetX++ { if grid[targetX][foldY] { newGrid[targetX][targetY] = grid[targetX][foldY] } } } } return newGrid, countDots(newGrid) } func printGrid(grid map[int]map[int]bool) { maxX, maxY := gridSize(grid) for y := 0; y < maxY; y++ { row := "" for x := 0; x < maxX; x++ { if grid[x][y] { row += "#" } else { row += " " } } fmt.Println(row) } }