this repo has no description
1package main
2
3import (
4 "bytes"
5 "strconv"
6
7 ff "github.com/firefly-zero/firefly-go/firefly"
8)
9
10type Grid struct {
11 NumRows int
12 NumCols int
13 Grid [][]int
14}
15
16func (grid *Grid) Initialize() {
17 grid.NumRows = CONFIG.Grid.Rows
18 grid.NumCols = CONFIG.Grid.Columns
19 grid.Grid = make([][]int, grid.NumRows)
20 for i := range grid.Grid {
21 grid.Grid[i] = make([]int, grid.NumCols)
22 }
23}
24
25// Prints Game state for debug purposes
26func (grid *Grid) Print() {
27 for row := 0; row < CONFIG.Grid.Rows; row++ {
28 var b bytes.Buffer
29 b.WriteString(strconv.Itoa(row))
30 b.WriteString(":\t")
31 for col := 0; col < CONFIG.Grid.Columns; col++ {
32 b.WriteString(strconv.Itoa(grid.Grid[row][col]))
33 }
34 ff.LogDebug(b.String())
35 }
36}
37
38func (grid *Grid) Render() {
39 // TODO: implement proper offset configuration, so the grid is displayed centered
40
41 for row := 0; row < grid.NumRows; row++ {
42 for col := 0; col < grid.NumCols; col++ {
43 cellValue := grid.Grid[row][col]
44
45 // cellValue 0 means empty cell / no block
46 if cellValue == 0 {
47 ff.DrawRect(
48 ff.P(col*CELLSIZE+OFFSET, row*CELLSIZE),
49 ff.S(CELLSIZE-1, CELLSIZE-1),
50 ff.Style{
51 FillColor: CONFIG.Grid.FillColor,
52 StrokeColor: CONFIG.Grid.StrokeColor,
53 StrokeWidth: 1,
54 },
55 )
56 } else {
57 // cellValue > 0 means a block; here we determine the color
58 color := grid.getCellColor(cellValue)
59
60 ff.DrawRect(
61 ff.P(col*CELLSIZE+OFFSET, row*CELLSIZE),
62 ff.S(CELLSIZE-1, CELLSIZE-1),
63 ff.Style{
64 FillColor: color,
65 StrokeColor: color,
66 StrokeWidth: 1,
67 },
68 )
69 }
70 }
71 }
72}
73
74func (grid *Grid) getCellColor(cellValue int) ff.Color {
75 var color ff.Color
76
77 // if the cellValue < 10, then we are in single player mode
78 // and each distinct cellValue is supposed to get a dedicated
79 // color as configured per block type
80 if cellValue < 10 {
81 return *COLORS[cellValue]
82 } else if CONFIG.GameMode == MultiplayerCoop {
83 // but in multiplayer mode, blocks of a player have the same color
84 // player1 has cellValues 11, 12, 13, 14, 15, 16, 17 - he gets COLORS[1]
85 // player2 has cellValues 21, 22, 23, 24, 25, 26, 27 - he gets COLORS[2]
86 // playerN has cellValues N1, N2, NN, N4, N5, N6, N7 - he gets COLORS[N]
87 // ... as len(COLORS) == 8 this would break with more than 8 players
88 return *COLORS[cellValue/10]
89 }
90 return color
91}
92
93func (grid *Grid) IsCellOutside(row, column int) bool {
94 if row >= 0 && row < grid.NumRows && column >= 0 && column < grid.NumCols {
95 return false
96 }
97 return true
98}
99
100func (grid *Grid) IsCellEmpty(row, column int) bool {
101 return grid.Grid[row][column] == 0
102}
103
104func (grid *Grid) IsRowFull(row int) bool {
105 for column := 0; column < grid.NumCols; column++ {
106 if grid.Grid[row][column] == 0 {
107 return false
108 }
109 }
110 return true
111}
112
113func (grid *Grid) ClearRow(row int) {
114 for column := 0; column < grid.NumCols; column++ {
115 grid.Grid[row][column] = 0
116 }
117}
118
119func (grid *Grid) ClearFullRows() int {
120 completed := 0
121 for row := grid.NumRows - 1; row >= 0; row-- {
122 if grid.IsRowFull(row) {
123 grid.ClearRow(row)
124 completed++
125 } else if completed > 0 {
126 grid.MoveRowDown(row, completed)
127 }
128 }
129 return completed
130}
131
132func (grid *Grid) MoveRowDown(row, numRows int) {
133 for column := 0; column < grid.NumCols; column++ {
134 grid.Grid[row+numRows][column] = grid.Grid[row][column]
135 grid.Grid[row][column] = 0
136 }
137}
138
139func (grid *Grid) LockBlock(tiles []Position, blockID int, player *Player) {
140 // In MultiplayerCoop we add a multiple of 10 (playerOffset) to the blockID
141 // to identify which player locked the block (e.g. to color the blocks accordingly)
142 //
143 // player1 has cellValues 11, 12, 13, 14, 15, 16, 17 - he gets COLORS[1]
144 // player2 has cellValues 21, 22, 23, 24, 25, 26, 27 - he gets COLORS[2]
145 // playerN has cellValues N1, N2, NN, N4, N5, N6, N7 - he gets COLORS[N]
146 playerOffset := 0
147 if CONFIG.GameMode == MultiplayerCoop {
148 playerOffset = (player.playerNum + 1) * 10
149 }
150
151 for _, tile := range tiles {
152 grid.Grid[tile.Row][tile.Column] = blockID + playerOffset
153 }
154}
155
156// CanFitBlock checks if a block's tiles can fit in the grid
157func (grid *Grid) CanFitBlock(tiles []Position) bool {
158 for _, tile := range tiles {
159 if grid.IsCellOutside(tile.Row, tile.Column) {
160 return false
161 }
162 if !grid.IsCellEmpty(tile.Row, tile.Column) {
163 return false
164 }
165 }
166 return true
167}