Initial commit, also running version
This commit is contained in:
26
cell.go
Normal file
26
cell.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package minesweeper
|
||||||
|
|
||||||
|
import "image/color"
|
||||||
|
|
||||||
|
type CellType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
NO_BOMB CellType = iota
|
||||||
|
BOMB
|
||||||
|
)
|
||||||
|
|
||||||
|
type State int
|
||||||
|
|
||||||
|
const (
|
||||||
|
OPEN State = iota
|
||||||
|
DARK
|
||||||
|
FLAG
|
||||||
|
)
|
||||||
|
|
||||||
|
type Cell struct {
|
||||||
|
top, left float32
|
||||||
|
color color.Color
|
||||||
|
state State
|
||||||
|
cellType CellType
|
||||||
|
bombNeighbours int
|
||||||
|
}
|
||||||
26
cmd/mine-sweeper/main.go
Normal file
26
cmd/mine-sweeper/main.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
minesweeper "github.com/Pablu23/mine-sweeper"
|
||||||
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
width := 720
|
||||||
|
height := 720
|
||||||
|
cellSize := 60
|
||||||
|
bombPercentage := 20
|
||||||
|
|
||||||
|
ebiten.SetWindowSize(width, height)
|
||||||
|
ebiten.SetWindowTitle("Hello, World!")
|
||||||
|
game, err := minesweeper.NewGame(width, height, cellSize, bombPercentage)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ebiten.RunGame(game); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
9
constants.go
Normal file
9
constants.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package minesweeper
|
||||||
|
|
||||||
|
import "image/color"
|
||||||
|
|
||||||
|
var (
|
||||||
|
OPEN_COLOR = color.RGBA{200, 200, 200, 255}
|
||||||
|
DARK_COLOR = color.RGBA{20, 20, 20, 255}
|
||||||
|
FLAG_COLOR = color.RGBA{0, 255, 0, 255}
|
||||||
|
)
|
||||||
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
|
||||||
|
}
|
||||||
24
go.mod
Normal file
24
go.mod
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
module github.com/Pablu23/mine-sweeper
|
||||||
|
|
||||||
|
go 1.23.4
|
||||||
|
|
||||||
|
require github.com/hajimehoshi/ebiten/v2 v2.8.8
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200707082815-5321531c36a2 // indirect
|
||||||
|
github.com/go-text/typesetting v0.2.0 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 // indirect
|
||||||
|
golang.org/x/image v0.20.0 // indirect
|
||||||
|
golang.org/x/mobile v0.0.0-20210208171126-f462b3930c8f // indirect
|
||||||
|
golang.org/x/text v0.18.0 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325 // indirect
|
||||||
|
github.com/ebitengine/hideconsole v1.0.0 // indirect
|
||||||
|
github.com/ebitengine/purego v0.8.0 // indirect
|
||||||
|
github.com/hajimehoshi/ebiten v1.12.12
|
||||||
|
github.com/jezek/xgb v1.1.1 // indirect
|
||||||
|
golang.org/x/sync v0.8.0 // indirect
|
||||||
|
golang.org/x/sys v0.25.0 // indirect
|
||||||
|
)
|
||||||
80
go.sum
Normal file
80
go.sum
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
|
github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325 h1:Gk1XUEttOk0/hb6Tq3WkmutWa0ZLhNn/6fc6XZpM7tM=
|
||||||
|
github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325/go.mod h1:ulhSQcbPioQrallSuIzF8l1NKQoD7xmMZc5NxzibUMY=
|
||||||
|
github.com/ebitengine/hideconsole v1.0.0 h1:5J4U0kXF+pv/DhiXt5/lTz0eO5ogJ1iXb8Yj1yReDqE=
|
||||||
|
github.com/ebitengine/hideconsole v1.0.0/go.mod h1:hTTBTvVYWKBuxPr7peweneWdkUwEuHuB3C1R/ielR1A=
|
||||||
|
github.com/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+GvvE=
|
||||||
|
github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200707082815-5321531c36a2 h1:Ac1OEHHkbAZ6EUnJahF0GKcU0FjPc/V8F1DvjhKngFE=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200707082815-5321531c36a2/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
|
github.com/go-text/typesetting v0.2.0 h1:fbzsgbmk04KiWtE+c3ZD4W2nmCRzBqrqQOvYlwAOdho=
|
||||||
|
github.com/go-text/typesetting v0.2.0/go.mod h1:2+owI/sxa73XA581LAzVuEBZ3WEEV2pXeDswCH/3i1I=
|
||||||
|
github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
|
github.com/hajimehoshi/bitmapfont v1.3.0/go.mod h1:/Qb7yVjHYNUV4JdqNkPs6BSZwLjKqkZOMIp6jZD0KgE=
|
||||||
|
github.com/hajimehoshi/ebiten v1.12.12 h1:JvmF1bXRa+t+/CcLWxrJCRsdjs2GyBYBSiFAfIqDFlI=
|
||||||
|
github.com/hajimehoshi/ebiten v1.12.12/go.mod h1:1XI25ImVCDPJiXox4h9yK/CvN5sjDYnbF4oZcFzPXHw=
|
||||||
|
github.com/hajimehoshi/ebiten/v2 v2.8.8 h1:xyMxOAn52T1tQ+j3vdieZ7auDBOXmvjUprSrxaIbsi8=
|
||||||
|
github.com/hajimehoshi/ebiten/v2 v2.8.8/go.mod h1:durJ05+OYnio9b8q0sEtOgaNeBEQG7Yr7lRviAciYbs=
|
||||||
|
github.com/hajimehoshi/file2byteslice v0.0.0-20200812174855-0e5e8a80490e/go.mod h1:CqqAHp7Dk/AqQiwuhV1yT2334qbA/tFWQW0MD2dGqUE=
|
||||||
|
github.com/hajimehoshi/go-mp3 v0.3.1/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM=
|
||||||
|
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
||||||
|
github.com/hajimehoshi/oto v0.6.8/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
||||||
|
github.com/jakecoffman/cp v1.0.0/go.mod h1:JjY/Fp6d8E1CHnu74gWNnU0+b9VzEdUVPoJxg2PsTQg=
|
||||||
|
github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4=
|
||||||
|
github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
|
||||||
|
github.com/jfreymuth/oggvorbis v1.0.1/go.mod h1:NqS+K+UXKje0FUYUPosyQ+XTVvjmVjps1aEZH1sumIk=
|
||||||
|
github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
|
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU=
|
||||||
|
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||||
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
|
golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/image v0.0.0-20200801110659-972c09e46d76/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw=
|
||||||
|
golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM=
|
||||||
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
|
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
|
golang.org/x/mobile v0.0.0-20210208171126-f462b3930c8f h1:aEcjdTsycgPqO/caTgnxfR9xwWOltP/21vtJyFztEy0=
|
||||||
|
golang.org/x/mobile v0.0.0-20210208171126-f462b3930c8f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
|
||||||
|
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
|
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||||
|
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||||
|
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
131
util.go
Normal file
131
util.go
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user