1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "groovie/cell.h"
24 
25 namespace Groovie {
26 
CellGame()27 CellGame::CellGame() {
28 	_startX = _startY = _endX = _endY = 255;
29 
30 	_stack_index = _boardStackPtr = 0;
31 	_flag4 = false;
32 	_flag2 = false;
33 	_flag1 = false;
34 	_coeff3 = 0;
35 
36 	_moveCount = 0;
37 }
38 
getStartX()39 byte CellGame::getStartX() {
40 	if (_startX > BOARDSIZE) {
41 		warning ("CellGame::getStartX: not calculated yet (%d)!", _startX);
42 		return 0;
43 	} else {
44 		return _startX;
45 	}
46 }
47 
getStartY()48 byte CellGame::getStartY() {
49 	if (_startY > BOARDSIZE) {
50 		warning ("CellGame::getStartY: not calculated yet (%d)!", _startY);
51 		return 6;
52 	} else {
53 		return _startY;
54 	}
55 }
56 
getEndX()57 byte CellGame::getEndX() {
58 	if (_endX > BOARDSIZE) {
59 		warning ("CellGame::getEndX: not calculated yet (%d)!", _endX);
60 		return 1;
61 	} else {
62 		return _endX;
63 	}
64 }
65 
getEndY()66 byte CellGame::getEndY() {
67 	if (_endY > BOARDSIZE) {
68 		warning ("CellGame::getEndY: not calculated yet (%d)!", _endY);
69 		return 6;
70 	} else {
71 		return _endY;
72 	}
73 }
74 
~CellGame()75 CellGame::~CellGame() {
76 }
77 
78 const int8 possibleMoves[][9] = {
79 	{ 1, 7, 8, -1 },
80 	{ 0, 2, 7, 8, 9, -1 },
81 	{ 1, 3, 8, 9, 10, -1 },
82 	{ 2, 4, 9, 10, 11, -1 },
83 	{ 3, 5, 10, 11, 12, -1 },
84 	{ 4, 6, 11, 12, 13, -1 }, // 5
85 	{ 5, 12, 13, -1 },
86 	{ 0, 1, 8, 14, 15, -1 },
87 	{ 0, 1, 2, 7, 9, 14, 15, 16, -1 },
88 	{ 1, 2, 3, 8, 10, 15, 16, 17, -1 },
89 	{ 2, 3, 4, 9, 11, 16, 17, 18, -1 }, // 10
90 	{ 3, 4, 5, 10, 12, 17, 18, 19, -1 },
91 	{ 4, 5, 6, 11, 13, 18, 19, 20, -1 },
92 	{ 5, 6, 12, 19, 20, -1 },
93 	{ 7, 8, 15, 21, 22, -1 },
94 	{ 7, 8, 9, 14, 16, 21, 22, 23, -1 }, // 15
95 	{ 8, 9, 10, 15, 17, 22, 23, 24, -1 },
96 	{ 9, 10, 11, 16, 18, 23, 24, 25, -1 },
97 	{ 10, 11, 12, 17, 19, 24, 25, 26, -1 },
98 	{ 11, 12, 13, 18, 20, 25, 26, 27, -1 },
99 	{ 12, 13, 19, 26, 27, -1 }, // 20
100 	{ 14, 15, 22, 28, 29, -1 },
101 	{ 14, 15, 16, 21, 23, 28, 29, 30, -1 },
102 	{ 15, 16, 17, 22, 24, 29, 30, 31, -1 },
103 	{ 16, 17, 18, 23, 25, 30, 31, 32, -1 },
104 	{ 17, 18, 19, 24, 26, 31, 32, 33, -1 }, // 25
105 	{ 18, 19, 20, 25, 27, 32, 33, 34, -1 },
106 	{ 19, 20, 26, 33, 34, -1 },
107 	{ 21, 22, 29, 35, 36, -1 },
108 	{ 21, 22, 23, 28, 30, 35, 36, 37, -1 },
109 	{ 22, 23, 24, 29, 31, 36, 37, 38, -1 }, // 30
110 	{ 23, 24, 25, 30, 32, 37, 38, 39, -1 },
111 	{ 24, 25, 26, 31, 33, 38, 39, 40, -1 },
112 	{ 25, 26, 27, 32, 34, 39, 40, 41, -1 },
113 	{ 26, 27, 33, 40, 41, -1 },
114 	{ 28, 29, 36, 42, 43, -1 }, // 35
115 	{ 28, 29, 30, 35, 37, 42, 43, 44, -1 },
116 	{ 29, 30, 31, 36, 38, 43, 44, 45, -1 },
117 	{ 30, 31, 32, 37, 39, 44, 45, 46, -1 },
118 	{ 31, 32, 33, 38, 40, 45, 46, 47, -1 },
119 	{ 32, 33, 34, 39, 41, 46, 47, 48, -1 }, // 40
120 	{ 33, 34, 40, 47, 48, -1 },
121 	{ 35, 36, 43, -1 },
122 	{ 35, 36, 37, 42, 44, -1 },
123 	{ 36, 37, 38, 43, 45, -1 },
124 	{ 37, 38, 39, 44, 46, -1 }, // 45
125 	{ 38, 39, 40, 45, 47, -1 },
126 	{ 39, 40, 41, 46, 48, -1 },
127 	{ 40, 41, 47, -1 }
128 };
129 
130 
131 const int8 strategy2[][17] = {
132 	{ 2, 9, 14, 15, 16, -1 },
133 	{ 3, 10, 14, 15, 16, 17, -1 },
134 	{ 0, 4, 7, 11, 14, 15, 16, 17, 18, -1 },
135 	{ 1, 5, 8, 12, 15, 16, 17, 18, 19, -1 },
136 	{ 2, 6, 9, 13, 16, 17, 18, 19, 20, -1 },
137 	{ 3, 10, 17, 18, 19, 20, -1 }, // 5
138 	{ 4, 11, 18, 19, 20, -1 },
139 	{ 2, 9, 16, 21, 22, 23, -1 },
140 	{ 3, 10, 17, 21, 22, 23, 24, -1 },
141 	{ 0, 4, 7, 11, 14, 18, 21, 22, 23, 24, 25, -1 },
142 	{ 1, 5, 8, 12, 15, 19, 22, 23, 24, 25, 26, -1 }, // 10
143 	{ 2, 6, 9, 13, 16, 20, 23, 24, 25, 26, 27, -1 },
144 	{ 3, 10, 17, 24, 25, 26, 27, -1 },
145 	{ 4, 11, 18, 25, 26, 27, -1 },
146 	{ 0, 1, 2, 9, 16, 23, 28, 29, 30, -1 },
147 	{ 0, 1, 2, 3, 10, 17, 24, 28, 29, 30, 31, -1 }, // 15
148 	{ 0, 1, 2, 3, 4, 7, 11, 14, 18, 21, 25, 28, 29, 30, 31, 32, -1 },
149 	{ 1, 2, 3, 4, 5, 8, 12, 15, 19, 22, 26, 29, 30, 31, 32, 33, -1 },
150 	{ 2, 3, 4, 5, 6, 9, 13, 16, 20, 23, 27, 30, 31, 32, 33, 34, -1 },
151 	{ 3, 4, 5, 6, 10, 17, 24, 31, 32, 33, 34, -1 },
152 	{ 4, 5, 6, 11, 18, 25, 32, 33, 34, -1 }, // 20
153 	{ 7, 8, 9, 16, 23, 30, 35, 36, 37, -1 },
154 	{ 7, 8, 9, 10, 17, 24, 31, 35, 36, 37, 38, -1 },
155 	{ 7, 8, 9, 10, 11, 14, 18, 21, 25, 28, 32, 35, 36, 37, 38, 39, -1 },
156 	{ 8, 9, 10, 11, 12, 15, 19, 22, 26, 29, 33, 36, 37, 38, 39, 40, -1 },
157 	{ 9, 10, 11, 12, 13, 16, 20, 23, 27, 30, 34, 37, 38, 39, 40, 41, -1 }, // 25
158 	{ 10, 11, 12, 13, 17, 24, 31, 38, 39, 40, 41, -1 },
159 	{ 11, 12, 13, 18, 25, 32, 39, 40, 41, -1 },
160 	{ 14, 15, 16, 23, 30, 37, 42, 43, 44, -1 },
161 	{ 14, 15, 16, 17, 24, 31, 38, 42, 43, 44, 45, -1 },
162 	{ 14, 15, 16, 17, 18, 21, 25, 28, 32, 35, 39, 42, 43, 44, 45, 46, -1 }, // 30
163 	{ 15, 16, 17, 18, 19, 22, 26, 29, 33, 36, 40, 43, 44, 45, 46, 47, -1 },
164 	{ 16, 17, 18, 19, 20, 23, 27, 30, 34, 37, 41, 44, 45, 46, 47, 48, -1 },
165 	{ 17, 18, 19, 20, 24, 31, 38, 45, 46, 47, 48, -1 },
166 	{ 18, 19, 20, 25, 32, 39, 46, 47, 48, -1 },
167 	{ 21, 22, 23, 30, 37, 44, -1 }, // 35
168 	{ 21, 22, 23, 24, 31, 38, 45, -1 },
169 	{ 21, 22, 23, 24, 25, 28, 32, 35, 39, 42, 46, -1 },
170 	{ 22, 23, 24, 25, 26, 29, 33, 36, 40, 43, 47, -1 },
171 	{ 23, 24, 25, 26, 27, 30, 34, 37, 41, 44, 48, -1 },
172 	{ 24, 25, 26, 27, 31, 38, 45, -1 }, // 40
173 	{ 25, 26, 27, 32, 39, 46, -1 },
174 	{ 28, 29, 30, 37, 44, -1 },
175 	{ 28, 29, 30, 31, 38, 45, -1 },
176 	{ 28, 29, 30, 31, 32, 35, 39, 42, 46, -1 },
177 	{ 29, 30, 31, 32, 33, 36, 40, 43, 47, -1 }, // 45
178 	{ 30, 31, 32, 33, 34, 37, 41, 44, 48, -1 },
179 	{ 31, 32, 33, 34, 38, 45, -1 },
180 	{ 32, 33, 34, 39, 46, -1 }
181 };
182 
copyToTempBoard()183 void CellGame::copyToTempBoard() {
184 	for (int i = 0; i < 53; ++i) {
185 		_tempBoard[i] = _board[i];
186 	}
187 }
188 
copyFromTempBoard()189 void CellGame::copyFromTempBoard() {
190 	for (int i = 0; i < 53; ++i) {
191 		_board[i] = _tempBoard[i];
192 	}
193 }
194 
copyToShadowBoard()195 void CellGame::copyToShadowBoard() {
196 	_board[53] = 0;
197 	_board[55] = 1;
198 	_board[56] = 0;
199 
200 	for (int i = 0; i < 49; ++i) {
201 		_shadowBoard[i] = _board[i];
202 	}
203 }
204 
pushBoard()205 void CellGame::pushBoard() {
206 	assert(_boardStackPtr < 57 * 9);
207 
208 	for (int i = 0; i < 57; ++i)
209 		_boardStack[_boardStackPtr + i] = _board[i];
210 	_boardStackPtr += 57;
211 }
212 
popBoard()213 void CellGame::popBoard() {
214 	assert(_boardStackPtr > 0);
215 
216 	_boardStackPtr -= 57;
217 	for (int i = 0; i < 57; ++i) {
218 		_board[i] = _boardStack[_boardStackPtr + i];
219 	}
220 }
221 
pushShadowBoard()222 void CellGame::pushShadowBoard() {
223 	assert(_boardStackPtr < 57 * 9);
224 
225 	for (int i = 0; i < 57; ++i)
226 		_boardStack[_boardStackPtr + i] = _shadowBoard[i];
227 
228 	_boardStackPtr += 57;
229 }
230 
popShadowBoard()231 void CellGame::popShadowBoard() {
232 	assert(_boardStackPtr > 0);
233 
234 	_boardStackPtr -= 57;
235 
236 	for (int i = 0; i < 57; ++i) {
237 		_shadowBoard[i] = _boardStack[_boardStackPtr + i];
238 	}
239 }
240 
clearMoves()241 void CellGame::clearMoves() {
242 	_stack_startXY[0] = _board[53];
243 	_stack_endXY[0] = _board[54];
244 	_stack_pass[0] = _board[55];
245 
246 	_stack_index = 1;
247 }
248 
pushMove()249 void CellGame::pushMove() {
250 	_stack_startXY[_stack_index] = _board[53];
251 	_stack_endXY[_stack_index] = _board[54];
252 	_stack_pass[_stack_index] = _board[55];
253 
254 	_stack_index++;
255 }
256 
resetMove()257 void CellGame::resetMove() {
258 	_board[53] = 0;
259 	_board[54] = 0;
260 	_board[55] = 0;
261 }
262 
takeCells(uint16 whereTo,int8 color)263 void CellGame::takeCells(uint16 whereTo, int8 color) {
264 	int cellN;
265 	const int8 *str;
266 
267 	str = possibleMoves[whereTo];
268 	while (1) {
269 		cellN = *str++;
270 		if (cellN < 0)
271 			break;
272 		if (_tempBoard[cellN] > 0) {
273 			--_tempBoard[_tempBoard[cellN] + 48];
274 			_tempBoard[cellN] = color;
275 			++_tempBoard[color + 48];
276 		}
277 	}
278 }
279 
countAllCells()280 void CellGame::countAllCells() {
281 	_board[49] = 0;
282 	_board[50] = 0;
283 	_board[51] = 0;
284 	_board[52] = 0;
285 
286 	for (int i = 0; i < 49; i++) {
287 		switch (_board[i]) {
288 		case 1:	// CELL_BLUE
289 			_board[49]++;
290 			break;
291 		case 2:	// CELL_GREEN
292 			_board[50]++;
293 			break;
294 		case 3:
295 			_board[51]++;
296 			break;
297 		case 4:
298 			_board[52]++;
299 			break;
300 		default:
301 			break;
302 		}
303 	}
304 }
305 
countCellsOnTempBoard(int8 color)306 int CellGame::countCellsOnTempBoard(int8 color) {
307 	const int8 *str;
308 	int res = 0;
309 	int i;
310 
311 	for (i = 0; i < 49; i++)
312 		_boardSum[i] = 0;
313 
314 	for (i = 0; i < 49; i++) {
315 		if (_tempBoard[i] == color) {
316 			for (str = possibleMoves[i]; *str > 0; str++) {
317 				if (!_tempBoard[*str])
318 					++_boardSum[*str];
319 			}
320 		}
321 	}
322 
323 	for (i = 0; i < 49; i++)
324 		res += _boardSum[i];
325 
326 	return res;
327 }
328 
canMoveFunc1(int8 color)329 bool CellGame::canMoveFunc1(int8 color) {
330 	const int8 *str;
331 
332 	if (_board[55] == 1) {
333 		for (; _board[53] < 49; _board[53]++) {
334 			if (_shadowBoard[_board[53]] == color) {
335 				str = &possibleMoves[_board[53]][_board[56]];
336 				for (;_board[56] < 8; _board[56]++) {
337 					_board[54] = *str++;
338 					if (_board[54] < 0)
339 						break;
340 					if (!_shadowBoard[_board[54]]) {
341 						_shadowBoard[_board[54]] = -1;
342 						++_board[56];
343 						return true;
344 					}
345 				}
346 				_board[56] = 0;
347 			}
348 		}
349 		_board[53] = 0;
350 		_board[55] = 2;
351 		_board[56] = 0;
352 	}
353 	if (_board[55] == 2) {
354 		for (; _board[53] < 49; _board[53]++) {
355 			if (_shadowBoard[_board[53]] == color) {
356 				str = &strategy2[_board[53]][_board[56]];
357 				for (;_board[56] < 16; _board[56]++) {
358 					_board[54] = *str++;
359 					if (_board[54] < 0)
360 						break;
361 					if (!_board[_board[54]]) {
362 						++_board[56];
363 						return true;
364 					}
365 				}
366 				_board[56] = 0;
367 			}
368 		}
369 	}
370 
371 	return false;
372 }
373 
canMoveFunc3(int8 color)374 bool CellGame::canMoveFunc3(int8 color) {
375 	const int8 *str;
376 
377 	if (_board[55] == 1) {
378 		for (; _board[53] < 49; _board[53]++) {
379 			if (_shadowBoard[_board[53]] == color) {
380 				str = &possibleMoves[_board[53]][_board[56]];
381 				for (;_board[56] < 8; _board[56]++) {
382 					_board[54] = *str++;
383 					if (_board[54] < 0)
384 						break;
385 					if (!_shadowBoard[_board[54]]) {
386 						_shadowBoard[_board[54]] = -1;
387 						++_board[56];
388 						return true;
389 					}
390 				}
391 				_board[56] = 0;
392 			}
393 		}
394 
395 		_board[53] = 0;
396 		_board[55] = 2;
397 		_board[56] = 0;
398 		for (int i = 0; i < 49; ++i)
399 			_shadowBoard[i] = _board[i];
400 	}
401 	if (_board[55] == 2) {
402 		for (; _board[53] < 49; _board[53]++) {
403 			if (_shadowBoard[_board[53]] == color) {
404 				str = &strategy2[_board[53]][_board[56]];
405 				for (;_board[56] < 16; _board[56]++) {
406 					_board[54] = *str++;
407 					if (_board[54] < 0)
408 						break;
409 					if (!_shadowBoard[_board[54]]) {
410 						_shadowBoard[_board[54]] = -1;
411 						++_board[56];
412 						return true;
413 					}
414 				}
415 				_board[56] = 0;
416 			}
417 		}
418 	}
419 
420 	return false;
421 }
422 
canMoveFunc2(int8 color)423 bool CellGame::canMoveFunc2(int8 color) {
424 	const int8 *str;
425 
426 	while (1) {
427 		while (_board[_board[54]]) {
428 			++_board[54];
429 			if (_board[54] >= 49)
430 				return false;
431 		}
432 		if (!_board[55]) {
433 			str = possibleMoves[_board[54]];
434 			while (1) {
435 				_board[53] = *str++;
436 				if (_board[53] < 0)
437 					break;
438 				if (_board[_board[53]] == color) {
439 					_board[55] = 1;
440 					return true;
441 				}
442 			}
443 			_board[55] = 1;
444 		}
445 		if (_board[55] == 1) {
446 			_board[55] = 2;
447 			_board[56] = 0;
448 		}
449 		if (_board[55] == 2) {
450 			str = &strategy2[_board[54]][_board[56]];
451 			for (; _board[56] < 16; _board[56]++) {
452 				_board[53] = *str++;
453 				if (_board[53] < 0)
454 					break;
455 				if (_board[_board[53]] == color) {
456 					++_board[56];
457 					return true;
458 				}
459 			}
460 			++_board[54];
461 			_board[55] = 0;
462 			if (_board[54] >= 49)
463 				break;
464 		}
465 	}
466 	return false;
467 }
468 
makeMove(int8 color)469 void CellGame::makeMove(int8 color) {
470 	copyToTempBoard();
471 	_tempBoard[_board[54]] = color;
472 	++_tempBoard[color + 48];
473 	if (_board[55] == 2) {
474 		_tempBoard[_board[53]] = 0;
475 		--_tempBoard[color + 48];
476 	}
477 	takeCells(_board[54], color);
478 }
479 
getBoardWeight(int8 color1,int8 color2)480 int CellGame::getBoardWeight(int8 color1, int8 color2) {
481 	int8 celln;
482 	const int8 *str;
483 	byte cellCnt[8];
484 
485 	str = possibleMoves[_board[54]];
486 	cellCnt[1] = _board[49];
487 	cellCnt[2] = _board[50];
488 	cellCnt[3] = _board[51];
489 	cellCnt[4] = _board[52];
490 	if (_board[55] != 2)
491 		++cellCnt[color2];
492 	celln = *str++;
493 
494 	celln = _board[celln];
495 	if (celln > 0) {
496 		--cellCnt[celln];
497 		++cellCnt[color2];
498 	}
499 	celln = *str++;
500 
501 	celln = _board[celln];
502 	if (celln > 0) {
503 		--cellCnt[celln];
504 		++cellCnt[color2];
505 	}
506 	celln = *str++;
507 
508 	celln = _board[celln];
509 	if (celln > 0) {
510 		--cellCnt[celln];
511 		++cellCnt[color2];
512 	}
513 	while (1) {
514 		celln = *str++;
515 		if (celln < 0)
516 			break;
517 		celln = _board[celln];
518 		if (celln > 0) {
519 			--cellCnt[celln];
520 			++cellCnt[color2];
521 		}
522 	}
523 	return _coeff3 + 2 * (2 * cellCnt[color1] - cellCnt[1] - cellCnt[2] - cellCnt[3] - cellCnt[4]);
524 }
525 
chooseBestMove(int8 color)526 void CellGame::chooseBestMove(int8 color) {
527 	int moveIndex = 0;
528 
529 	if (_flag2) {
530 		int bestWeight = 32767;
531 		for (int i = 0; i < _stack_index; ++i) {
532 			_board[53] = _stack_startXY[i];
533 			_board[54] = _stack_endXY[i];
534 			_board[55] = _stack_pass[i];
535 			makeMove(color);
536 			int curWeight = countCellsOnTempBoard(color);
537 			if (curWeight <= bestWeight) {
538 				if (curWeight < bestWeight)
539 					moveIndex = 0;
540 				bestWeight = curWeight;
541 				_stack_startXY[moveIndex] = _board[53];
542 				_stack_endXY[moveIndex] = _board[54];
543 				_stack_pass[moveIndex++] = _board[55];
544 			}
545 		}
546 		_stack_index = moveIndex;
547 	}
548 
549 	_startX = _stack_startXY[0] % 7;
550 	_startY = _stack_startXY[0] / 7;
551 	_endX = _stack_endXY[0] % 7;
552 	_endY = _stack_endXY[0] / 7;
553 }
554 
calcBestWeight(int8 color1,int8 color2,uint16 depth,int bestWeight)555 int8 CellGame::calcBestWeight(int8 color1, int8 color2, uint16 depth, int bestWeight) {
556 	int8 res;
557 	int8 curColor;
558 	bool canMove;
559 	int type;
560 	uint16 i;
561 	int8 currBoardWeight;
562 	int8 weight;
563 
564 	pushBoard();
565 	copyFromTempBoard();
566 	curColor = color2;
567 	for (i = 0;; ++i) {
568 		if (i >= 4) {
569 			res = _coeff3 + 2 * (2 * _board[color1 + 48] - _board[49] - _board[50] - _board[51] - _board[52]);
570 			popBoard();
571 			return res;
572 		}
573 		++curColor;
574 		if (curColor > 4)
575 			curColor = 1;
576 
577 		if (_board[curColor + 48]) {
578 			if (_board[curColor + 48] >= 49 - _board[49] - _board[50] - _board[51] - _board[52]) {
579 				resetMove();
580 				canMove = canMoveFunc2(curColor);
581 				type = 1;
582 			} else {
583 				copyToShadowBoard();
584 				if (depth == 1) {
585 					canMove = canMoveFunc3(curColor);
586 					type = 3;
587 				} else {
588 					canMove = canMoveFunc1(curColor);
589 					type = 2;
590 				}
591 			}
592 			if (canMove)
593 				break;
594 		}
595 	}
596 	if (_flag1) {
597 		popBoard();
598 		return bestWeight + 1;
599 	}
600 
601 	depth -= 1;
602 	if (depth) {
603 		makeMove(curColor);
604 		if (type == 1) {
605 			res = calcBestWeight(color1, curColor, depth, bestWeight);
606 		} else {
607 			pushShadowBoard();
608 			res = calcBestWeight(color1, curColor, depth, bestWeight);
609 			popShadowBoard();
610 		}
611 	} else {
612 		res = getBoardWeight(color1, curColor);
613 	}
614 
615 	if ((res < bestWeight && color1 != curColor) || _flag4) {
616 		popBoard();
617 		return res;
618 	}
619 
620 	currBoardWeight = _coeff3 + 2 * (2 * _board[color1 + 48] - _board[49] - _board[50] - _board[51] - _board[52]);
621 	while (1) {
622 		if (type == 1) {
623 			canMove = canMoveFunc2(curColor);
624 		} else if (type == 2) {
625 			canMove = canMoveFunc1(curColor);
626 		} else {
627 			canMove = canMoveFunc3(curColor);
628 		}
629 
630 		if (!canMove)
631 			break;
632 		if (_flag1) {
633 			popBoard();
634 			return bestWeight + 1;
635 		}
636 		if (_board[55] == 2) {
637 			if (getBoardWeight(color1, curColor) == currBoardWeight)
638 				continue;
639 		}
640 		if (!depth) {
641 			weight = getBoardWeight(color1, curColor);
642 			if (type == 1) {
643 				if (_board[55] == 2)
644 					_board[56] = 16;
645 			}
646 		} else {
647 			makeMove(curColor);
648 			if (type != 1) {
649 				pushShadowBoard();
650 				weight = calcBestWeight(color1, curColor, depth, bestWeight);
651 				popShadowBoard();
652 			} else {
653 				weight = calcBestWeight(color1, curColor, depth, bestWeight);
654 			}
655 		}
656 		if ((weight < res && color1 != curColor) || (weight > res && color1 == curColor))
657 			res = weight;
658 
659 		if ((res < bestWeight && color1 != curColor) || _flag4)
660 			break;
661 	}
662 	popBoard();
663 
664 	return res;
665 }
666 
doGame(int8 color,int depth)667 int16 CellGame::doGame(int8 color, int depth) {
668 	bool canMove;
669 	int type;
670 
671 	countAllCells();
672 	if (_board[color + 48] >= 49 - _board[49] - _board[50] - _board[51] - _board[52]) {
673 		resetMove();
674 		canMove = canMoveFunc2(color);
675 		type = true;
676 	} else {
677 		copyToShadowBoard();
678 		canMove = canMoveFunc1(color);
679 		type = false;
680 	}
681 
682 	if (canMove) {
683 		int8 w1, w2;
684 		if (_board[color + 48] - _board[49] - _board[50] - _board[51] - _board[52] == 0)
685 			depth = 0;
686 		_coeff3 = 0;
687 		if (_board[55] == 1)
688 			_coeff3 = 1;
689 		clearMoves();
690 		if (depth) {
691 			makeMove(color);
692 			_flag4 = false;
693 			if (type) {
694 				w2 = calcBestWeight(color, color, depth, -127);
695 			} else {
696 				pushShadowBoard();
697 				w2 = calcBestWeight(color, color, depth, -127);
698 				popShadowBoard();
699 			}
700 		} else {
701 			w2 = getBoardWeight(color, color);
702 		}
703 		int8 currBoardWeight = 2 * (2 * _board[color + 48] - _board[49] - _board[50] - _board[51] - _board[52]);
704 		while (1) {
705 			if (type)
706 				canMove = canMoveFunc2(color);
707 			else
708 				canMove = canMoveFunc1(color);
709 
710 			if (!canMove)
711 				break;
712 			if (_flag1)
713 				break;
714 			_coeff3 = 0;
715 			if (_board[55] == 2) {
716 				if (getBoardWeight(color, color) == currBoardWeight)
717 					continue;
718 			}
719 			if (_board[55] == 1)
720 				_coeff3 = 1;
721 			if (depth) {
722 				makeMove(color);
723 				_flag4 = false;
724 				if (type) {
725 					w1 = calcBestWeight(color, color, depth, w2);
726 				} else {
727 					pushShadowBoard();
728 					w1 = calcBestWeight(color, color, depth, w2);
729 					popShadowBoard();
730 				}
731 			} else {
732 				w1 = getBoardWeight(color, color);
733 			}
734 			if (w1 == w2)
735 				pushMove();
736 
737 			if (w1 > w2) {
738 				clearMoves();
739 				w2 = w1;
740 			}
741 		}
742 		chooseBestMove(color);
743 		return 1;
744 	}
745 
746 	return 0;
747 }
748 
749 const int8 depths[] = { 1, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 3, 2, 2, 3, 3, 2, 3, 3, 3 };
750 
calcMove(int8 color,uint16 depth)751 int16 CellGame::calcMove(int8 color, uint16 depth) {
752 	int result = 0;
753 
754 	_flag1 = false;
755 	++_moveCount;
756 	if (depth) {
757 		if (depth == 1) {
758 			_flag2 = true;
759 			result = doGame(color, 0);
760 		} else {
761 			int newDepth;
762 
763 			newDepth = depths[3 * (depth - 2) + _moveCount % 3];
764 			_flag2 = true;
765 			if (newDepth >= 20) {
766 				assert(0); // This branch is not implemented
767 			} else {
768 				result = doGame(color, newDepth);
769 			}
770 		}
771 	} else {
772 		_flag2 = false;
773 		result = doGame(color, depth);
774 	}
775 	return result;
776 }
777 
playStauf(byte color,uint16 depth,byte * scriptBoard)778 int CellGame::playStauf(byte color, uint16 depth, byte *scriptBoard) {
779 	int i;
780 
781 	for (i = 0; i < 49; i++, scriptBoard++) {
782 		_board[i] = 0;
783 		if (*scriptBoard == 50)
784 			_board[i] = 1;
785 		if (*scriptBoard == 66)
786 			_board[i] = 2;
787 	}
788 	for (i = 49; i < 57; i++)
789 		_board[i] = 0;
790 
791 	return calcMove(color, depth);
792 }
793 
794 
795 } // End of Groovie namespace
796