183 lines
4.3 KiB
Go
183 lines
4.3 KiB
Go
package geom
|
|
|
|
import (
|
|
//"fmt"
|
|
"image/color"
|
|
"math/rand"
|
|
|
|
"github.com/hajimehoshi/ebiten/v2"
|
|
)
|
|
|
|
var defaultSquareSpacing = 5
|
|
var minBorder = 20
|
|
var ScoreOffset = 50
|
|
var HighScoreOffset = 10
|
|
var GameGrid Grid
|
|
var MaxGridDimension = 20
|
|
|
|
type Grid struct {
|
|
squareSpacing int
|
|
squares [][]Square
|
|
startX int
|
|
startY int
|
|
squareSize int
|
|
coloredSquaresRemaining int
|
|
}
|
|
|
|
// used for comparing two squares positions
|
|
type Pair struct {
|
|
rowNum int
|
|
colNum int
|
|
}
|
|
|
|
func (pr Pair) equal(pr2 Pair) bool {
|
|
return pr.rowNum == pr2.rowNum && pr.colNum == pr2.colNum
|
|
|
|
}
|
|
|
|
func pairAlreadyExists(pr Pair, pairs []Pair) bool {
|
|
result := false
|
|
for _, nextPair := range pairs {
|
|
if pr.equal(nextPair) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (grd *Grid) NumSquares() int {
|
|
size := -1
|
|
if len(grd.squares[0]) != 0 {
|
|
size = len(grd.squares) * len(grd.squares[0])
|
|
}
|
|
return size
|
|
}
|
|
|
|
// returns num rows by num columns
|
|
func (grd *Grid) Size() (int, int) {
|
|
if len(grd.squares[0]) != 0 {
|
|
return len(grd.squares), len(grd.squares[0])
|
|
}
|
|
return 0, 0
|
|
}
|
|
|
|
func BuildGrid(numRows int, numColumns int) {
|
|
grd := Grid{squareSpacing: defaultSquareSpacing}
|
|
|
|
winWidth, winHeight := ebiten.WindowSize()
|
|
sqSize := min((winWidth-2*minBorder-defaultSquareSpacing*numColumns)/numColumns, (winHeight-2*minBorder-ScoreOffset-3*HighScoreOffset-defaultSquareSpacing*numRows)/numRows)
|
|
sqSize = max(sqSize, 1) //ensure a nonzero, nonnegative square size
|
|
gridWidth := numColumns*(sqSize+grd.squareSpacing) - grd.squareSpacing
|
|
gridHeight := numRows*(sqSize+grd.squareSpacing) - grd.squareSpacing
|
|
|
|
currentX := (winWidth - gridWidth) / 2
|
|
currentY := ScoreOffset + (winHeight-gridHeight-ScoreOffset-HighScoreOffset)/2
|
|
grd.startX = currentX
|
|
grd.startY = currentY
|
|
grd.squareSize = sqSize
|
|
|
|
table := make([][]Square, numRows)
|
|
|
|
for i := 0; i < numRows; i++ {
|
|
row := make([]Square, numColumns)
|
|
for j := 0; j < numColumns; j++ {
|
|
sq := MakeSquare(sqSize)
|
|
sq.SetPosition(currentX, currentY)
|
|
row[j] = sq
|
|
currentX += sqSize + grd.squareSpacing
|
|
}
|
|
table[i] = row
|
|
currentY += sqSize + grd.squareSpacing
|
|
currentX = grd.startX
|
|
}
|
|
|
|
grd.squares = table
|
|
|
|
//assign random colours to a subset of all squares
|
|
squaresToColour := min(numColumns, numRows)
|
|
|
|
usedPositions := make([]Pair, squaresToColour)
|
|
coloredSoFar := 0
|
|
for i := 0; i < squaresToColour; i++ {
|
|
colourIndex := rand.Intn(len(LightRGBMap))
|
|
row := rand.Intn(numRows) + 1
|
|
col := rand.Intn(numColumns) + 1
|
|
//prevent a colour on the starting square
|
|
if row == numRows && col == 1 {
|
|
col = 2
|
|
}
|
|
|
|
//make sure we don't colour the same square twice
|
|
nextPair := Pair{rowNum: row, colNum: col}
|
|
if coloredSoFar == 0 {
|
|
usedPositions[0] = nextPair
|
|
coloredSoFar = 1
|
|
} else {
|
|
for pairAlreadyExists(nextPair, usedPositions) {
|
|
row = rand.Intn(numRows) + 1
|
|
col = rand.Intn(numColumns) + 1
|
|
//prevent a colour on the starting square
|
|
if row == numRows && col == 1 {
|
|
col = 2
|
|
}
|
|
nextPair = Pair{rowNum: row, colNum: col}
|
|
}
|
|
usedPositions[coloredSoFar] = nextPair
|
|
coloredSoFar += 1
|
|
|
|
}
|
|
|
|
grd.ChangeColour(row, col, LightRGBMap[colourIndex])
|
|
grd.GetSquareAt(row, col).RGBColourIndex = colourIndex
|
|
}
|
|
grd.coloredSquaresRemaining = squaresToColour
|
|
|
|
GameGrid = grd
|
|
}
|
|
|
|
func (grd *Grid) Draw(screen *ebiten.Image) {
|
|
opts := &ebiten.DrawImageOptions{}
|
|
|
|
for _, rowOfSquares := range grd.squares {
|
|
for _, sq := range rowOfSquares {
|
|
xPos := float64(sq.X())
|
|
yPos := float64(sq.Y())
|
|
opts.GeoM.Translate(xPos, yPos)
|
|
screen.DrawImage(sq.Img, opts)
|
|
opts.GeoM.Reset()
|
|
}
|
|
}
|
|
}
|
|
|
|
func (grd *Grid) DrawUpTo(finalSquareCount int, screen *ebiten.Image) {
|
|
opts := &ebiten.DrawImageOptions{}
|
|
curr := 1
|
|
for _, rowOfSquares := range grd.squares {
|
|
for _, sq := range rowOfSquares {
|
|
xPos := float64(sq.X())
|
|
yPos := float64(sq.Y())
|
|
opts.GeoM.Translate(xPos, yPos)
|
|
screen.DrawImage(sq.Img, opts)
|
|
opts.GeoM.Reset()
|
|
if curr == finalSquareCount {
|
|
return
|
|
}
|
|
curr++
|
|
}
|
|
}
|
|
}
|
|
|
|
func (grd *Grid) ChangeColour(row int, column int, clr color.Color) {
|
|
sq := grd.squares[row-1][column-1]
|
|
sq.ChangeColour(clr)
|
|
}
|
|
|
|
func (grd *Grid) GetSquareAt(row int, column int) *Square {
|
|
return &grd.squares[row-1][column-1]
|
|
}
|
|
|
|
func (grd *Grid) ColouredSquaresRemaining() int {
|
|
return grd.coloredSquaresRemaining
|
|
}
|