Initial commit
This commit is contained in:
987
engines/groovie/logic/triangle.cpp
Normal file
987
engines/groovie/logic/triangle.cpp
Normal file
@@ -0,0 +1,987 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, MojoTouch has exclusively licensed
|
||||
* this code on November 10th, 2021, to be use in closed-source products.
|
||||
* Therefore, any contributions (commits) to it will also be dual-licensed.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "groovie/groovie.h"
|
||||
#include "groovie/logic/triangle.h"
|
||||
|
||||
namespace Groovie {
|
||||
|
||||
namespace {
|
||||
extern const int8 triangleLookup1[12];
|
||||
extern const int8 triangleLookup2[12];
|
||||
extern const int8 triangleLookup3[12];
|
||||
extern const int8 triangleLogicTable[924];
|
||||
}
|
||||
|
||||
TriangleGame::TriangleGame() : _random("TriangleGame") {
|
||||
init();
|
||||
#if 0
|
||||
test();
|
||||
#endif
|
||||
}
|
||||
|
||||
void TriangleGame::run(byte *scriptVariables) {
|
||||
byte op = scriptVariables[3];
|
||||
uint8 move;
|
||||
|
||||
switch (op) {
|
||||
case 3:
|
||||
init();
|
||||
scriptVariables[3] = 0;
|
||||
return;
|
||||
|
||||
case 4:
|
||||
// Samantha AI
|
||||
move = sub03(2);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
// Stauf AI (only called after Samantha)
|
||||
move = sub03(1);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Player and then Stauf
|
||||
debugC(kDebugLogic, "player chose spot %d", (int)(scriptVariables[1]) + (10 * (int)scriptVariables[0]));
|
||||
setCell(scriptVariables[1] + 10 * scriptVariables[0], 2);
|
||||
scriptVariables[3] = sub02();
|
||||
|
||||
if (scriptVariables[3] == 0) {
|
||||
move = sub03(1);
|
||||
} else {
|
||||
debugC(kDebugLogic, "winner: %d", (int)scriptVariables[3]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
scriptVariables[0] = move / 10;
|
||||
scriptVariables[1] = move % 10;
|
||||
scriptVariables[3] = sub02();
|
||||
debugC(kDebugLogic, "stauf chose spot %d, winner: %d", (int)move, (int)scriptVariables[3]);
|
||||
}
|
||||
|
||||
void TriangleGame::init() {
|
||||
debugC(kDebugLogic, "TriangleGame::init(), seed: %u", _random.getSeed());
|
||||
_triangleCellCount = 0;
|
||||
memset(_triangleCells, 0, 66);
|
||||
}
|
||||
|
||||
int8 TriangleGame::sub02() {
|
||||
int8 v6[132];
|
||||
int8 v7[68];
|
||||
|
||||
sub05(_triangleCells, v6, v7);
|
||||
|
||||
for (int i = 0; v6[i] != 66; i++) {
|
||||
bool v1 = false;
|
||||
bool v2 = false;
|
||||
bool pl = false;
|
||||
|
||||
// There could be several sections, each one
|
||||
// ends with 66. And the overall list ends with 66 too
|
||||
// Hence, two loops
|
||||
for (; v6[i] != 66; i++) {
|
||||
if (!triangleLogicTable[14 * v6[i] + 6])
|
||||
pl = true;
|
||||
if (!triangleLogicTable[14 * v6[i] + 7])
|
||||
v2 = true;
|
||||
if (!triangleLogicTable[14 * v6[i] + 8])
|
||||
v1 = true;
|
||||
}
|
||||
|
||||
if (pl && v2 && v1)
|
||||
return _triangleCells[v6[i - 1]];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8 TriangleGame::sub03(int8 player) {
|
||||
int8 pickedMoves[4];
|
||||
int8 tempTriangle1[68];
|
||||
int8 tempTriangle2[68];
|
||||
int8 a6a[132];
|
||||
int8 tempTriangle3[68];
|
||||
int8 tempMoves[132];
|
||||
int8 pos;
|
||||
|
||||
if (_triangleCellCount >= 2) {
|
||||
sub05(_triangleCells, tempMoves, tempTriangle3);
|
||||
sub07(tempMoves, _triangleCells, tempTriangle3, tempTriangle2, tempTriangle1, a6a);
|
||||
|
||||
// Find move until valid one
|
||||
(pos = sub09(player, tempTriangle2, tempTriangle1, a6a, _triangleCells)) != 66 ||
|
||||
(pos = sub10(player, tempTriangle1, _triangleCells)) != 66 ||
|
||||
(pos = sub12(player, a6a, _triangleCells, tempTriangle1)) != 66 ||
|
||||
(pos = sub09(3 - player, tempTriangle2, tempTriangle1, a6a, _triangleCells));
|
||||
|
||||
if (pos == 66) {
|
||||
pos = _random.getRandomNumber(65);
|
||||
|
||||
int8 oldPos = pos;
|
||||
while (_triangleCells[pos]) {
|
||||
if (++pos > 65)
|
||||
pos = 0;
|
||||
if (oldPos == pos) {
|
||||
pos = 66;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int8 max = 0;
|
||||
if (!_triangleCells[24]) {
|
||||
pickedMoves[0] = 24;
|
||||
max = 1;
|
||||
}
|
||||
|
||||
if (!_triangleCells[31])
|
||||
pickedMoves[max++] = 31;
|
||||
if (!_triangleCells[32])
|
||||
pickedMoves[max++] = 32;
|
||||
if (max)
|
||||
pos = pickedMoves[_random.getRandomNumber(max - 1)];
|
||||
else {
|
||||
warning("TriangleGame: Undefined behaviour");
|
||||
pos = 0; // tempMoves is uninitalized in this branch, so just return 0
|
||||
}
|
||||
}
|
||||
|
||||
if (pos != 66)
|
||||
setCell(pos, player);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
void TriangleGame::sub05(int8 *triangleCells, int8 *tempMoves, int8 *tempTriangle) {
|
||||
int8 dest[8];
|
||||
|
||||
for (int i = 0; i < 66; i++)
|
||||
tempTriangle[i] = triangleCells[i];
|
||||
|
||||
int v16 = 3;
|
||||
|
||||
for (int j = 0; j < 66; ++j) {
|
||||
if (triangleCells[j]) {
|
||||
bool flag = false;
|
||||
|
||||
copyLogicRow(j, triangleCells[j], dest);
|
||||
for (int8 *k = dest; *k != 66; k++) {
|
||||
if (j > *k) {
|
||||
if (flag) {
|
||||
if (tempTriangle[j] != tempTriangle[*k])
|
||||
replaceCells(tempTriangle, j, tempTriangle[j], tempTriangle[*k]);
|
||||
} else {
|
||||
flag = true;
|
||||
tempTriangle[j] = tempTriangle[*k];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
tempTriangle[j] = v16++;
|
||||
}
|
||||
}
|
||||
|
||||
int v11 = 0;
|
||||
|
||||
if (v16 > 3) {
|
||||
for (int v12 = 3; v12 < v16; v12++) {
|
||||
int v14 = v11;
|
||||
|
||||
for (int m = 0; m < 66; m++) {
|
||||
if (tempTriangle[m] == v12)
|
||||
tempMoves[v11++] = m;
|
||||
}
|
||||
|
||||
if (v11 != v14)
|
||||
tempMoves[v11++] = 66;
|
||||
}
|
||||
}
|
||||
|
||||
tempMoves[v11] = 66;
|
||||
}
|
||||
|
||||
void TriangleGame::sub07(int8 *tempMoves, int8 *triangleCells, int8 *tempTriangle3, int8 *tempTriangle2, int8 *tempTriangle1, int8 *tempMoves2) {
|
||||
int8 singleRow[8];
|
||||
int8 tempTriangle[68];
|
||||
int8 routes[4356];
|
||||
|
||||
for (int i = 0; i < 66; i++) {
|
||||
tempTriangle2[i] = tempTriangle3[i];
|
||||
tempTriangle1[i] = 0;
|
||||
}
|
||||
|
||||
if (*tempMoves != 66) {
|
||||
for (int8 *ptr1 = tempMoves; *ptr1 != 66; ptr1++) {
|
||||
int8 *v45 = &routes[66 * tempTriangle3[*ptr1]];
|
||||
*v45 = 66;
|
||||
|
||||
while (*ptr1 != 66) {
|
||||
copyLogicRow(*ptr1++, 0, singleRow);
|
||||
collapseLoops(v45, singleRow);
|
||||
}
|
||||
}
|
||||
|
||||
for (int8 *ptr2 = tempMoves; *ptr2 != 66; ptr2++) {
|
||||
int8 *j;
|
||||
|
||||
for (j = ptr2; *j != 66; j++)
|
||||
;
|
||||
for (int8 *k = j + 1; *k != 66; k++) {
|
||||
if (triangleCells[*k] == triangleCells[*ptr2]) {
|
||||
int8 val1 = tempTriangle2[*k];
|
||||
int8 val2 = tempTriangle2[*ptr2];
|
||||
|
||||
if (val1 != val2) {
|
||||
int8 lookupLen = copyLookup(&routes[66 * val2], &routes[66 * val1], tempTriangle);
|
||||
if (lookupLen == 1) {
|
||||
if (triangleCells[*ptr2] == 1) {
|
||||
tempTriangle1[tempTriangle[0]] |= 1u;
|
||||
} else if (triangleCells[*ptr2] == 2) {
|
||||
tempTriangle1[tempTriangle[0]] |= 0x40u;
|
||||
}
|
||||
} else if (lookupLen > 1) {
|
||||
int8 v16 = lookupLen - 1;
|
||||
do {
|
||||
if (triangleCells[*ptr2] == 1) {
|
||||
tempTriangle1[tempTriangle[v16]] |= 0x10u;
|
||||
} else if (triangleCells[*ptr2] == 2) {
|
||||
tempTriangle1[tempTriangle[v16]] |= 0x20u;
|
||||
}
|
||||
} while (v16--);
|
||||
|
||||
collapseLoops(&routes[66 * tempTriangle2[*k]], &routes[66 * tempTriangle2[*ptr2]]);
|
||||
int8 from = tempTriangle2[*ptr2];
|
||||
int8 to = tempTriangle2[*k];
|
||||
for (int m = 0; m < 66; m++) {
|
||||
if (tempTriangle2[m] == from)
|
||||
tempTriangle2[m] = to;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; *k != 66; k++)
|
||||
;
|
||||
}
|
||||
for (; *ptr2 != 66; ptr2++)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
int8 maxVal = 0;
|
||||
for (int i = 0; i < 66; i++) {
|
||||
if (tempTriangle2[i] > maxVal)
|
||||
maxVal = tempTriangle2[i];
|
||||
}
|
||||
|
||||
int8 len2 = 0;
|
||||
|
||||
for (int i = 3; i <= maxVal; i++) {
|
||||
int8 prevLen2 = len2;
|
||||
for (int j = 0; j < 66; j++) {
|
||||
if (tempTriangle2[j] == i)
|
||||
tempMoves2[len2++] = j;
|
||||
}
|
||||
|
||||
if (prevLen2 != len2)
|
||||
tempMoves2[len2++] = 66;
|
||||
}
|
||||
|
||||
tempMoves2[len2] = 66;
|
||||
|
||||
for (int8 *ptr3 = tempMoves2; *ptr3 != 66; ptr3++) {
|
||||
bool flag1 = false, flag2 = false, flag3 = false;
|
||||
int8 row = tempTriangle2[*ptr3];
|
||||
byte mask1 = 0, mask2 = 0;
|
||||
|
||||
for (int i = 0; i < 66; i++) {
|
||||
if (tempTriangle2[i] == row && triangleCells[i]) {
|
||||
if (triangleCells[i] == 1) {
|
||||
mask1 = 1;
|
||||
mask2 = 16;
|
||||
} else {
|
||||
mask1 = 64;
|
||||
mask2 = 32;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (*ptr3 != 66) {
|
||||
if (!triangleLogicTable[14 * *ptr3 + 6])
|
||||
flag1 = 1;
|
||||
if (!triangleLogicTable[14 * *ptr3 + 7])
|
||||
flag2 = 1;
|
||||
if (!triangleLogicTable[14 * *ptr3 + 8])
|
||||
flag3 = 1;
|
||||
++ptr3;
|
||||
}
|
||||
|
||||
if (!flag1) {
|
||||
int8 lookup1 = copyLookup(triangleLookup1, &routes[66 * row], tempTriangle);
|
||||
if (lookup1 == 1) {
|
||||
tempTriangle1[tempTriangle[0]] |= mask1;
|
||||
} else if (lookup1 > 1) {
|
||||
int k = lookup1 - 1;
|
||||
do
|
||||
tempTriangle1[tempTriangle[k]] |= mask2;
|
||||
while (k--);
|
||||
flag1 = 1;
|
||||
}
|
||||
}
|
||||
if (!flag2) {
|
||||
int8 lookup2 = copyLookup(triangleLookup2, &routes[66 * row], tempTriangle);
|
||||
if (lookup2 == 1) {
|
||||
tempTriangle1[tempTriangle[0]] |= mask1;
|
||||
} else if (lookup2 > 1) {
|
||||
int k = lookup2 - 1;
|
||||
do
|
||||
tempTriangle1[tempTriangle[k]] |= mask2;
|
||||
while (k--);
|
||||
flag2 = 1;
|
||||
}
|
||||
}
|
||||
if (!flag3) {
|
||||
int8 lookup3 = copyLookup(triangleLookup3, &routes[66 * row], tempTriangle);
|
||||
if (lookup3 == 1) {
|
||||
tempTriangle1[tempTriangle[0]] |= mask1;
|
||||
} else if (lookup3 > 1) {
|
||||
int k = lookup3 - 1;
|
||||
do
|
||||
tempTriangle1[tempTriangle[k]] |= mask2;
|
||||
while (k--);
|
||||
flag3 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
byte mask3 = 0;
|
||||
|
||||
if (flag1)
|
||||
mask3 = 4;
|
||||
if (flag2)
|
||||
mask3 |= 8u;
|
||||
if (flag3)
|
||||
mask3 |= 2u;
|
||||
|
||||
for (int i = 0; i < 66; i++) {
|
||||
if (tempTriangle2[i] == row)
|
||||
tempTriangle1[i] |= mask3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int8 TriangleGame::sub09(int8 player, int8 *tempTriangle2, int8 *tempTriangle1, int8 *a4, int8 *triangleCells) {
|
||||
int8 movesTable[280];
|
||||
|
||||
int numDir1 = 0;
|
||||
int numDir2 = 0;
|
||||
int numDir3 = 0;
|
||||
int numDir4 = 0;
|
||||
int row = 0;
|
||||
|
||||
for (const int8 *tPtr = &triangleLogicTable[6]; tPtr < &triangleLogicTable[924]; tPtr += 14, row++) {
|
||||
if (!triangleCells[row] && (tempTriangle1[row] & (player == 1 ? 1 : 64)) != 0) {
|
||||
int c1 = 0, c2 = 0, c3 = 0;
|
||||
int mask = 0;
|
||||
|
||||
copyLogicRow(row, player, movesTable);
|
||||
|
||||
for (int8 *movPtr = movesTable; *movPtr != 66; ++movPtr) {
|
||||
int row2 = 0;
|
||||
|
||||
mask |= tempTriangle1[*movPtr];
|
||||
|
||||
for (const int8 *tPtr2 = &triangleLogicTable[6]; tPtr2 < &triangleLogicTable[924]; tPtr2 += 14, row2++) {
|
||||
if (tempTriangle2[row2] == tempTriangle2[*movPtr]) {
|
||||
c1 += (tPtr2[0] == 0) ? 1 : 0;
|
||||
c2 += (tPtr2[1] == 0) ? 1 : 0;
|
||||
c3 += (tPtr2[2] == 0) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (c1)
|
||||
mask &= ~4u;
|
||||
if (c2)
|
||||
mask &= ~8u;
|
||||
if (c3)
|
||||
mask &= ~2u;
|
||||
|
||||
if (tPtr[0] || c1) {
|
||||
if (tPtr[1] || c2) {
|
||||
if (tPtr[2] || c3) {
|
||||
if (mask) {
|
||||
if (mask == 0xe) {
|
||||
movesTable[numDir2 + 76] = row;
|
||||
numDir2++;
|
||||
} else if (mask == 2 || mask == 8 || mask == 4) {
|
||||
movesTable[numDir4 + 212] = row;
|
||||
numDir4++;
|
||||
} else {
|
||||
movesTable[numDir3 + 144] = row;
|
||||
numDir3++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
movesTable[numDir1 + 8] = row;
|
||||
numDir1++;
|
||||
}
|
||||
} else {
|
||||
movesTable[numDir1 + 8] = row;
|
||||
numDir1++;
|
||||
}
|
||||
} else {
|
||||
movesTable[numDir1 + 8] = row;
|
||||
numDir1++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numDir1)
|
||||
return movesTable[_random.getRandomNumber(numDir1 - 1) + 8];
|
||||
if (numDir2)
|
||||
return movesTable[_random.getRandomNumber(numDir2 - 1) + 76];
|
||||
if (numDir3)
|
||||
return movesTable[_random.getRandomNumber(numDir3 - 1) + 144];
|
||||
if (numDir4)
|
||||
return movesTable[_random.getRandomNumber(numDir4 - 1) + 212];
|
||||
|
||||
return 66;
|
||||
}
|
||||
|
||||
int8 TriangleGame::sub10(int8 player, int8 *a2, int8 *triangleCells) {
|
||||
int8 *destPtr;
|
||||
byte mask;
|
||||
int counter;
|
||||
int8 dest1[8];
|
||||
int8 dest2[68];
|
||||
|
||||
mask = 0;
|
||||
counter = 0;
|
||||
|
||||
if (player == 1)
|
||||
mask = 16;
|
||||
else if (player == 2)
|
||||
mask = 32;
|
||||
|
||||
for (int i = 0; i < 66; ++i) {
|
||||
if (!triangleCells[i] && (mask & (byte)a2[i]) != 0) {
|
||||
copyLogicRow(i, player, dest1);
|
||||
|
||||
destPtr = dest1;
|
||||
|
||||
while (*destPtr != 66) {
|
||||
if ((a2[*destPtr] & 0xE) == 0xE) {
|
||||
dest2[counter] = i;
|
||||
counter++;
|
||||
break;
|
||||
}
|
||||
|
||||
destPtr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (counter)
|
||||
return dest2[_random.getRandomNumber(counter - 1)];
|
||||
|
||||
return 66;
|
||||
}
|
||||
|
||||
int8 TriangleGame::sub12(int8 player, int8 *tempMoves, int8 *triangleCells, int8 *tempTriangle) {
|
||||
int8 moves[8];
|
||||
int8 tempTriangle1[68];
|
||||
int8 tempTriangle2[68];
|
||||
int8 tempTriangle3[68];
|
||||
int8 tempTriangle4[68];
|
||||
|
||||
int8 result = 66;
|
||||
int maxlen = -1;
|
||||
int8 *startPtr = triangleCells;
|
||||
|
||||
for (int8 *ptr = tempMoves; *ptr != 66; ptr++) {
|
||||
int len = 0;
|
||||
int8 *beg = ptr;
|
||||
int8 p0 = *ptr;
|
||||
|
||||
for (; *ptr != 66; ++ptr)
|
||||
++len;
|
||||
|
||||
if (len > maxlen && triangleCells[p0] == player) {
|
||||
maxlen = len;
|
||||
startPtr = beg;
|
||||
}
|
||||
}
|
||||
|
||||
tempTriangle4[0] = 66;
|
||||
|
||||
for (int8 *ptr = startPtr; *ptr != 66; ++ptr) {
|
||||
if (sub13(*ptr, triangleCells, moves))
|
||||
collapseLoops(tempTriangle4, moves);
|
||||
}
|
||||
|
||||
int len1 = 0, len2 = 0, len3 = 0;
|
||||
|
||||
tempTriangle1[0] = 66;
|
||||
tempTriangle2[0] = 66;
|
||||
tempTriangle3[0] = 66;
|
||||
|
||||
for (int8 *ptr = tempTriangle4; *ptr != 66; ++ptr) {
|
||||
int8 v13 = 100;
|
||||
|
||||
int8 v15 = triangleLogicTable[14 * *ptr + 11];
|
||||
if (v15 < 100)
|
||||
v13 = triangleLogicTable[14 * *ptr + 11];
|
||||
|
||||
int8 v16 = triangleLogicTable[14 * *ptr + 13];
|
||||
if (v13 > v16)
|
||||
v13 = triangleLogicTable[14 * *ptr + 13];
|
||||
|
||||
int8 v17 = triangleLogicTable[14 * *ptr + 12];
|
||||
if (v13 > v17)
|
||||
v13 = triangleLogicTable[14 * *ptr + 12];
|
||||
|
||||
if (v13 == v15) {
|
||||
tempTriangle1[len1++] = *ptr;
|
||||
} else if (v13 == v17) {
|
||||
tempTriangle2[len2++] = *ptr;
|
||||
} else if (v13 == v16) {
|
||||
tempTriangle3[len3++] = *ptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool flag1 = false, flag2 = false, flag3 = false;
|
||||
tempTriangle3[len3] = 66;
|
||||
tempTriangle2[len2] = 66;
|
||||
tempTriangle1[len1] = 66;
|
||||
|
||||
int8 startVal = tempTriangle[*startPtr];
|
||||
|
||||
switch (startVal) {
|
||||
case 8:
|
||||
flag3 = true;
|
||||
break;
|
||||
case 4:
|
||||
flag2 = true;
|
||||
break;
|
||||
case 2:
|
||||
flag1 = true;
|
||||
break;
|
||||
case 12:
|
||||
flag2 = true;
|
||||
flag3 = flag2;
|
||||
break;
|
||||
case 6:
|
||||
flag1 = true;
|
||||
flag2 = true;
|
||||
break;
|
||||
case 10:
|
||||
flag1 = true;
|
||||
flag3 = true;
|
||||
break;
|
||||
case 14:
|
||||
flag2 = false;
|
||||
flag1 = false;
|
||||
flag3 = flag2;
|
||||
break;
|
||||
default:
|
||||
flag2 = true;
|
||||
flag1 = true;
|
||||
flag3 = flag2;
|
||||
break;
|
||||
}
|
||||
|
||||
int minLen = 101;
|
||||
if (flag1) {
|
||||
for (int8 *ptr = tempTriangle1; *ptr != 66; ++ptr) {
|
||||
int8 part1 = 0;
|
||||
if ((startVal & 8) == 0)
|
||||
part1 = triangleLogicTable[14 * *ptr + 7];
|
||||
int8 part2 = 0;
|
||||
if ((startVal & 4) == 0)
|
||||
part2 = triangleLogicTable[14 * *ptr + 6];
|
||||
if (minLen > part1 + part2) {
|
||||
minLen = part1 + part2;
|
||||
result = *ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag2) {
|
||||
for (int8 *ptr = tempTriangle2; *ptr != 66; ++ptr) {
|
||||
int8 part1 = 0;
|
||||
if ((startVal & 8) == 0)
|
||||
part1 = triangleLogicTable[14 * *ptr + 7];
|
||||
int8 part2 = 0;
|
||||
if ((startVal & 2) == 0)
|
||||
part2 = triangleLogicTable[14 * *ptr + 8];
|
||||
if (minLen > part1 + part2) {
|
||||
minLen = part1 + part2;
|
||||
result = *ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag3) {
|
||||
for (int8 *ptr = tempTriangle3; *ptr != 66; ++ptr) {
|
||||
int8 part1 = 0;
|
||||
if ((startVal & 2) == 0)
|
||||
part1 = triangleLogicTable[14 * *ptr + 8];
|
||||
int8 part2 = 0;
|
||||
if ((startVal & 4) == 0)
|
||||
part2 = triangleLogicTable[14 * *ptr + 6];
|
||||
if (minLen > part1 + part2) {
|
||||
minLen = part1 + part2;
|
||||
result = *ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int TriangleGame::sub13(int8 row, int8 *triangleCells, int8 *moves) {
|
||||
int pos = 0;
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int8 v6 = triangleLogicTable[14 * row + i];
|
||||
|
||||
if (v6 != -1 && !triangleCells[v6]) {
|
||||
int v7 = (i + 1) % 6;
|
||||
int8 v8 = triangleLogicTable[14 * row + v7];
|
||||
|
||||
if (v8 != -1 && !triangleCells[v8]) {
|
||||
int8 v9 = triangleLogicTable[14 * v6 + v7];
|
||||
|
||||
if (v9 != -1 && !triangleCells[v9])
|
||||
moves[pos++] = v9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
moves[pos] = 66;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
void TriangleGame::setCell(int8 cellnum, int8 val) {
|
||||
assert(cellnum >= 0);
|
||||
assert(cellnum < 66);
|
||||
if (cellnum >= 0 && cellnum < 66) {
|
||||
++_triangleCellCount;
|
||||
assert(_triangleCells[cellnum] == 0);
|
||||
_triangleCells[cellnum] = val;
|
||||
}
|
||||
}
|
||||
|
||||
void TriangleGame::copyLogicRow(int row, int8 key, int8 *dest) {
|
||||
int pos = 0;
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int8 val = triangleLogicTable[14 * row + i];
|
||||
if (val != -1 && _triangleCells[val] == key)
|
||||
dest[pos++] = val;
|
||||
}
|
||||
|
||||
dest[pos] = 66;
|
||||
}
|
||||
|
||||
void TriangleGame::replaceCells(int8 *tempTriangle, int limit, int8 from, int8 to) {
|
||||
for (int i = 0; i <= limit; ++i) {
|
||||
if (tempTriangle[i] == from)
|
||||
tempTriangle[i] = to;
|
||||
}
|
||||
}
|
||||
|
||||
int TriangleGame::copyLookup(const int8 *lookup, int8 *start, int8 *dest){
|
||||
int counter = 0;
|
||||
|
||||
if (*lookup == 66) {
|
||||
*dest = 66;
|
||||
return counter;
|
||||
}
|
||||
|
||||
for (; *lookup != 66; lookup++) {
|
||||
for (int8 *ptr = start; *ptr != 66; ptr++) {
|
||||
if (*ptr == *lookup)
|
||||
dest[counter++] = *lookup;
|
||||
}
|
||||
}
|
||||
|
||||
dest[counter] = 66;
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
void TriangleGame::collapseLoops(int8 *route, int8 *singleRow) {
|
||||
int len = 0;
|
||||
for (int8 *i = route; *i != 66; i++)
|
||||
len++;
|
||||
|
||||
int origlen = len;
|
||||
|
||||
|
||||
for (int8 *i = singleRow; *i != 66; i++) {
|
||||
int j;
|
||||
for (j = 0; j < len; j++) {
|
||||
if (route[j] == *i)
|
||||
break;
|
||||
}
|
||||
if (j == len)
|
||||
route[len++] = *i;
|
||||
}
|
||||
|
||||
if (len != origlen)
|
||||
route[len] = 66;
|
||||
}
|
||||
|
||||
bool TriangleGame::testGame(uint32 seed, const Common::Array<uint8> moves, bool playerWin) {
|
||||
byte vars[1024];
|
||||
byte &op = vars[3];
|
||||
byte &move10s = vars[0];
|
||||
byte &move1s = vars[1];
|
||||
byte &winner = vars[3];
|
||||
|
||||
memset(vars, 0, sizeof(vars));
|
||||
|
||||
op = 3;
|
||||
run(vars);
|
||||
|
||||
warning("starting TriangleGame::testGame(%u, %u, %d)", seed, moves.size(), (int)playerWin);
|
||||
_random.setSeed(seed);
|
||||
|
||||
for (uint i = 0; i < moves.size(); i++) {
|
||||
if (i % 2) {
|
||||
// check Stauf's move
|
||||
uint8 move = ((uint)move10s * 10) + (uint)move1s;
|
||||
if (move != moves[i]) {
|
||||
error("%u: bad Stauf move: %d", (int)i, (int)move);
|
||||
// return false here is useful for finding the right seed to test
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// else, input player's move
|
||||
if (winner != 0)
|
||||
error("%u: early winner: %d", (int)i, (int)winner);
|
||||
|
||||
uint8 move = moves[i];
|
||||
move10s = move / 10;
|
||||
move1s = move % 10;
|
||||
op = 0;
|
||||
run(vars);
|
||||
}
|
||||
|
||||
if (playerWin && winner != 2)
|
||||
error("player didn't win, winner: %d", (int)winner);
|
||||
if (playerWin == false && winner != 1)
|
||||
error("Stauf didn't win, winner: %d", (int)winner);
|
||||
|
||||
warning("finished TriangleGame::testGame(%u, %u, %d)", seed, moves.size(), (int)playerWin);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TriangleGame::ensureSamanthaWin(uint32 seed) {
|
||||
byte vars[1024];
|
||||
byte &op = vars[3];
|
||||
byte &winner = vars[3];
|
||||
|
||||
op = 3;
|
||||
run(vars);
|
||||
|
||||
warning("starting TriangleGame::ensureSamanthaWin(%u)", seed);
|
||||
_random.setSeed(seed);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
// Samantha
|
||||
op = 4;
|
||||
run(vars);
|
||||
if (winner)
|
||||
break;
|
||||
|
||||
// Stauf
|
||||
op = 5;
|
||||
run(vars);
|
||||
if (winner)
|
||||
break;
|
||||
}
|
||||
|
||||
if (winner != 2)
|
||||
error("Samantha didn't win, winner: %d", (int)winner);
|
||||
|
||||
warning("finished TriangleGame::ensureSamanthaWin(%u)", seed);
|
||||
}
|
||||
|
||||
void TriangleGame::testPlayRandomly(uint32 seed) {
|
||||
byte vars[1024];
|
||||
byte &op = vars[3];
|
||||
byte &move10s = vars[0];
|
||||
byte &move1s = vars[1];
|
||||
byte &winner = vars[3];
|
||||
|
||||
op = 3;
|
||||
run(vars);
|
||||
|
||||
warning("starting TriangleGame::testPlayRandomly(%u)", seed);
|
||||
_random.setSeed(seed);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
// Player make random move
|
||||
uint8 move = 0;
|
||||
do {
|
||||
move = _random.getRandomNumber(65);
|
||||
} while (_triangleCells[move]);
|
||||
|
||||
move10s = move / 10;
|
||||
move1s = move % 10;
|
||||
op = 0;
|
||||
run(vars);
|
||||
if (winner)
|
||||
break;
|
||||
|
||||
// Stauf
|
||||
op = 5;
|
||||
run(vars);
|
||||
if (winner)
|
||||
break;
|
||||
}
|
||||
|
||||
if (winner != 1)
|
||||
error("Stauf didn't win, winner: %d", (int)winner);
|
||||
|
||||
warning("finished TriangleGame::testPlayRandomly(%u)", seed);
|
||||
}
|
||||
|
||||
void TriangleGame::test() {
|
||||
warning("starting TriangleGame::test");
|
||||
uint32 oldSeed = _random.getSeed();
|
||||
|
||||
// Samantha appears to not always win, but she usually does, and she wins these seeds
|
||||
// haven't verified if she always wins in the original game
|
||||
for (uint32 i = 100; i < 105; i++)
|
||||
ensureSamanthaWin(i);
|
||||
|
||||
// Similar thing here, technically there might be a seed where the player wins, but Stauf should win the vast majority of them
|
||||
for (uint32 i = 200; i < 205; i++)
|
||||
testPlayRandomly(i);
|
||||
|
||||
testGame(1, {24, 32, 30, 42, 37, 53, 45, 39, 19, 47, 20, 56, 55, 59, 36, 49, 29, 46, 23, 38, 18}, true);
|
||||
testGame(1, {24, 32, 30, 42, 37, 53, 19, 39, 45, 47, 46, 59, 56, 49, 38, 48, 31, 40, 25, 50, 20}, true);
|
||||
testGame(2, {24, 31, 33, 38, 43, 46, 16, 41, 54, 52, 64, 61, 53, 37, 42, 51, 32, 40, 23, 60, 15}, true);
|
||||
testGame(2, {24, 31, 33, 38, 43, 46, 16, 41, 53, 52, 64, 61, 54, 37, 34, 50, 25, 36, 17, 0, 10}, true);
|
||||
testGame(40680, {0, 24, 1, 12, 2, 4, 3, 5, 6, 30, 7, 9, 8, 29, 10, 13, 11, 47, 14, 18, 20, 37, 19, 36, 27, 57, 26, 31}, false);
|
||||
|
||||
_random.setSeed(oldSeed);
|
||||
warning("finished TriangleGame::test");
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
const int8 triangleLookup1[12] = {
|
||||
0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66
|
||||
};
|
||||
|
||||
const int8 triangleLookup2[12] = {
|
||||
0, 2, 5, 9, 14, 20, 27, 35, 44, 54, 65, 66
|
||||
};
|
||||
|
||||
const int8 triangleLookup3[12] = {
|
||||
55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66
|
||||
};
|
||||
|
||||
const int8 triangleLogicTable[924] = {
|
||||
-1, -1, 2, 1, -1, -1, 0, 0, 10, 10, 6, 0, 10, 10,
|
||||
0, 2, 4, 3, -1, -1, 0, 1, 9, 9, 5, 1, 9, 9,
|
||||
-1, -1, 5, 4, 1, 0, 1, 0, 9, 11, 5, 1, 9, 9,
|
||||
1, 4, 7, 6, -1, -1, 0, 2, 8, 8, 4, 2, 8, 8,
|
||||
2, 5, 8, 7, 3, 1, 1, 1, 8, 10, 4, 1, 8, 8,
|
||||
-1, -1, 9, 8, 4, 2, 2, 0, 8, 12, 4, 2, 8, 8,
|
||||
3, 7, 11, 10, -1, -1, 0, 3, 7, 7, 3, 3, 7, 7,
|
||||
4, 8, 12, 11, 6, 3, 1, 2, 7, 9, 3, 2, 7, 7,
|
||||
5, 9, 13, 12, 7, 4, 2, 1, 7, 11, 3, 2, 7, 7,
|
||||
-1, -1, 14, 13, 8, 5, 3, 0, 7, 13, 3, 3, 7, 7,
|
||||
6, 11, 16, 15, -1, -1, 0, 4, 6, 6, 3, 4, 6, 6,
|
||||
7, 12, 17, 16, 10, 6, 1, 3, 6, 8, 2, 3, 6, 6,
|
||||
8, 13, 18, 17, 11, 7, 2, 2, 6, 10, 2, 2, 6, 6,
|
||||
9, 14, 19, 18, 12, 8, 3, 1, 6, 12, 2, 3, 6, 6,
|
||||
-1, -1, 20, 19, 13, 9, 4, 0, 6, 14, 3, 4, 6, 6,
|
||||
10, 16, 22, 21, -1, -1, 0, 5, 5, 5, 3, 5, 5, 5,
|
||||
11, 17, 23, 22, 15, 10, 1, 4, 5, 7, 2, 4, 5, 5,
|
||||
12, 18, 24, 23, 16, 11, 2, 3, 5, 9, 1, 3, 5, 5,
|
||||
13, 19, 25, 24, 17, 12, 3, 2, 5, 11, 1, 3, 5, 5,
|
||||
14, 20, 26, 25, 18, 13, 4, 1, 5, 13, 2, 4, 5, 5,
|
||||
-1, -1, 27, 26, 19, 14, 5, 0, 5, 15, 3, 5, 5, 5,
|
||||
15, 22, 29, 28, -1, -1, 0, 6, 4, 4, 3, 6, 6, 4,
|
||||
16, 23, 30, 29, 21, 15, 1, 5, 4, 6, 2, 5, 5, 4,
|
||||
17, 24, 31, 30, 22, 16, 2, 4, 4, 8, 1, 4, 4, 4,
|
||||
18, 25, 32, 31, 23, 17, 3, 3, 4, 10, 0, 3, 4, 4,
|
||||
19, 26, 33, 32, 24, 18, 4, 2, 4, 12, 1, 4, 4, 4,
|
||||
20, 27, 34, 33, 25, 19, 5, 1, 4, 14, 2, 5, 4, 5,
|
||||
-1, -1, 35, 34, 26, 20, 6, 0, 4, 16, 3, 6, 4, 6,
|
||||
21, 29, 37, 36, -1, -1, 0, 7, 3, 3, 3, 7, 7, 3,
|
||||
22, 30, 38, 37, 28, 21, 1, 6, 3, 5, 2, 6, 6, 3,
|
||||
23, 31, 39, 38, 29, 22, 2, 5, 3, 7, 1, 5, 5, 3,
|
||||
24, 32, 40, 39, 30, 23, 3, 4, 3, 9, 0, 4, 4, 3,
|
||||
25, 33, 41, 40, 31, 24, 4, 3, 3, 11, 0, 4, 3, 4,
|
||||
26, 34, 42, 41, 32, 25, 5, 2, 3, 13, 1, 5, 3, 5,
|
||||
27, 35, 43, 42, 33, 26, 6, 1, 3, 15, 2, 6, 3, 6,
|
||||
-1, -1, 44, 43, 34, 27, 7, 0, 3, 17, 3, 7, 3, 7,
|
||||
28, 37, 46, 45, -1, -1, 0, 8, 2, 2, 4, 8, 8, 2,
|
||||
29, 38, 47, 46, 36, 28, 1, 7, 2, 4, 3, 7, 7, 2,
|
||||
30, 39, 48, 47, 37, 29, 2, 6, 2, 6, 2, 6, 6, 2,
|
||||
31, 40, 49, 48, 38, 30, 3, 5, 2, 8, 1, 5, 5, 3,
|
||||
32, 41, 50, 49, 39, 31, 4, 4, 2, 10, 1, 4, 4, 4,
|
||||
33, 42, 51, 50, 40, 32, 5, 3, 2, 12, 1, 5, 3, 5,
|
||||
34, 43, 52, 51, 41, 33, 6, 2, 2, 14, 2, 6, 2, 6,
|
||||
35, 44, 53, 52, 42, 34, 7, 1, 2, 16, 3, 7, 2, 7,
|
||||
-1, -1, 54, 53, 43, 35, 8, 0, 2, 18, 4, 8, 2, 8,
|
||||
36, 46, 56, 55, -1, -1, 0, 9, 1, 1, 5, 9, 9, 1,
|
||||
37, 47, 57, 56, 45, 36, 1, 8, 1, 3, 4, 8, 8, 1,
|
||||
38, 48, 58, 57, 46, 37, 2, 7, 1, 5, 3, 7, 7, 2,
|
||||
39, 49, 59, 58, 47, 38, 3, 6, 1, 7, 2, 6, 6, 3,
|
||||
40, 50, 60, 59, 48, 39, 4, 5, 1, 9, 2, 5, 5, 4,
|
||||
41, 51, 61, 60, 49, 40, 5, 4, 1, 11, 2, 5, 4, 5,
|
||||
42, 52, 62, 61, 50, 41, 6, 3, 1, 13, 2, 6, 3, 6,
|
||||
43, 53, 63, 62, 51, 42, 7, 2, 1, 15, 3, 7, 2, 7,
|
||||
44, 54, 64, 63, 52, 43, 8, 1, 1, 17, 4, 8, 1, 8,
|
||||
-1, -1, 65, 64, 53, 44, 9, 0, 1, 19, 5, 9, 1, 9,
|
||||
45, 56, -1, -1, -1, -1, 0, 10, 0, 0, 6, 10, 10, 0,
|
||||
46, 57, -1, -1, 55, 45, 1, 9, 0, 2, 5, 9, 9, 1,
|
||||
47, 58, -1, -1, 56, 46, 2, 8, 0, 4, 4, 8, 8, 2,
|
||||
48, 59, -1, -1, 57, 47, 3, 7, 0, 6, 3, 7, 7, 3,
|
||||
49, 60, -1, -1, 58, 48, 4, 6, 0, 8, 3, 6, 6, 4,
|
||||
50, 61, -1, -1, 59, 49, 5, 5, 0, 10, 3, 5, 5, 5,
|
||||
51, 62, -1, -1, 60, 50, 6, 4, 0, 12, 3, 6, 4, 6,
|
||||
52, 63, -1, -1, 61, 51, 7, 3, 0, 14, 3, 7, 3, 7,
|
||||
53, 64, -1, -1, 62, 52, 8, 2, 0, 16, 4, 8, 2, 8,
|
||||
54, 65, -1, -1, 63, 53, 9, 1, 0, 18, 5, 9, 1, 9,
|
||||
-1, -1, -1, -1, 64, 54, 10, 0, 0, 20, 6, 10, 0, 10
|
||||
};
|
||||
|
||||
} // End of anonymous namespace
|
||||
|
||||
|
||||
} // End of Groovie namespace
|
||||
Reference in New Issue
Block a user