summaryrefslogtreecommitdiff
path: root/noncore/games/zsame/StoneField.cpp
Unidiff
Diffstat (limited to 'noncore/games/zsame/StoneField.cpp') (more/less context) (show whitespace changes)
-rw-r--r--noncore/games/zsame/StoneField.cpp390
1 files changed, 390 insertions, 0 deletions
diff --git a/noncore/games/zsame/StoneField.cpp b/noncore/games/zsame/StoneField.cpp
new file mode 100644
index 0000000..49d8eca
--- a/dev/null
+++ b/noncore/games/zsame/StoneField.cpp
@@ -0,0 +1,390 @@
1/*
2 * ksame 0.4 - simple Game
3 * Copyright (C) 1997,1998 Marcus Kreutzberger
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 */
20
21#include "StoneField.h"
22#include <assert.h>
23
24StoneFieldState::StoneFieldState(const StoneField &stonefield)
25{
26 field=new unsigned char[stonefield.maxstone];
27 for (int i=0;i<stonefield.maxstone;i++)
28 field[i]=stonefield.field[i].color;
29
30 colors=stonefield.colors;
31 board=stonefield.board;
32 score=stonefield.score;
33 gameover=stonefield.gameover;
34}
35
36StoneFieldState::~StoneFieldState() {
37 delete[] field;
38}
39
40void
41StoneFieldState::restore(StoneField &stonefield) const {
42 for (int i=0;i<stonefield.maxstone;i++) {
43 stonefield.field[i].color=field[i];
44 stonefield.field[i].changed=true;
45 stonefield.field[i].marked=false;
46 }
47
48 stonefield.colors=colors;
49 stonefield.board=board;
50 stonefield.score=score;
51 stonefield.marked=0;
52 stonefield.gameover=gameover;
53}
54
55StoneField::StoneField(int width, int height,
56 int colors, unsigned int board,
57 bool undoenabled)
58{
59// Q_ASSERT(width>0);
60// Q_ASSERT(height>0);
61
62 if (undoenabled) undolist=new QList<StoneFieldState>;
63 else undolist=0;
64
65 sizex=width;
66 sizey=height;
67 maxstone=sizex*sizey;
68 field=new Stone[maxstone];
69 newGame(board,colors);
70 m_gotBonus= false;
71}
72
73StoneField::~StoneField() {
74 delete[] field;
75 delete undolist;
76// kdDebug() << "~StoneField\n" << endl;
77}
78
79int
80StoneField::width() const {
81 return sizex;
82}
83
84int
85StoneField::height() const {
86 return sizey;
87}
88
89void
90StoneField::newGame(unsigned int board,int colors) {
91// kdDebug() << "StoneField::newgame board "
92// << board << " colors " << colors << endl;
93 if (colors<1) colors=3;
94 if (colors>7) colors=7;
95 this->colors=colors;
96 this->board=board;
97 reset();
98}
99
100void
101StoneField::reset() {
102 random.setSeed(board);
103
104 Stone *stone=field;
105 for (int i=0;i<maxstone;i++,stone++) {
106 stone->color=1+random.getLong(colors);
107 stone->marked=false;
108 stone->changed=true;
109 }
110
111 gameover=-1;
112 score=0;
113 marked=0;
114
115 if (undolist) {
116 undolist->setAutoDelete(true);
117 undolist->clear();
118 }
119
120
121 int c[7];
122 int j;
123 for (j=0;j<7;j++) c[j]=0;
124
125 for (j=0,stone=field;j<maxstone;j++,stone++) {
126 c[stone->color]++;
127 }
128// kdDebug() << "red " << c[1] << endl;
129// kdDebug() << "blue " << c[2] << endl;
130// kdDebug() << "yellow " << c[3] << endl;
131// kdDebug() << "green " << c[4] << endl;
132
133}
134
135int
136StoneField::map(int x,int y) {
137 assert (!(x<0||y<0||x>=sizex||y>=sizey));
138 return x+y*sizex;
139}
140
141int
142StoneField::mark(int x,int y,bool force) {
143 int index=map(x,y);
144
145 if (index<0) {
146 unmark();
147 return 0;
148 }
149
150 if (field[index].marked) return -1;
151 unmark();
152
153 mark(index,field[index].color);
154
155 if (marked==1&&!force) {
156 field[index].marked=false;
157 marked=0;
158 }
159 return marked;
160}
161
162void
163StoneField::mark(int index,unsigned char color) {
164 if ( index<0 || index>=maxstone ) return;
165
166 Stone &stone=field[index];
167
168 if (stone.marked) return;
169
170 if (!stone.color || stone.color!=color) return;
171
172 stone.changed=true;
173 stone.marked=true;
174 marked++;
175
176 // mark left
177 if ((index%sizex)!=0) mark(index-1,color);
178 // mark right
179 if (((index+1)%sizex)!=0) mark(index+1,color);
180 // mark upward
181 if (index>=sizex) mark(index-sizex,color);
182 // mark downward
183 if (index<(sizex-1)*sizey) mark(index+sizex,color);
184}
185
186void
187StoneField::unmark() {
188 if (!marked) return;
189
190 Stone *stone=field;
191 for (int i=0;i<maxstone;i++,stone++) {
192 stone->marked=false;
193 stone->changed=true;
194 }
195 marked=0;
196}
197
198int
199StoneField::remove(int x,int y,bool force) {
200 int index=map(x,y);
201
202 if (index<0) return 0;
203
204 if (!field[index].marked) {
205 mark(x,y,force);
206 }
207
208 if (!marked) return 0;
209
210 // remove a single stone??
211 if (marked==1&&!force) return 0;
212
213 // add current field to undolist
214 if (undolist)
215 undolist->append(new StoneFieldState(*this));
216
217 // increase score
218 if (marked>2)
219 score+=(marked-2)*(marked-2);
220
221 // remove marked stones
222 Stone *stone=field;
223 for (int i=0;i<maxstone;i++,stone++) {
224 if (stone->marked) {
225 stone->color=0;
226 stone->changed=true;
227 stone->marked=false;
228 }
229 }
230 int removed=marked;
231 marked=0;
232
233 for (int col=0;col<sizex;col++) {
234 int i1=col+maxstone-sizex;
235 while ( i1>=0 && field[i1].color ) i1-=sizex;
236 int i2=i1;
237 while (i2>=0) {
238 while ( i2>=0 && !field[i2].color ) i2-=sizex;
239 while ( i2>=0 && field[i2].color ) {
240 field[i1].color=field[i2].color;
241 field[i1].changed=true;
242 field[i2].color=0;
243 field[i2].changed=true;
244 i1-=sizex;
245 i2-=sizex;
246 }
247 }
248 }
249
250 // find the last column that has something
251 int lastcol = sizex;
252 while (lastcol > 0 && !field[map(lastcol-1, sizey-1)].color) {
253 lastcol--;
254 }
255
256 for (int col=0;col<lastcol-1;) {
257 bool empty = true;
258 for (int row = 0; row < sizey; row++)
259 if (field[map(col, row)].color) {
260 empty = false;
261 break;
262 }
263 if (!empty) {
264 col++;
265 continue;
266 }
267 int nextfullcol = col + 1;
268 while (nextfullcol < sizex &&
269 !field[map(nextfullcol, sizey - 1)].color)
270 nextfullcol++;
271
272 if (nextfullcol > sizex - 1)
273 break; // we're ready
274
275 for (int row=0; row < sizey; row++) {
276 int source = map(nextfullcol, row);
277 int dest = map(col, row);
278 field[dest].color=field[source].color;
279 field[dest].changed=true;
280 field[source].color=0;
281 field[source].changed=true;
282 }
283 }
284
285 // add a bonus, if field is empty
286 if (!field[map(0, sizey-1)].color) {
287 score+=1000;
288 m_gotBonus= true;
289 }
290
291 // gameover is undefined
292 gameover=-1;
293 return removed;
294}
295
296bool StoneField::undoPossible() const {
297 return !(!undolist||undolist->isEmpty());
298}
299
300int
301StoneField::undo(int count) {
302 if (!undoPossible())
303 return 0;
304 if (count <= 0)
305 return 0;
306 int undocount=1;
307 StoneFieldState *state=0;
308 undolist->setAutoDelete(true);
309 while (--count>0) {
310 if (undolist->count()==1) break;
311 undolist->removeLast();
312 undocount++;
313 }
314 state=undolist->getLast();
315// Q_ASSERT(state);
316 state->restore(*this);
317 undolist->removeLast();
318 return undocount;
319}
320
321bool
322StoneField::isGameover() const {
323 register int i=maxstone-1;;
324 register unsigned char color;
325
326 if (gameover>=0) return (bool)gameover;
327 // kdDebug() << "-->gameover" << endl;
328
329 while (i>=0) {
330 // kdDebug() << i << " " << field[i].color << endl;
331 // ignore empty fields
332 while ( i>=0 && field[i].color==0 ) i--;
333 // Wenn Stein gefunden,
334 // dann die Nachbarn auf gleiche Farbe pruefen.
335 while ( i>=0 && (color=field[i].color) ) {
336 // check left
337 if ( (i%sizex)!=0 && field[i-1].color==color)
338 goto check_gameover;
339 // check upward
340 if ( i>=sizex && field[i-sizex].color==color)
341 goto check_gameover;
342 i--;
343 }
344 }
345 check_gameover:
346 gameover=(i<0);
347 // kdDebug() << "<--gameover" << endl;
348 return (bool)gameover;
349}
350
351bool StoneField::gotBonus() const {
352 return m_gotBonus;
353}
354
355int
356StoneField::getBoard() const {
357 return board;
358}
359
360int
361StoneField::getScore() const {
362 return score;
363}
364
365int
366StoneField::getColors() const {
367 return colors;
368}
369
370int
371StoneField::getMarked() const {
372 return marked;
373}
374
375int
376StoneField::getFieldSize() const {
377 return maxstone;
378}
379
380struct Stone *
381StoneField::getField() const {
382 return field;
383}
384
385
386
387
388
389
390