package ui import ( "fmt" "github.com/ryanhamamura/c4/snake" "github.com/ryanhamamura/via/h" ) func SnakeBoard(sg *snake.SnakeGame) h.H { state := sg.State if state == nil || sg.Status != snake.StatusInProgress && sg.Status != snake.StatusFinished { return nil } // Build a lookup grid for rendering type cellInfo struct { snakeIdx int // -1 = empty, -2 = food isHead bool } grid := make([][]cellInfo, state.Height) for y := 0; y < state.Height; y++ { grid[y] = make([]cellInfo, state.Width) for x := 0; x < state.Width; x++ { grid[y][x] = cellInfo{snakeIdx: -1} } } for fi := range state.Food { f := state.Food[fi] if f.X >= 0 && f.X < state.Width && f.Y >= 0 && f.Y < state.Height { grid[f.Y][f.X] = cellInfo{snakeIdx: -2} } } for si, s := range state.Snakes { if s == nil { continue } for bi, bp := range s.Body { if bp.X >= 0 && bp.X < state.Width && bp.Y >= 0 && bp.Y < state.Height { grid[bp.Y][bp.X] = cellInfo{snakeIdx: si, isHead: bi == 0} } } } // Cell size scales with grid dimensions cellSize := cellSizeForGrid(state.Width, state.Height) var rows []h.H for y := 0; y < state.Height; y++ { var cells []h.H for x := 0; x < state.Width; x++ { ci := grid[y][x] class := "snake-cell" style := fmt.Sprintf("width:%dpx;height:%dpx;", cellSize, cellSize) switch { case ci.snakeIdx == -2: class += " snake-food" case ci.snakeIdx >= 0: s := state.Snakes[ci.snakeIdx] colorIdx := ci.snakeIdx bg := "" if colorIdx < len(snake.SnakeColors) { bg = snake.SnakeColors[colorIdx] style += fmt.Sprintf("background:%s;", bg) } if !s.Alive { class += " snake-dead" } if ci.isHead { class += " snake-head" if bg != "" { style += fmt.Sprintf("box-shadow:0 0 8px %s;", bg) } } } cells = append(cells, h.Div(h.Class(class), h.Attr("style", style))) } rowAttrs := append([]h.H{h.Class("snake-row")}, cells...) rows = append(rows, h.Div(rowAttrs...)) } boardStyle := fmt.Sprintf("grid-template-columns:repeat(%d,1fr);", state.Width) attrs := []h.H{ h.Class("snake-board"), h.Attr("style", boardStyle), } attrs = append(attrs, rows...) return h.Div(attrs...) } func cellSizeForGrid(width, height int) int { maxDim := width if height > maxDim { maxDim = height } switch { case maxDim <= 15: return 28 case maxDim <= 20: return 24 case maxDim <= 30: return 20 case maxDim <= 40: return 16 default: return 14 } }