package minesweeper import ( "image/color" "golang.org/x/exp/rand" ) func RandomUntilNoBomb(cellCount int, bombIndexes map[int]struct{}) int { r := rand.Intn(cellCount) loop := true for loop { if _, ok := bombIndexes[r]; !ok { loop = false } r = rand.Intn(cellCount) } return r } func (g *Game) XYToIndex(x int, y int) int { index := y*(g.columns) + x return index } func (g *Game) IndexToXY(index int) (int, int) { x := index % (g.columns) y := index / (g.columns) return x, y } func (g *Game) CursorPosToIndex(x int, y int) int { logicX := x / g.CellSize logicY := y / g.CellSize return g.XYToIndex(logicX, logicY) } func (g *Game) CalcNeighbourBombs(index int) int { bombs := 0 g.applyNeighbours(index, func(i int) { if g.cells[i].cellType == BOMB { bombs += 1 } }) return bombs } func (g *Game) SetBomblessNeighboursToOpen(index int) { g.applyNeighbours(index, func(i int) { if g.cells[i].bombNeighbours == 0 && g.cells[i].state != OPEN { g.cells[i].state = OPEN g.SetBomblessNeighboursToOpen(i) } else if g.cells[i].cellType != BOMB { g.cells[i].state = OPEN } }) } func (g *Game) applyNeighbours(index int, f func(index int)) { posX, posY := g.IndexToXY(index) for x := -1; x <= 1; x++ { for y := -1; y <= 1; y++ { if posX+x < 0 || posX+x >= g.rows { continue } if posY+y < 0 || posY+y >= g.columns { continue } i := g.XYToIndex(posX+x, posY+y) f(i) } } } func MatchColor(state State) color.Color { switch state { case OPEN: return OPEN_COLOR case DARK: return DARK_COLOR case FLAG: return FLAG_COLOR default: return color.Black } } func (g *Game) SetupCells() ([]Cell, map[int]struct{}) { cellCount := (g.columns * g.rows) bombs := float64(cellCount) * (float64(g.bombPercentage) / 100) cells := make([]Cell, 0) bombIndexes := make(map[int]struct{}) for range int(bombs) { r := RandomUntilNoBomb(cellCount, bombIndexes) bombIndexes[r] = struct{}{} } index := 0 for x := range g.columns { for y := range g.rows { cellType := NO_BOMB cellColor := color.RGBA{120, 120, 120, 255} if _, isBomb := bombIndexes[index]; isBomb { cellType = BOMB cellColor = color.RGBA{255, 0, 0, 255} } cells = append(cells, Cell{ top: float32(x * g.CellSize), left: float32(y * g.CellSize), color: cellColor, cellType: cellType, state: DARK, }) index += 1 } } for i := range cells { cells[i].bombNeighbours = g.CalcNeighbourBombs(i) } return cells, bombIndexes }