1package hitori23import (4 "encoding/json"5 "fmt"67 "github.com/FelineStateMachine/puzzletea/game"8)910// Save represents the serialized state of a Hitori game.11type Save struct {12 Size int `json:"size"`13 Numbers string `json:"numbers"`14 Marks string `json:"marks"`15 ModeTitle string `json:"mode_title"`16}1718func (m Model) GetSave() ([]byte, error) {19 save := Save{20 Size: m.size,21 Numbers: m.numbers.String(),22 Marks: serializeMarks(m.userMarks),23 ModeTitle: m.modeTitle,24 }25 data, err := json.Marshal(save)26 if err != nil {27 return nil, fmt.Errorf("failed to marshal hitori save: %w", err)28 }29 return data, nil30}3132// ImportModel reconstructs a Model from saved JSON data.33func ImportModel(data []byte) (*Model, error) {34 var s Save35 if err := json.Unmarshal(data, &s); err != nil {36 return nil, fmt.Errorf("failed to unmarshal hitori save: %w", err)37 }38 if s.Size <= 0 {39 return nil, fmt.Errorf("invalid grid size in save: %d", s.Size)40 }4142 numbers := newGrid(state(s.Numbers))43 marks := deserializeMarks(s.Marks, s.Size)4445 m := &Model{46 size: s.Size,47 numbers: numbers,48 userMarks: marks,49 initialUserMarks: newMarks(s.Size),50 cursor: game.Cursor{X: 0, Y: 0},51 keys: DefaultKeyMap,52 modeTitle: s.ModeTitle,53 }54 m.recomputeState()55 return m, nil56}