1     #include <assert.h>
2     #include <stdlib.h>
3     #include <SDL.h>
4     #include "cube.h"
5     #include "font.h"
6     #include "soundDev.h"
7     #include "view.h"
8     #include "bombView.h"
9     #include "bomb.h"
BombSquad(Cube * _cube,unsigned int _dims,unsigned int _skillLevel,bool _wrap,BombSquadView * _view)10         NKlein_54321::BombSquad::BombSquad(
11                 Cube* _cube,
12                 unsigned int _dims,
13                 unsigned int _skillLevel,
14                 bool _wrap,
15                 BombSquadView* _view
16             ) : cube( _cube ),
17                 dims( _dims ),
18                 skillLevel( _skillLevel ),
19                 wrap( _wrap ),
20                 view( _view )
21         {
22             assert( cube != 0 );
23             assert( dims > 1 );
24             assert( dims <= NKlein_54321::Cube::DIMENSIONS );
25             assert( NKlein_54321::Cube::DIMENSIONS <= 4 );
26             assert( skillLevel < 3 );
27             this->reset();
28         }
29         void
reset(void)30         NKlein_54321::BombSquad::reset( void )
31         {
32             *this->cube = 0;
33 
34                 unsigned int table[ Cube::DIMENSIONS+1 ][ 3 ] = {
35                     {   0,   0,   0 },
36                     {   1,   2,   3 },
37                     {   2,   4,   8 },
38                     {   4,   8,  16 },
39                     {  16,  32,  64 },
40                 };
41             unsigned int bombs = table[ this->dims ][ this->skillLevel ];
42             unsigned int len
43                 = NKlein_54321::Cube::arrayLengths[ this->dims ];
44 
45                 unsigned int* lut = new unsigned int[ bombs ];
46                 unsigned int lutLen = 0;
47 
48                 for ( unsigned int ii=0; ii < bombs; ++ii ) {
49                         unsigned int index = random() % len--;
50                         for ( unsigned int jj=0; jj < lutLen; ++jj ) {
51                             if ( index >= lut[ jj ] ) {
52                                 ++index;
53                             }
54                         }
55 
56                         (*this->cube)[ index ] |= BOMB;
57                             unsigned int nn[ 2 * NKlein_54321::Cube::DIMENSIONS ];
58                             unsigned int nc;
59 
60                             nc = NKlein_54321::Cube::getNeighbors(
61                                     nn, index, this->dims, this->wrap
62                                 );
63                             for ( unsigned int jj=0; jj < nc; ++jj ) {
64                                 ++(*this->cube)[ nn[ jj ] ];
65                             }
66 
67                             unsigned int spot = lutLen;
68                             while ( spot > 0 && lut[ spot-1 ] > index ) {
69                                 lut[ spot ] = lut[ spot-1 ];
70                                 --spot;
71                             }
72                             lut[ spot ] = index;
73                             ++lutLen;
74                 }
75 
76                 delete[] lut;
77                 this->bombCount = bombs;
78                 this->flagCount = 0;
79                 this->coveredCount
80                     = NKlein_54321::Cube::arrayLengths[ this->dims ];
81                 this->gameOver = false;
82 
83             if ( this->view != 0 ) {
84                 this->view->reset();
85                 this->view->redraw();
86             }
87         }
88         void
uncover(unsigned int index,bool click)89         NKlein_54321::BombSquad::uncover(
90                 unsigned int index, bool click
91             )
92         {
93             unsigned int cell = (*this->cube)[ index ];
94             if ( ( cell & ( UNCOVERED | FLAG ) ) == 0 ) {
95                     --this->coveredCount;
96                     if ( click && this->view != 0 ) {
97                         this->view->moveNoise();
98                     }
99                     (*this->cube)[ index ] |= UNCOVERED;
100                     if ( this->view != 0 ) {
101                         this->view->redraw( index );
102                     }
103 
104                 if ( ( cell & BOMB ) != 0 ) {
105                         if ( ! this->gameOver ) {
106                             this->gameOver = true;
107                             if ( this->view != 0 ) {
108                                 this->view->showLosing();
109                             }
110                         }
111                 } else if ( ( cell & 0x0FFF ) == 0 ) {
112                         unsigned int nn[ 2 * NKlein_54321::Cube::DIMENSIONS ];
113                         unsigned int nc = this->cube->getNeighbors(
114                                 nn, index, this->dims, this->wrap
115                             );
116 
117                         for ( unsigned int ii=0; ii < nc; ++ii ) {
118                             this->uncover( nn[ ii ], false );
119                         }
120                 }
121 
122                 if ( click ) {
123                     this->checkWinningCondition();
124                 }
125             }
126         }
127         void
toggleFlag(unsigned int index)128         NKlein_54321::BombSquad::toggleFlag(
129                 unsigned int index
130             )
131         {
132             if ( ( (*this->cube)[ index ] & UNCOVERED ) == 0 ) {
133                 (*this->cube)[ index ] ^= FLAG;
134 
135                     if ( ( (*this->cube)[ index ] & FLAG ) == 0 ) {
136                         --this->flagCount;
137                     } else {
138                         ++this->flagCount;
139                     }
140 
141                 if ( this->view != 0 ) {
142                     this->view->moveNoise();
143                     this->view->redraw( index );
144                 }
145 
146                 this->checkWinningCondition();
147             }
148         }
149         void
checkWinningCondition(void)150         NKlein_54321::BombSquad::checkWinningCondition( void ) {
151             if ( ! this->gameOver
152             && this->flagCount == this->bombCount
153             && this->coveredCount == this->bombCount ) {
154                 this->gameOver = true;
155                 if ( this->view != 0 ) {
156                     this->view->showWinning(
157                             this->flagCount, this->bombCount
158                         );
159                 }
160             }
161         };
162