clone

fifteen puzzle games for the terminal, with daily puzzles, weekly ladders and xp, built on bubble tea

chore/app-model-decomp
puzzletea / games / fillomino / grid.go
grid.go 2.6K
1package fillomino23import (4 "strconv"5 "strings"6)78type point struct {9 x int10 y int11}1213type grid [][]int1415func newGrid(width, height int) grid {16 cells := make(grid, height)17 for y := range height {18 cells[y] = make([]int, width)19 }20 return cells21}2223func cloneGrid(src grid) grid {24 if src == nil {25 return nil26 }2728 height := len(src)29 width := 030 if height > 0 {31 width = len(src[0])32 }3334 dst := newGrid(width, height)35 for y := range height {36 copy(dst[y], src[y])37 }38 return dst39}4041func parseGrid(encoded string, width, height int) (grid, error) {42 cells := newGrid(width, height)43 rows := strings.Split(strings.TrimSpace(encoded), "\n")44 for y := range height {45 if y >= len(rows) {46 continue47 }4849 fields := strings.Fields(rows[y])50 if len(fields) == 0 {51 fields = splitCompactRow(rows[y])52 }53 if len(fields) != width {54 return nil, errInvalidGridEncoding55 }56 for x := range width {57 if fields[x] == "." {58 continue59 }60 value, err := strconv.Atoi(fields[x])61 if err != nil {62 return nil, errInvalidGridEncoding63 }64 cells[y][x] = value65 }66 }67 return cells, nil68}6970func splitCompactRow(row string) []string {71 items := make([]string, 0, len(row))72 for _, r := range row {73 items = append(items, string(r))74 }75 return items76}7778func encodeGrid(g grid) string {79 var rows []string80 for y, row := range g {81 items := make([]string, len(row))82 for x, value := range row {83 if value == 0 {84 items[x] = "."85 continue86 }87 items[x] = strconv.Itoa(value)88 }89 rows = append(rows, strings.Join(items, " "))90 if y == len(g)-1 {91 break92 }93 }94 return strings.Join(rows, "\n")95}9697func newProvidedMask(givens grid) [][]bool {98 mask := make([][]bool, len(givens))99 for y := range len(givens) {100 mask[y] = make([]bool, len(givens[y]))101 for x := range len(givens[y]) {102 mask[y][x] = givens[y][x] != 0103 }104 }105 return mask106}107108func serializeProvided(mask [][]bool) string {109 var rows []string110 for _, row := range mask {111 var line strings.Builder112 for _, value := range row {113 if value {114 line.WriteByte('#')115 continue116 }117 line.WriteByte('.')118 }119 rows = append(rows, line.String())120 }121 return strings.Join(rows, "\n")122}123124func deserializeProvided(encoded string, width, height int) [][]bool {125 mask := make([][]bool, height)126 rows := strings.Split(encoded, "\n")127 for y := range height {128 mask[y] = make([]bool, width)129 if y >= len(rows) {130 continue131 }132 for x := range width {133 if x < len(rows[y]) && rows[y][x] == '#' {134 mask[y][x] = true135 }136 }137 }138 return mask139}140141func maxCellValue(g grid) int {142 best := 0143 for y := range len(g) {144 for x := range len(g[y]) {145 if g[y][x] > best {146 best = g[y][x]147 }148 }149 }150 return best151}