@@ -31,6 +31,7 @@ type model struct {
31
31
playerRow int
32
32
playerCol int
33
33
34
+ score int
34
35
gameOver bool
35
36
}
36
37
@@ -84,7 +85,8 @@ func (m *model) movePlayer(row, col int) {
84
85
85
86
if m.table [row ][col ] == item {
86
87
// We collected an item. A new item and enemy needs to be
87
- // spawned.
88
+ // spawned. Increase the score.
89
+ m .score ++
88
90
m .spawnItem ()
89
91
m .spawnEnemy ()
90
92
}
@@ -131,39 +133,45 @@ func (m *model) playerRight() {
131
133
m .movePlayer (m .playerRow , m .playerCol + 1 )
132
134
}
133
135
134
- // newModel is responsible for creating an initial model that is ready to use.
135
- func newModel () * model {
136
+ // init is responsible for initializing or resetting a model that is ready
137
+ // to use for a new game.
138
+ func (m * model ) init () {
139
+ // Clear and reset all fields as init() is also used for restarting
140
+ // an existing game. Therefore our model needs to be fresh.
136
141
// By default, all entries in our table have value zero as type rune
137
- // is based on int and represents symbols. We only set non-empty fields
138
- // explicitly.
139
- model := & model {}
142
+ // is based on int and represents symbols. Initially, all cells are
143
+ // empty.
144
+ var table [tableHeight ][tableWidth ]rune
145
+ m .table = table
146
+ m .playerRow = 0
147
+ m .playerCol = 0
148
+ m .score = 0
149
+ m .gameOver = false
140
150
141
151
// Set the four corners.
142
- model .table [0 ][0 ] = corner
143
- model .table [0 ][tableWidth - 1 ] = corner
144
- model .table [tableHeight - 1 ][0 ] = corner
145
- model .table [tableHeight - 1 ][tableWidth - 1 ] = corner
152
+ m .table [0 ][0 ] = corner
153
+ m .table [0 ][tableWidth - 1 ] = corner
154
+ m .table [tableHeight - 1 ][0 ] = corner
155
+ m .table [tableHeight - 1 ][tableWidth - 1 ] = corner
146
156
147
157
// Draw horizontal borders at the top and bottom.
148
158
for col := 1 ; col < tableWidth - 1 ; col ++ {
149
- model .table [0 ][col ] = lineHorizontal
150
- model .table [tableHeight - 1 ][col ] = lineHorizontal
159
+ m .table [0 ][col ] = lineHorizontal
160
+ m .table [tableHeight - 1 ][col ] = lineHorizontal
151
161
}
152
162
153
163
// Draw vertical borders on the left and right side.
154
164
for row := 1 ; row < tableHeight - 1 ; row ++ {
155
- model .table [row ][0 ] = lineVertical
156
- model .table [row ][tableWidth - 1 ] = lineVertical
165
+ m .table [row ][0 ] = lineVertical
166
+ m .table [row ][tableWidth - 1 ] = lineVertical
157
167
}
158
168
159
169
// Spawn our player near the top left corner.
160
- model .playerRow = 1
161
- model .playerCol = 1
162
- model.table [model.playerRow ][model.playerCol ] = player
163
-
164
- model .spawnItem ()
170
+ m .playerRow = 1
171
+ m .playerCol = 1
172
+ m.table [m.playerRow ][m.playerCol ] = player
165
173
166
- return model
174
+ m . spawnItem ()
167
175
}
168
176
169
177
// Init can be used to setup initial command to perform.
@@ -180,9 +188,17 @@ func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
180
188
181
189
case tea.KeyMsg :
182
190
183
- // If our game is lost, any key shall terminate the program .
191
+ // If our game is lost, any key shall restart the game .
184
192
if m .gameOver {
185
- return m , tea .Quit
193
+
194
+ switch msg .String () {
195
+
196
+ case "ctrl+c" , "q" :
197
+ return m , tea .Quit
198
+ case "enter" :
199
+ m .init ()
200
+ return m , nil
201
+ }
186
202
}
187
203
188
204
switch msg .String () {
@@ -207,13 +223,20 @@ func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
207
223
// View is required for building what we want to show on the screen.
208
224
// That means we need to translate our model data into a string for displaying.
209
225
func (m * model ) View () string {
226
+ builder := strings.Builder {}
227
+
210
228
if m .gameOver {
211
229
// Just inform about game over and don't continue.
212
- return "Player died, Game Over!"
230
+ builder .WriteString ("\n \n \n \n \n " )
231
+ builder .WriteString (" You died, Game Over!" )
232
+ builder .WriteString ("\n \n " )
233
+ builder .WriteString (fmt .Sprintf (" Your score: %d" , m .score ))
234
+ builder .WriteString ("\n \n " )
235
+ builder .WriteString (" Press enter to restart or q to quit" )
236
+
237
+ return builder .String ()
213
238
}
214
239
215
- builder := strings.Builder {}
216
-
217
240
// Iterate our table (2d array) and print non-empty fields as set in
218
241
// our model. Empty (zero) fields shall be printed with a blank space.
219
242
for _ , row := range m .table {
@@ -235,7 +258,8 @@ func (m *model) View() string {
235
258
236
259
func main () {
237
260
// Create our initial model.
238
- model := newModel ()
261
+ model := & model {}
262
+ model .init ()
239
263
240
264
// Program setup to initialize bubbletea and use full screen.
241
265
program := tea .NewProgram (model , tea .WithAltScreen ())
0 commit comments