2b5e4c3f05478f29f9877d5b3efbb704a299db6f
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

1) /* Blinker
2)    Copyright 2011-2019 Stefan Schuermans <stefan@blinkenarea.org>
3)    Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
4)    a blinkenarea.org project */
5) 
6) #include <cmath>
7) #include <stdlib.h>
8) #include <string>
9) #include <vector>
10) 
11) #include <BlinkenLib/BlinkenFrame.h>
12) 
13) #include "File.h"
14) #include "Format.h"
15) #include "FormatFile.h"
16) #include "Game.h"
17) #include "Mgrs.h"
18) #include "Module.h"
19) #include "NameFile.h"
20) #include "OpConn.h"
21) #include "OpConnIf.h"
22) #include "OpReqIf.h"
23) #include "OutStreamFile.h"
24) #include "Tetris.h"
25) #include "Time.h"
26) #include "TimeCallee.h"
27) #include "UIntFile.h"
28) 
29) namespace Blinker {
30) 
31) /**
32)  * @brief constructor
33)  * @param[in] name module name
34)  * @param[in] mgrs managers
35)  * @param[in] dirBase base directory
36)  */
37) Tetris::Tetris(const std::string &name, Mgrs &mgrs, const Directory &dirBase):
38)   Game(name, mgrs, dirBase),
39)   m_fileStoneColor(dirBase.getFile("stoneColor")),
40)   m_fileDelay(dirBase.getFile("delay")),
Stefan Schuermans tetris: dropping stones

Stefan Schuermans authored 5 years ago

41)   m_fileDropDelay(dirBase.getFile("dropDelay")),
Stefan Schuermans tetris: add blink delay

Stefan Schuermans authored 5 years ago

42)   m_fileBlinkDelay(dirBase.getFile("blinkDelay")),
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

43)   m_fileGameOverDelay(dirBase.getFile("gameOverDelay")),
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

44)   m_fileStartSound(dirBase.getFile("startSound")),
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

45)   m_fileRowCompleteSound(dirBase.getFile("rowCompleteSound")),
46)   m_fileGameOverSound(dirBase.getFile("gameOverSound")),
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

47)   m_stoneColor(),
48)   m_delay(c_delayDescr.default_),
Stefan Schuermans tetris: dropping stones

Stefan Schuermans authored 5 years ago

49)   m_dropDelay(c_dropDelayDescr.default_),
Stefan Schuermans tetris: add blink delay

Stefan Schuermans authored 5 years ago

50)   m_blinkDelay(c_blinkDelayDescr.default_),
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

51)   m_gameOverDelay(c_gameOverDelayDescr.default_),
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

52)   m_pConn(NULL),
Stefan Schuermans tetris: add blink delay

Stefan Schuermans authored 5 years ago

53)   m_stone(-1), m_rot(-1), m_posX(-1), m_posY(-1),
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

54)   m_dropping(false), m_blinking(0), m_completed(0), m_gameOver(0),
Stefan Schuermans tetris: add blink delay

Stefan Schuermans authored 5 years ago

55)   m_field(), m_rowsBlink()
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

56) {
57)   // open operator connection interfaces for player
58)   m_mgrs.m_opMgr.open(m_name, this);
59) }
60) 
61) /// virtual destructor
62) Tetris::~Tetris()
63) {
64)   // close operator connection interface
65)   m_mgrs.m_opMgr.close(m_name);
66) 
67)   // close open operator connection
68)   if (m_pConn) {
69)     m_pConn->close();
70)     m_pConn = NULL;
71)   }
72) }
73) 
74) /// check for update of configuration (derived game), return true on update
75) bool Tetris::updateConfigGame()
76) {
77)   bool ret = false;
78) 
79)   // color file was modified -> convert color, return true for update
80)   // cfg value file was updated -> read new cfg value, return true for update
Stefan Schuermans tetris: always check all co...

Stefan Schuermans authored 5 years ago

81)   if (colorUpdate(m_fileStoneColor, m_stoneColor)) {
82)     ret = true;
83)   }
84)   if (valueUpdate(m_fileDelay, c_delayDescr, m_delay)) {
85)     ret = true;
86)   }
87)   if (valueUpdate(m_fileDropDelay, c_dropDelayDescr, m_dropDelay)) {
88)     ret = true;
89)   }
90)   if (valueUpdate(m_fileBlinkDelay, c_blinkDelayDescr, m_blinkDelay)) {
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

91)     ret = true;
92)   }
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

93)   if (valueUpdate(m_fileGameOverDelay, c_gameOverDelayDescr,
94)                   m_gameOverDelay)) {
95)     ret = true;
96)   }
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

97) 
98)   // sound name file was modified -> re-read sound name, no other update needed
99)   soundUpdate(m_fileStartSound);
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

100)   soundUpdate(m_fileRowCompleteSound);
101)   soundUpdate(m_fileGameOverSound);
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

102) 
103)   return ret;
104) }
105) 
106) /**
107)  * @brief check if accepting new operator connection is possible
108)  * @param[in] name operator interface name
109)  * @return if accepting new connection is possible
110)  */
111) bool Tetris::acceptNewOpConn(const std::string &name)
112) {
113)   (void)name;
114) 
115)   // accept player if no one there yet
116)   return ! m_pConn;
117) }
118) 
119) /**
120)  * @brief new operator connection
121)  * @param[in] name operator interface name
122)  * @param[in] pConn operator connection object
123)  *
124)  * The new connection may not yet be used for sending inside this callback.
125)  */
126) void Tetris::newOpConn(const std::string &name, OpConn *pConn)
127) {
128)   (void)name;
129) 
130)   // player arrives and starts game
131)   if (! m_pConn) {
132)     m_pConn = pConn;
133)     requestOpConnSound(m_pConn, m_fileStartSound);
134)     activate();
135)   }
136)   // close imcoming connection as soon as possible, nothing else happens
137)   else {
138)     requestOpConnClose(pConn);
139)     return;
140)   }
141) }
142) 
143) /**
144)  * @brief key command received on operator connection
145)  * @param[in] pConn operator connection object
146)  * @param[in] key key that was pressed
147)  */
148) void Tetris::opConnRecvKey(OpConn *pConn, char key)
149) {
150)   // hash -> hang up
151)   if (key == '#') {
152)     opConnClose(pConn);
153)     pConn->close();
154)     return;
155)   }
156) 
157)   // star -> inform player about game
158)   if (key == '*') {
159)     playOpConnSound(pConn, m_fileStartSound);
160)     return;
161)   }
162) 
Stefan Schuermans tetris: dropping stones

Stefan Schuermans authored 5 years ago

163)   /** normal keys for controlling game,
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

164)       deactivated if dropping stone, rows blinking or end of game */
165)   if (m_dropping || m_blinking > 0 || m_gameOver > 0) {
Stefan Schuermans tetris: dropping stones

Stefan Schuermans authored 5 years ago

166)     return;
167)   }
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

168) 
Stefan Schuermans tetris WIP: move/freeze stones

Stefan Schuermans authored 5 years ago

169)   // move left
170)   if (key == '4') {
171)     if (checkStoneFit(m_stone, m_rot, m_posY, m_posX - 1)) {
172)       wipeStone(m_stone, m_rot, m_posY, m_posX);
173)       m_posX -= 1;
174)       drawStone(m_stone, m_rot, m_posY, m_posX); // TODO: active color
Stefan Schuermans tetris: output frame on sto...

Stefan Schuermans authored 5 years ago

175)       sendFrame();
Stefan Schuermans tetris WIP: move/freeze stones

Stefan Schuermans authored 5 years ago

176)     }
177)     return;
178)   }
179) 
180)   // move right
181)   if (key == '6') {
182)     if (checkStoneFit(m_stone, m_rot, m_posY, m_posX + 1)) {
183)       wipeStone(m_stone, m_rot, m_posY, m_posX);
184)       m_posX += 1;
185)       drawStone(m_stone, m_rot, m_posY, m_posX); // TODO: active color
Stefan Schuermans tetris: output frame on sto...

Stefan Schuermans authored 5 years ago

186)       sendFrame();
Stefan Schuermans tetris WIP: move/freeze stones

Stefan Schuermans authored 5 years ago

187)     }
188)     return;
189)   }
190) 
191)   // rotate left
192)   if (key == '1') {
193)     int new_rot = m_rot - 1;
194)     if (new_rot < 0) {
195)       new_rot = c_rotCnt - 1;
196)     }
197)     if (checkStoneFit(m_stone, new_rot, m_posY, m_posX)) {
198)       wipeStone(m_stone, m_rot, m_posY, m_posX);
199)       m_rot = new_rot;
200)       drawStone(m_stone, m_rot, m_posY, m_posX); // TODO: active color
Stefan Schuermans tetris: output frame on sto...

Stefan Schuermans authored 5 years ago

201)       sendFrame();
Stefan Schuermans tetris WIP: move/freeze stones

Stefan Schuermans authored 5 years ago

202)     }
203)     return;
204)   }
205) 
206)   // rotate right
207)   if (key == '2' || key == '3') {
208)     int new_rot = m_rot + 1;
209)     if (new_rot >= c_rotCnt) {
210)       new_rot = 0;
211)     }
212)     if (checkStoneFit(m_stone, new_rot, m_posY, m_posX)) {
213)       wipeStone(m_stone, m_rot, m_posY, m_posX);
214)       m_rot = new_rot;
215)       drawStone(m_stone, m_rot, m_posY, m_posX); // TODO: active color
Stefan Schuermans tetris: output frame on sto...

Stefan Schuermans authored 5 years ago

216)       sendFrame();
Stefan Schuermans tetris WIP: move/freeze stones

Stefan Schuermans authored 5 years ago

217)     }
218)     return;
219)   }
220) 
221)   // drop stone
222)   if (key == '8') {
Stefan Schuermans tetris: dropping stones

Stefan Schuermans authored 5 years ago

223)     m_dropping = true;
224)     planTimeStep(); // stone falls fater now -> update time callback
Stefan Schuermans tetris WIP: move/freeze stones

Stefan Schuermans authored 5 years ago

225)     return;
226)   }
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

227) }
228) 
229) /**
230)  * @brief play command received on operator connection
231)  * @param[in] pConn operator connection object
232)  * @param[in] sound name of sound to play
233)  */
234) void Tetris::opConnRecvPlay(OpConn *pConn, const std::string &sound)
235) {
236)   (void)pConn;
237)   (void)sound;
238) }
239) 
240) /**
241)  * @brief operator connection is closed
242)  * @param[in] pConn operator connection object
243)  *
244)  * The connection may not be used for sending any more in this callback.
245)  */
246) void Tetris::opConnClose(OpConn *pConn)
247) {
248)   // remove coperator connection from requests (if it was in)
249)   forgetOpConn(pConn);
250) 
251)   // player leaves -> deactivate game
252)   if (pConn == m_pConn) {
253)     m_pConn = NULL;
254)     deactivate();
255)   }
256) }
257) 
258) /// re-initialize game (e.g. due to config change)
259) void Tetris::reinitialize()
260) {
261)   // convert colors
262)   color2data(m_fileStoneColor, m_stoneColor);
263)   // get values
264)   valueFromFile(m_fileDelay, c_delayDescr, m_delay);
Stefan Schuermans tetris: remove completed rows

Stefan Schuermans authored 5 years ago

265)   valueFromFile(m_fileDropDelay, c_dropDelayDescr, m_dropDelay);
266)   valueFromFile(m_fileBlinkDelay, c_blinkDelayDescr, m_blinkDelay);
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

267)   valueFromFile(m_fileGameOverDelay, c_gameOverDelayDescr, m_gameOverDelay);
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

268) 
269)   // initialize field: empty
270)   m_field.clear();
271)   m_field.resize(m_height * m_width, -1);
272) 
Stefan Schuermans tetris: remove completed rows

Stefan Schuermans authored 5 years ago

273)   // initialize blinking rows: no row blinking
274)   m_rowsBlink.clear();
275)   m_rowsBlink.resize(m_height, false);
276) 
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

277)   // no rows blinking or completed, game not over yet
278)   m_blinking = 0;
279)   m_completed = 0;
280)   m_gameOver = 0;
281) 
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

282)   // start with new stone
283)   newStone();
284) 
285)   // redraw image and send frame
286)   redraw();
287) 
288)   // request first time step if needed
289)   planTimeStep();
290) }
291) 
292) /// redraw current game image, expected to call sendFrame() at end
293) void Tetris::redraw()
294) {
295)   // draw background
296)   rectFill(0, m_height, 0, m_width, m_backgroundColor);
297) 
Stefan Schuermans tetris: remove completed rows

Stefan Schuermans authored 5 years ago

298)   // draw fixed pixels, respect blinking rows
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

299)   for (int y = 0, i = 0; y < m_height; ++y) {
Stefan Schuermans tetris: remove completed rows

Stefan Schuermans authored 5 years ago

300)     if (! (m_blinking & 1) || ! m_rowsBlink.at(y)) {
301)       for (int x = 0; x < m_width; ++x, ++i) {
302)         if (m_field.at(i) >= 0) {
303)           pixel(y, x, m_stoneColor);
304)         }
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

305)       }
306)     }
307)   }
308) 
309)   // draw current stone
310)   drawStone(m_stone, m_rot, m_posY, m_posX);
311) 
312)   // send updated image buffer as frame
313)   sendFrame();
314) }
315) 
316) /// process next time step of game
317) void Tetris::timeStep()
318) {
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

319)   // count time at end of game
320)   if (m_gameOver > 0) {
321)     timeGameOver();
Stefan Schuermans tetris: remove completed rows

Stefan Schuermans authored 5 years ago

322)   // blinking of completed rows
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

323)   } else if (m_blinking > 0) {
324)     timeBlinkRows();
325)   // falling stone
326)   } else {
327)     timeStone();
328)   }
329) 
330)   // request next time step
331)   planTimeStep();
332) }
333) 
334) /// count time at end of game
335) void Tetris::timeGameOver()
336) {
337)   // count time
338)   ++m_gameOver;
339) 
340)   // terminate game after some time
341)   if (m_gameOver >= 8) {
342)     // close operator connection
343)     if (m_pConn) {
344)       forgetOpConn(m_pConn); // remove from requests (if it was in)
345)       m_pConn->close();
346)       m_pConn = NULL;
347)     }
348)     // deactivate game
349)     deactivate();
350)   }
351) }
352) 
353) /// blink completed rows
354) void Tetris::timeBlinkRows()
355) {
356)   // blink rows
357)   ++m_blinking;
358) 
359)   // end of blinking -> remove blinking rows, new stone
360)   if (m_blinking >= 8) {
361)     // remove blinking rows
362)     for (int b = 0; b < m_height; ++b) {
363)       if (m_rowsBlink.at(b)) {
364)         // move rows 0..b-1 one row down, i.e., to rows 1..b
365)         for (int y = b, i = b * m_width + m_width - 1; y > 0; --y) {
366)           for (int x = m_width - 1; x >= 0; --x, --i) {
367)             m_field.at(i) = m_field.at(i - m_width);
Stefan Schuermans tetris: remove completed rows

Stefan Schuermans authored 5 years ago

368)           }
369)         }
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

370)         // clear first row
371)         for (int x = 0; x < m_width; ++x) {
372)           m_field.at(x) = -1;
373)         }
374)         // row not blinking any more
375)         m_rowsBlink.at(b) = false;
Stefan Schuermans tetris: remove completed rows

Stefan Schuermans authored 5 years ago

376)       }
377)     }
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

378)     // blinking done
379)     m_blinking = 0;
380)     // new stone
381)     newStone();
382)   }
Stefan Schuermans tetris WIP: move/freeze stones

Stefan Schuermans authored 5 years ago

383) 
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

384)   // redraw image and send frame
385)   redraw();
386) }
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

387) 
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

388) /// falling stone
389) void Tetris::timeStone()
390) {
391)   // stone can move down by one pixel
392)   if (checkStoneFit(m_stone, m_rot, m_posY + 1, m_posX)) {
393)     // move stone down by one pixel
394)     wipeStone(m_stone, m_rot, m_posY, m_posX);
395)     m_posY += 1;
396)     drawStone(m_stone, m_rot, m_posY, m_posX); // TODO: active color
397)   }
Stefan Schuermans tetris: remove completed rows

Stefan Schuermans authored 5 years ago

398) 
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

399)   // stone cannot move down by one pixel
400)   else {
401)     // add stone permanently to field at current position
402)     freezeStone(m_stone, m_rot, m_posY, m_posX);
403)     drawStone(m_stone, m_rot, m_posY, m_posX); // TODO: frozen color
404) 
405)     // overflow of game field -> game over
406)     if (checkStoneOverflow(m_stone, m_rot, m_posY, m_posX)) {
407)       // unset stone
408)       m_stone = -1;
409)       // game over
410)       m_gameOver = 1;
411)       playOpConnSound(m_pConn, m_fileGameOverSound);
Stefan Schuermans tetris: remove completed rows

Stefan Schuermans authored 5 years ago

412)     }
413) 
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

414)     // no overflow
Stefan Schuermans tetris: remove completed rows

Stefan Schuermans authored 5 years ago

415)     else {
416)       // no current stone any more
417)       m_stone = -1;
418)       // check for completed rows, (afterwards: new stone)
419)       checkComplete();
420)     }
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

421)   }
Stefan Schuermans tetris: remove completed rows

Stefan Schuermans authored 5 years ago

422) 
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

423)   // send updated image buffer as frame
424)   sendFrame();
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

425) }
426) 
Stefan Schuermans tetris: remove completed rows

Stefan Schuermans authored 5 years ago

427) /// check for completed rows to disappear (new stone afterwards)
428) void Tetris::checkComplete()
429) {
430)   // collect y coordinated of completed rows -> m_rowsBlink
431)   bool blink = false;
432)   for (int y = 0, i = 0; y < m_height; ++y) {
433)     bool complete = true;
434)     for (int x = 0; x < m_width; ++x, ++i) {
435)       if (m_field.at(i) < 0) {
436)         complete = false;
437)       }
438)     }
439)     m_rowsBlink.at(y) = complete;
440)     if (complete) {
441)       blink = true;
442)     }
443)   }
444) 
445)   // no completed rows -> new stone
446)   if (! blink) {
447)     newStone();
448)   }
449) 
450)   // start blinking (start with rows visible, last bit == 0)
451)   else {
452)     m_blinking = 2;
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

453)     playOpConnSound(m_pConn, m_fileRowCompleteSound);
Stefan Schuermans tetris: remove completed rows

Stefan Schuermans authored 5 years ago

454)   }
455) }
456) 
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

457) /// set up a new stone
458) void Tetris::newStone()
459) {
460)   // random stone, random rotation
461)   m_stone = rand() % c_stoneCnt;
462)   m_rot = rand() % c_rotCnt;
463) 
464)   // postion: two pixels above top middle
465)   m_posX = (m_width - 1) / 2;
466)   m_posY = -2;
Stefan Schuermans tetris: dropping stones

Stefan Schuermans authored 5 years ago

467) 
468)   // stone is not being dropped yet
469)   m_dropping = false;
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

470) }
471) 
472) /// set time for next time step of game - or unset if not needed
473) void Tetris::planTimeStep()
474) {
475)   // no time call needed if not active
476)   if (! isActive()) {
477)     unsetTimeStep();
478)     return;
479)   }
480) 
Stefan Schuermans tetris: dropping stones

Stefan Schuermans authored 5 years ago

481)   // compute interval based on game state
Stefan Schuermans tetris: add blink delay

Stefan Schuermans authored 5 years ago

482)   int interval_ms = m_delay;
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

483)   int speedup = m_completed;
484)   if (m_gameOver > 0) {
485)     interval_ms = m_gameOverDelay;
486)     speedup = 0;
Stefan Schuermans tetris: add blink delay

Stefan Schuermans authored 5 years ago

487)   } else if (m_blinking > 0) {
488)     interval_ms = m_blinkDelay;
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

489)   } else if (m_dropping) {
490)     interval_ms = m_dropDelay;
Stefan Schuermans tetris: add blink delay

Stefan Schuermans authored 5 years ago

491)   }
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

492)   float scale = 0.3f + 0.7f * expf(-0.3f * speedup);
493)   float interval = 1e-3f * interval_ms * scale;
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

494) 
495)   // request next time call
496)   Time stepTime;
497)   stepTime.fromFloatSec(interval);
498)   setTimeStep(Time::now() + stepTime);
499) }
500) 
Stefan Schuermans tetris WIP: move/freeze stones

Stefan Schuermans authored 5 years ago

501) /// get rotatation of stone from stone/rotation index (or NULL in invalid)
502) Tetris::RotStone const * Tetris::getRotStone(int stone, int rot)
503) {
504)   if (! checkLimitInt(stone, 0, c_stoneCnt -1) ||
505)       ! checkLimitInt(rot, 0, c_rotCnt - 1)) {
506)     return NULL; // invalid stone or rotation
507)   }
508)   return &c_stones[stone].rot[rot];
509) }
510) 
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

511) /// check if stone fits at position
512) bool Tetris::checkStoneFit(int stone, int rot, int y, int x) const
513) {
514)   // get rotation of stone
Stefan Schuermans tetris WIP: move/freeze stones

Stefan Schuermans authored 5 years ago

515)   RotStone const *rotStone = getRotStone(stone, rot);
516)   if (! rotStone) {
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

517)     return false; // invalid stone or rotation -> does not fit
518)   }
519) 
520)   // check pixels
521)   for (int p = 0; p < c_pixelCnt; ++p) {
Stefan Schuermans tetris WIP: move/freeze stones

Stefan Schuermans authored 5 years ago

522)     int py = y + rotStone->pixels[p].y;
523)     int px = x + rotStone->pixels[p].x;
524)     if (py > m_height - 1 || ! checkLimitInt(px, 0, m_width - 1)) {
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

525)       return false; // outside field (except at top) -> does not fit
526)     }
Stefan Schuermans tetris WIP: move/freeze stones

Stefan Schuermans authored 5 years ago

527)     if (py >= 0) { // do not check above top
528)       int pi = py * m_width + px;
529)       if (m_field.at(pi) >= 0) {
530)         return false; // occupixed pixel -> does not fit
531)       }
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

532)     }
533)   }
534) 
535)   // all checks passed -> stone fits
536)   return true;
537) }
538) 
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

539) /// check if stone overflow game field
540) bool Tetris::checkStoneOverflow(int stone, int rot, int y, int x) const
541) {
542)   // get rotation of stone
543)   RotStone const *rotStone = getRotStone(stone, rot);
544)   if (! rotStone) {
545)     return true; // invalid stone or rotation -> overflow
546)   }
547) 
548)   // check pixels for overflow
549)   for (int p = 0; p < c_pixelCnt; ++p) {
550)     int py = y + rotStone->pixels[p].y;
551)     int px = x + rotStone->pixels[p].x;
552)     if (! checkLimitInt(py, 0, m_height -1) ||
553)         ! checkLimitInt(px, 0, m_width - 1)) {
554)       return true; // outside field (including top) -> overflow
555)     }
556)   }
557) 
558)   // all checks passed -> no overflow
559)   return false;
560) }
561) 
Stefan Schuermans tetris WIP: move/freeze stones

Stefan Schuermans authored 5 years ago

562) /// freeze stone to field at position
563) void Tetris::freezeStone(int stone, int rot, int y, int x)
564) {
565)   // get rotation of stone
566)   RotStone const *rotStone = getRotStone(stone, rot);
567)   if (! rotStone) {
568)     return; // invalid stone or rotation -> nothing to do
569)   }
570) 
571)   // add pixels to field
572)   for (int p = 0; p < c_pixelCnt; ++p) {
573)     int py = y + rotStone->pixels[p].y;
574)     int px = x + rotStone->pixels[p].x;
575)     if (checkLimitInt(py, 0, m_height - 1) &&
576)         checkLimitInt(px, 0, m_width - 1)) {
577)       int pi = py * m_width + px;
578)       m_field.at(pi) = stone; // mark pixel in field with stone index
579)     }
580)   }
581) }
582) 
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

583) /// draw a stone to image buffer
584) void Tetris::drawStone(int stone, int rot, int y, int x)
585) {
586)   colorStone(stone, rot, y, x, m_stoneColor);
587) }
588) 
589) /// wipe a stone from image buffer (i.e. replace it with background color)
590) void Tetris::wipeStone(int stone, int rot, int y, int x)
591) {
592)   colorStone(stone, rot, y, x, m_backgroundColor);
593) }
594) 
595) /// set shape of stone to color in image buffer
596) void Tetris::colorStone(int stone, int rot, int y, int x,
597)                         ColorData const &color)
598) {
599)   // get rotation of stone
Stefan Schuermans tetris WIP: move/freeze stones

Stefan Schuermans authored 5 years ago

600)   RotStone const *rotStone = getRotStone(stone, rot);
601)   if (! rotStone) {
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

602)     return; // invalid stone or rotation -> nothing to do
603)   }
604) 
605)   // color pixels
606)   for (int p = 0; p < c_pixelCnt; ++p) {
Stefan Schuermans tetris WIP: move/freeze stones

Stefan Schuermans authored 5 years ago

607)     pixel(y + rotStone->pixels[p].y, x + rotStone->pixels[p].x, color);
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

608)   }
609) }
610) 
611) /// stone data
612) Tetris::Stone const Tetris::c_stones[7] = {
613)   // the I
614)   { {
615)       { { { -2,  0 }, { -1,  0 }, {  0,  0 }, {  1,  0 } } },
616)       { { {  0, -2 }, {  0, -1 }, {  0,  0 }, {  0,  1 } } },
617)       { { { -2,  0 }, { -1,  0 }, {  0,  0 }, {  1,  0 } } },
618)       { { {  0, -2 }, {  0, -1 }, {  0,  0 }, {  0,  1 } } },
619)   } },
620)   // the L
621)   { {
622)       { { {  1, -1 }, { -1,  0 }, {  0,  0 }, {  1,  0 } } },
623)       { { {  0, -1 }, {  0,  0 }, {  0,  1 }, {  1,  1 } } },
624)       { { { -1,  0 }, {  0,  0 }, {  1,  0 }, { -1,  1 } } },
625)       { { { -1, -1 }, {  0, -1 }, {  0,  0 }, {  0,  1 } } },
626)   } },
627)   // the J
628)   { {
629)       { { { -1, -1 }, { -1,  0 }, {  0,  0 }, {  1,  0 } } },
630)       { { {  0, -1 }, {  1, -1 }, {  0,  0 }, {  0,  1 } } },
631)       { { { -1,  0 }, {  0,  0 }, {  1,  0 }, {  1,  1 } } },
632)       { { {  0, -1 }, {  0,  0 }, { -1,  1 }, {  0,  1 } } },
633)   } },
634)   // the T
635)   { {
636)       { { {  0, -1 }, { -1,  0 }, {  0,  0 }, {  1,  0 } } },
637)       { { {  0, -1 }, {  0,  0 }, {  1,  0 }, {  0,  1 } } },
638)       { { { -1,  0 }, {  0,  0 }, {  1,  0 }, {  0,  1 } } },
639)       { { {  0, -1 }, { -1,  0 }, {  0,  0 }, {  0,  1 } } },
640)   } },
641)   // the O
642)   { {
643)       { { {  0, -1 }, {  1, -1 }, {  0,  0 }, {  1,  0 } } },
644)       { { {  0, -1 }, {  1, -1 }, {  0,  0 }, {  1,  0 } } },
645)       { { {  0, -1 }, {  1, -1 }, {  0,  0 }, {  1,  0 } } },
646)       { { {  0, -1 }, {  1, -1 }, {  0,  0 }, {  1,  0 } } },
647)   } },
648)   // the Z
649)   { {
650)       { { { -1, -1 }, {  0, -1 }, {  0,  0 }, {  1,  0 } } },
651)       { { {  0, -1 }, { -1,  0 }, {  0,  0 }, { -1,  1 } } },
652)       { { { -1, -1 }, {  0, -1 }, {  0,  0 }, {  1,  0 } } },
653)       { { {  0, -1 }, { -1,  0 }, {  0,  0 }, { -1,  1 } } },
654)   } },
655)   // the S
656)   { {
657)       { { {  0, -1 }, {  1, -1 }, { -1,  0 }, {  0,  0 } } },
658)       { { { -1, -1 }, { -1,  0 }, {  0,  0 }, {  0,  1 } } },
659)       { { {  0, -1 }, {  1, -1 }, { -1,  0 }, {  0,  0 } } },
660)       { { { -1, -1 }, { -1,  0 }, {  0,  0 }, {  0,  1 } } },
661)   } },
662) };
663) 
664) /// number of stones
665) int const Tetris::c_stoneCnt = sizeof(Tetris::c_stones) /
666)                                sizeof(Tetris::c_stones[0]);
667) /// number of rotations per stone
668) int const Tetris::c_rotCnt = sizeof(Tetris::Stone::rot) /
669)                              sizeof(Tetris::Stone::rot[0]);
670) /// number of pixels per stone
671) int const Tetris::c_pixelCnt = sizeof(Tetris::RotStone::pixels) /
672)                                sizeof(Tetris::RotStone::pixels[0]);
673) 
674) /// descriptor for delay value
Stefan Schuermans tetris WIP: move/freeze stones

Stefan Schuermans authored 5 years ago

675) Tetris::ValueDescr const Tetris::c_delayDescr = { 400, 200, 1000 };
Stefan Schuermans tetris game WIP

Stefan Schuermans authored 5 years ago

676) 
Stefan Schuermans tetris: dropping stones

Stefan Schuermans authored 5 years ago

677) /// descriptor for delay value during dropping a stone
678) Tetris::ValueDescr const Tetris::c_dropDelayDescr = { 100, 50, 250 };
679) 
Stefan Schuermans tetris: add blink delay

Stefan Schuermans authored 5 years ago

680) /// descriptor for delay value during blinking of disappearing rows
681) Tetris::ValueDescr const Tetris::c_blinkDelayDescr = { 50, 50, 250 };
682) 
Stefan Schuermans tetris: complete game logic

Stefan Schuermans authored 5 years ago

683) /// descriptor for delay value at end of game
684) Tetris::ValueDescr const Tetris::c_gameOverDelayDescr = { 2000, 100, 5000 };
685)