Initial commit, also running version
This commit is contained in:
181
game.go
Normal file
181
game.go
Normal file
@@ -0,0 +1,181 @@
|
||||
package minesweeper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image/color"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/examples/resources/fonts"
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||
"github.com/hajimehoshi/ebiten/v2/text/v2"
|
||||
)
|
||||
|
||||
type Game struct {
|
||||
Width, Height int
|
||||
CellSize int
|
||||
rows, columns int
|
||||
bombPercentage int
|
||||
cells []Cell
|
||||
firstMove bool
|
||||
lost bool
|
||||
won bool
|
||||
bombIndexes map[int]struct{}
|
||||
faceSource *text.GoTextFaceSource
|
||||
}
|
||||
|
||||
func NewGame(width, height, cellSize, bombPercentage int) (*Game, error) {
|
||||
s, err := text.NewGoTextFaceSource(bytes.NewReader(fonts.MPlus1pRegular_ttf))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows := width / cellSize
|
||||
columns := height / cellSize
|
||||
|
||||
g := &Game{
|
||||
Width: width,
|
||||
Height: height,
|
||||
CellSize: cellSize,
|
||||
rows: rows,
|
||||
columns: columns,
|
||||
bombPercentage: bombPercentage,
|
||||
cells: make([]Cell, rows*columns),
|
||||
firstMove: false,
|
||||
lost: false,
|
||||
won: false,
|
||||
bombIndexes: map[int]struct{}{},
|
||||
faceSource: s,
|
||||
}
|
||||
|
||||
g.Reset()
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func (g *Game) CheckWin() {
|
||||
for _, cell := range g.cells {
|
||||
if cell.cellType != BOMB && cell.state == FLAG {
|
||||
return
|
||||
} else if cell.cellType == BOMB && cell.state != FLAG {
|
||||
return
|
||||
} else if cell.state == DARK {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
g.won = true
|
||||
return
|
||||
}
|
||||
|
||||
func (g *Game) HandleFirstMove(i int) {
|
||||
if !g.firstMove {
|
||||
return
|
||||
}
|
||||
|
||||
indexes := make([]int, 0)
|
||||
|
||||
g.applyNeighbours(i, func(index int) {
|
||||
indexes = append(indexes, index)
|
||||
r := RandomUntilNoBomb(g.rows*g.columns, g.bombIndexes)
|
||||
g.cells[r].cellType = BOMB
|
||||
})
|
||||
|
||||
for _, i := range indexes {
|
||||
g.cells[i].cellType = NO_BOMB
|
||||
}
|
||||
|
||||
for i := range g.cells {
|
||||
g.cells[i].bombNeighbours = g.CalcNeighbourBombs(i)
|
||||
}
|
||||
|
||||
g.SetBomblessNeighboursToOpen(i)
|
||||
g.firstMove = false
|
||||
}
|
||||
|
||||
func (g *Game) Reset() {
|
||||
cells, indexes := g.SetupCells()
|
||||
g.cells = cells
|
||||
g.bombIndexes = indexes
|
||||
g.won = false
|
||||
g.lost = false
|
||||
g.firstMove = true
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
if !g.won && !g.lost {
|
||||
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
|
||||
x, y := ebiten.CursorPosition()
|
||||
index := g.CursorPosToIndex(x, y)
|
||||
g.HandleFirstMove(index)
|
||||
|
||||
if g.cells[index].cellType == BOMB && g.cells[index].state != FLAG {
|
||||
g.lost = true
|
||||
} else if g.cells[index].state != FLAG {
|
||||
g.cells[index].state = OPEN
|
||||
if g.cells[index].bombNeighbours == 0 {
|
||||
g.SetBomblessNeighboursToOpen(index)
|
||||
}
|
||||
}
|
||||
} else if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonRight) {
|
||||
x, y := ebiten.CursorPosition()
|
||||
index := g.CursorPosToIndex(x, y)
|
||||
if g.cells[index].state == DARK {
|
||||
g.cells[index].state = FLAG
|
||||
} else if g.cells[index].state == FLAG {
|
||||
g.cells[index].state = DARK
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if inpututil.IsKeyJustPressed(ebiten.KeyR) {
|
||||
g.Reset()
|
||||
}
|
||||
|
||||
g.CheckWin()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
showBombs := false
|
||||
if g.lost {
|
||||
showBombs = true
|
||||
ebitenutil.DebugPrint(screen, "Game Over!")
|
||||
} else if g.won {
|
||||
ebitenutil.DebugPrint(screen, "Game Won :) YAAY!")
|
||||
return
|
||||
}
|
||||
|
||||
g.DrawCells(screen, showBombs)
|
||||
}
|
||||
|
||||
func (g *Game) DrawCells(screen *ebiten.Image, showBombs bool) {
|
||||
for _, cell := range g.cells {
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(float64(cell.left), float64(cell.top))
|
||||
|
||||
borderImage := ebiten.NewImage(g.CellSize, g.CellSize)
|
||||
borderImage.Fill(color.Black)
|
||||
|
||||
cellImage := ebiten.NewImage(g.CellSize-2, g.CellSize-2)
|
||||
if showBombs && cell.cellType == BOMB {
|
||||
cellImage.Fill(color.RGBA{255, 0, 0, 255})
|
||||
} else {
|
||||
cellImage.Fill(MatchColor(cell.state))
|
||||
}
|
||||
borderImage.DrawImage(cellImage, nil)
|
||||
|
||||
if cell.state == OPEN && cell.bombNeighbours != 0 {
|
||||
txOp := &text.DrawOptions{}
|
||||
txOp.GeoM.Translate(float64(g.CellSize-24)/2, float64(g.CellSize-24)/2)
|
||||
text.Draw(borderImage, fmt.Sprintf("%v", cell.bombNeighbours), &text.GoTextFace{Source: g.faceSource, Size: 24}, txOp)
|
||||
}
|
||||
|
||||
screen.DrawImage(borderImage, op)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
|
||||
return outsideWidth, outsideHeight
|
||||
}
|
||||
Reference in New Issue
Block a user