clone

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

main
puzzletea / export / pdf / parse_nonogram.go
parse_nonogram.go 2.4K
1package pdfexport23import (4 "encoding/json"5 "fmt"6 "strings"7)89type nonogramSave struct {10 State string `json:"state"`11 Width int `json:"width"`12 Height int `json:"height"`13 RowHints [][]int `json:"row-hints"`14 ColHints [][]int `json:"col-hints"`15}1617func ParseNonogramPrintData(saveData []byte) (*NonogramData, error) {18 if len(strings.TrimSpace(string(saveData))) == 0 {19 return nil, nil20 }2122 var save nonogramSave23 if err := json.Unmarshal(saveData, &save); err != nil {24 return nil, fmt.Errorf("decode nonogram save: %w", err)25 }2627 stateRows := splitNonogramStateRows(save.State)2829 width := save.Width30 if width <= 0 {31 width = len(save.ColHints)32 }33 if width <= 0 {34 width = maxRuneWidth(stateRows)35 }3637 height := save.Height38 if height <= 0 {39 height = len(save.RowHints)40 }41 if height <= 0 {42 height = len(stateRows)43 }4445 if width <= 0 || height <= 0 {46 return nil, nil47 }4849 return &NonogramData{50 Width: width,51 Height: height,52 RowHints: normalizeNonogramHintRows(save.RowHints, height),53 ColHints: normalizeNonogramHintRows(save.ColHints, width),54 Grid: normalizeNonogramStateGrid(stateRows, width, height),55 }, nil56}5758func splitNonogramStateRows(raw string) []string {59 normalized := strings.ReplaceAll(strings.ReplaceAll(raw, "\r\n", "\n"), "\r", "\n")60 if normalized == "" {61 return nil62 }63 return strings.Split(normalized, "\n")64}6566func maxRuneWidth(rows []string) int {67 maxWidth := 068 for _, row := range rows {69 if n := len([]rune(row)); n > maxWidth {70 maxWidth = n71 }72 }73 return maxWidth74}7576func normalizeNonogramHintRows(src [][]int, size int) [][]int {77 if size <= 0 {78 return nil79 }8081 normalized := make([][]int, size)82 for i := range size {83 if i >= len(src) {84 normalized[i] = []int{0}85 continue86 }8788 filtered := make([]int, 0, len(src[i]))89 for _, value := range src[i] {90 if value > 0 {91 filtered = append(filtered, value)92 }93 }94 if len(filtered) == 0 {95 filtered = []int{0}96 }97 normalized[i] = filtered98 }99100 return normalized101}102103func normalizeNonogramStateGrid(rows []string, width, height int) [][]string {104 if width <= 0 || height <= 0 {105 return nil106 }107108 grid := make([][]string, height)109 for y := range height {110 grid[y] = make([]string, width)111 for x := range width {112 grid[y][x] = " "113 }114115 if y >= len(rows) {116 continue117 }118119 runes := []rune(rows[y])120 for x := 0; x < width && x < len(runes); x++ {121 if runes[x] == ' ' {122 continue123 }124 grid[y][x] = string(runes[x])125 }126 }127128 return grid129}