/* 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/winerack.h"

namespace Groovie {

enum WineBottle {
	kWineBottleOpponent = 1,
	kWineBottlePlayer = 2
};

namespace {
extern const int8 wineRackLogicTable[1200];
}

WineRackGame::WineRackGame() : _random("WineRackGame"), _totalBottles(0) {
	memset(_wineRackGrid, 0, 100);

#if 0
	runTests();
#endif
}

void WineRackGame::run(byte *scriptVariables) {
	char op = scriptVariables[3];
	byte pos = 0;

	/* positions on the board
	*	north = 9 (0, 9)
		south = 90 (9, 0)
		east = 99 (9, 9)
		west = 0 (0, 0)
	*/

	switch (op) {
	case 3:
		debugC(kDebugLogic, "WineRackGame initGrid, seed: %u", _random.getSeed());
		initGrid(scriptVariables[4]);
		break;
	case 4:	// Player's move
		pos = calculateNextMove(kWineBottlePlayer);
		placeBottle(pos, kWineBottlePlayer);
		scriptVariables[0] = pos / 10;
		scriptVariables[1] = pos % 10;
		scriptVariables[3] = didPlayerWin();
		break;
	case 5:	// Opponent's move
		scriptVariables[3] = 0;
		pos = calculateNextMove(kWineBottleOpponent);
		placeBottle(pos, kWineBottleOpponent);
		scriptVariables[0] = pos / 10;
		scriptVariables[1] = pos % 10;
		scriptVariables[3] = didAiWin() != 0 ? 1 : 0;
		break;
	default:
		scriptVariables[3] = 0;
		placeBottle(scriptVariables[0] * 10 + scriptVariables[1], 2);

		if (didPlayerWin()) {
			scriptVariables[3] = 2;
		} else {
			pos = calculateNextMove(kWineBottleOpponent);
			placeBottle(pos, kWineBottleOpponent);
			scriptVariables[0] = pos / 10;
			scriptVariables[1] = pos % 10;
			scriptVariables[3] = didAiWin() != 0 ? 1 : 0;
		}
		break;
	}
}

void WineRackGame::initGrid(byte difficulty) {
	memset(_wineRackGrid, 0, 100);

	switch (difficulty) {
	case 0:
		_totalBottles = 24;

		_wineRackGrid[15] = kWineBottlePlayer;
		_wineRackGrid[18] = kWineBottleOpponent;
		_wineRackGrid[19] = kWineBottleOpponent;
		_wineRackGrid[20] = kWineBottleOpponent;
		_wineRackGrid[21] = kWineBottleOpponent;
		_wineRackGrid[22] = kWineBottleOpponent;
		_wineRackGrid[23] = kWineBottleOpponent;
		_wineRackGrid[25] = kWineBottlePlayer;
		_wineRackGrid[26] = kWineBottleOpponent;
		_wineRackGrid[27] = kWineBottleOpponent;
		_wineRackGrid[28] = kWineBottleOpponent;
		_wineRackGrid[33] = kWineBottleOpponent;
		_wineRackGrid[34] = kWineBottleOpponent;
		_wineRackGrid[35] = kWineBottlePlayer;
		_wineRackGrid[36] = kWineBottleOpponent;
		_wineRackGrid[44] = kWineBottlePlayer;
		_wineRackGrid[45] = kWineBottlePlayer;
		_wineRackGrid[54] = kWineBottlePlayer;
		_wineRackGrid[62] = kWineBottlePlayer;
		_wineRackGrid[63] = kWineBottlePlayer;
		_wineRackGrid[64] = kWineBottlePlayer;
		_wineRackGrid[72] = kWineBottlePlayer;
		_wineRackGrid[82] = kWineBottlePlayer;
		_wineRackGrid[91] = kWineBottlePlayer;
		break;

	case 1:
		_totalBottles = 12;

		_wineRackGrid[75] = kWineBottlePlayer;
		_wineRackGrid[56] = kWineBottlePlayer;
		_wineRackGrid[45] = kWineBottlePlayer;
		_wineRackGrid[27] = kWineBottlePlayer;
		_wineRackGrid[24] = kWineBottlePlayer;
		_wineRackGrid[15] = kWineBottlePlayer;
		_wineRackGrid[64] = kWineBottleOpponent;
		_wineRackGrid[34] = kWineBottleOpponent;
		_wineRackGrid[33] = kWineBottleOpponent;
		_wineRackGrid[18] = kWineBottleOpponent;
		_wineRackGrid[16] = kWineBottleOpponent;
		_wineRackGrid[14] = kWineBottleOpponent;
		break;

	default:
		_totalBottles = 0;
		break;
	}
}

void WineRackGame::placeBottle(byte pos, byte val) {
	debugC(kDebugLogic, "placeBottle(%d, %d)", (int)pos, (int)val);
	_totalBottles++;
	assert(_wineRackGrid[pos] == 0);
	_wineRackGrid[pos] = val;
}

int8 WineRackGame::calculateNextMove(byte player) {
	int8 moves1[24];
	int8 moves2[24];
	byte playerIndex = (player == 1) + 1;

	if (!_totalBottles)
		return randomMoveStart();
	if (_totalBottles == 1)
		return randomMoveStart2();

	sub05(player, moves1);
	sub05(playerIndex, moves2);

	int8 result = sub06(moves1, moves2);

	if (result == -1)
		return findEmptySpot();

	assert(_wineRackGrid[result] == 0);

	return result;
}

int8 WineRackGame::findEmptySpot() {
	int8 result = 0;

	while (_wineRackGrid[result]) {
		if (result == 99)
			return 100;
		else
			++result;
	}

	return result;
}

void WineRackGame::sub05(int8 player, int8 *moves) {
	int8 moves1[23];
	int8 moves2[23];
	int8 to, delta, playerIndex;

	if (player == 1) {
		to = 90;
		delta = 10;
		playerIndex = 2;
	} else {
		to = 9;
		delta = 1;
		playerIndex = 3;
	}

	memset(moves, 0, 23);

	for (int i = 0; i < to; i += delta) {
		if (!_wineRackGrid[i] || _wineRackGrid[i] == player) {
			memset(moves1, 0, sizeof(moves1));
			memset(moves2, 0, sizeof(moves2));

			sub13(i, playerIndex, moves1, moves2);

			if (moves[0] < moves1[0]) {
				memcpy(moves, moves1, 23);
			}
		}
	}
}

int8 WineRackGame::sub06(int8 *moves1, int8 *moves2) {
	for (int i = 0; i < moves1[2]; i++) {

		int8 result = moves1[i + 3];

		if (!_wineRackGrid[result]) {
			for (int j = 0; j < moves2[2]; j++)
				if (moves2[j + 3] == result)
					return result;
		}
	}

	for (int i = 0; i < moves1[2]; i++) {
		if (!_wineRackGrid[moves1[i + 3]])
			return moves1[i + 3];
	}

	return -1;
}

uint32 WineRackGame::didPlayerWin() {
	memset(_wineRackGrid2, 0, 100);

	for (int i = 0; i < 10; i++) {
		if (_wineRackGrid[i] == kWineBottlePlayer) {
			int var = 0;
			sub10(100, i, 2, 3, &var);
			if (var == 1)
				return 1;
		}
	}

	return 0;
}

void WineRackGame::sub10(int8 endPos, int8 pos, int unused, int player, int *val) {
	int8 candidates[8];

	if (*val)
		return;

	if (wineRackLogicTable[12 * pos + player] == -1) {
		*val = 1;

		return;
	}

	sub11(pos, candidates);

	for (int i = 0; candidates[i] != 100; i++) {
		int8 nextPos = candidates[i];

		if (endPos != nextPos)
			sub10(pos, nextPos, unused, player, val);
	}
}

void WineRackGame::sub11(int8 pos, int8 *candidates) {
	int cnt = 0;

	_wineRackGrid2[pos] = 1;

	for (int i = 0; i < 6; i++) {
		int8 val = wineRackLogicTable[12 * pos + i];

		if (!_wineRackGrid2[val] && _wineRackGrid[pos] == _wineRackGrid[val])
			candidates[cnt++] = val;
	}

	candidates[cnt] = 100;
}

uint32 WineRackGame::didAiWin() {
	memset(_wineRackGrid2, 0, 100);

	for (int i = 0; i < 100; i += 10) {
		if (_wineRackGrid[i] == kWineBottleOpponent) {
			int var = 0;
			sub10(100, i, 1, 2, &var);
			if (var == 1)
				return 1;
		}
	}

	return 0;
}

void WineRackGame::sub13(int8 cell, int8 player, int8 *moves1, int8 *moves2) {
	int8 candidates[4];

	if (cell == -1)
		return;

	moves2[moves2[2] + 3] = cell;

	if (wineRackLogicTable[12 * cell + player] < 0) {
		++moves2[2];

		moves2[0] = countEmtpy(moves2);

		if (moves2[0] > moves1[0])
			memcpy(moves1, moves2, 23);

		--moves2[2];
	} else {
		++moves2[2];

		if (player == 2)
			sub15(cell, candidates);
		else
			sub16(cell, candidates);

		for (int i = 0; candidates[i] != -1; i++)
			sub13(candidates[i], player, moves1, moves2);

		--moves2[2];
	}
}

void WineRackGame::sub15(int8 cell, int8 *candidates) {
	int8 depth = 0;
	int8 pos2 = wineRackLogicTable[12 * cell + 2];
	int8 pos1 = wineRackLogicTable[12 * cell + 1];

	if (_wineRackGrid[pos2] == 2) {
		if (pos1 < 0 || _wineRackGrid[pos1] == 2) {
			if (cell >= 20) {
				int8 val1 = _wineRackGrid[cell - 10];

				if (val1 != 2) {
					int8 val2 = _wineRackGrid[cell - 10];

					if (val2 != 2 && (val1 == 1 || val2 == 1)) {
						depth = 1;
						candidates[0] = cell - 10;
					}
				}
			}
			if (cell < 80) {
				int8 val1 = _wineRackGrid[cell + 10];

				if (val1 != 2) {
					int8 val2 = _wineRackGrid[cell + 11];

					if (val2 != 2 && (val1 == 1 || val2 == 1)) {
						candidates[depth] = cell + 10;
						depth++;
					}
				}
			}
		} else if (_wineRackGrid[cell] == 1 || _wineRackGrid[pos1] == 1) {
			depth = 1;
			candidates[0] = pos1;
		}
	} else if (pos1 < 0 || _wineRackGrid[pos1] == 2) {
		if (_wineRackGrid[cell] == 1 || _wineRackGrid[pos2] == 1) {
			depth = 1;
			candidates[0] = pos2;
		}
	} else {
		depth = 2;
		candidates[0] = pos2;
		candidates[1] = pos1;
	}

	candidates[depth] = -1;
}

void WineRackGame::sub16(int8 cell, int8 *candidates) {
	int8 depth = 0;
	int8 pos3 = wineRackLogicTable[12 * cell + 3];
	int8 pos4 = wineRackLogicTable[12 * cell + 4];

	if (_wineRackGrid[pos3] == 1) {
		if (pos4 < 0 || _wineRackGrid[pos4] == 1) {
			if (cell % 10 >= 2) {
				int8 val1 = _wineRackGrid[cell - 1];

				if (val1 != 1) {
					int8 val2 = _wineRackGrid[cell + 8];

					if (val2 != 1 && (val1 == 2 || val2 == 2)) {
						depth = 1;
						candidates[0] = cell - 1;
					}
				}
			}
			if (cell < 80 && _wineRackGrid[cell + 1] != 1) {
				int8 val1 = _wineRackGrid[cell + 11];

				if (val1 != 1 && (_wineRackGrid[cell + 1] == 2 || val1 == 2)) {
					candidates[depth] = cell + 1;
					depth++;
				}
			}
		} else if (_wineRackGrid[cell] == 2 || _wineRackGrid[pos4] == 2) {
			depth = 1;
			candidates[0] = pos4;
		}
	} else if (pos4 < 0 || _wineRackGrid[pos4] == 1) {
		if (_wineRackGrid[cell] == 2 || _wineRackGrid[pos3] == 2) {
			depth = 1;
			candidates[0] = pos3;
		}
	} else {
		depth = 2;
		candidates[0] = pos3;
		candidates[1] = pos4;
	}

	candidates[depth] = -1;
}

int8 WineRackGame::countEmtpy(int8 *moves) {
	int8 cnt = 0;

	for (int i = 0; i < moves[2]; i++) {
		if (!_wineRackGrid[moves[i + 3]])
			++cnt;
	}

	return 20 - cnt;
}

int8 WineRackGame::randomMoveStart() {
	const int8 moves[] = { 44, 45, 54, 55 };

	return moves[_random.getRandomNumber(3)];
}

int8 WineRackGame::randomMoveStart2() {
	const int8 moves[] = { 25, 26, 63, 64 };
	// the original game doesn't ensure the spot isn't taken
	int8 res = 0;
	do {
		res = moves[_random.getRandomNumber(3)];
	} while (_wineRackGrid[res] != 0);
	return res;
}

void WineRackGame::testWinCondition(byte player, int baseX, int baseY) {
	initGrid(2);

	int basePos = baseX * 10 + baseY;

	for (int i = 0; i < 10; i++) {
		if (player == kWineBottlePlayer)
			placeBottle(i * 10 + basePos, player);
		else
			placeBottle(i + basePos, player);
	}

	if (player == kWineBottlePlayer && !didPlayerWin()) {
		error("WineRackGame::testWinCondition(%d, %d, %d) failed", (int)player, baseX, baseY);
	} else if (player == kWineBottleOpponent && !didAiWin()) {
		error("WineRackGame::testWinCondition(%d, %d, %d) failed", (int)player, baseX, baseY);
	}
}

void WineRackGame::testGame(uint32 seed, Common::Array<int> moves, bool playerWin) {
	byte vars[1024] = {};
	byte &x = vars[0];
	byte &y = vars[1];
	byte &op = vars[3];
	byte &winner = vars[3];
	byte &difficulty = vars[4];
	_random.setSeed(seed);

	difficulty = 2;
	op = 3;
	run(vars);
	winner = 0;

	for (uint i = 0; i < moves.size(); i += 2) {
		if (winner)
			error("early winner");
		x = moves[i];
		y = moves[i + 1];
		op = 1;
		run(vars);
	}

	if (playerWin && winner != 2)
		error("WineRackGame::testGame(%u, %u, %d) player didn't win", seed, moves.size(), (int)playerWin);
	else if (playerWin == false && winner != 1)
		error("WineRackGame::testGame(%u, %u, %d) ai didn't win", seed, moves.size(), (int)playerWin);
}

void WineRackGame::runTests() {
	warning("WineRackGame::runTests() starting");
	uint32 oldSeed = _random.getSeed();

	for (int i = 0; i < 10; i++) {
		testWinCondition(kWineBottlePlayer, 0, i);
		testWinCondition(kWineBottleOpponent, i, 0);
	}

	// pairs of x,y for the player's moves
	testGame(1, {9,0, 9,1, 9,2, 9,3, 9,4, 9,5, 9,6, 9,7, 9,8, 9,9}, false);
	testGame(2, {5,5, 3,5, 7,4, 1,6, 9,3, 0,7, 2,6, 4,5, 6,5, 8,4}, true);
	// in the original game, the AI had a 25% chance to move to 2,6 as its first move, even if your first move was to 2,6 already
	testGame(147160395, {2,6, 3,6, 4,6, 5,6, 7,6, 8,6, 9,6, 2,7, 3,7, 4,7}, false);

	_random.setSeed(oldSeed);
	warning("WineRackGame::runTests() finished");
}

namespace {

const int8 wineRackLogicTable[1200] = {
	-1, -1,  1, 10, -1, -1, -1, -1, 11, -1, -1, -1,
	-1, -1,  2, 11, 10,  0, -1, -1, 12, 20, -1, -1,
	-1, -1,  3, 12, 11,  1, -1, -1, 13, 21, 10, -1,
	-1, -1,  4, 13, 12,  2, -1, -1, 14, 22, 11, -1,
	-1, -1,  5, 14, 13,  3, -1, -1, 15, 23, 12, -1,
	-1, -1,  6, 15, 14,  4, -1, -1, 16, 24, 13, -1,
	-1, -1,  7, 16, 15,  5, -1, -1, 17, 25, 14, -1,
	-1, -1,  8, 17, 16,  6, -1, -1, 18, 26, 15, -1,
	-1, -1,  9, 18, 17,  7, -1, -1, 19, 27, 16, -1,
	-1, -1, -1, 19, 18,  8, -1, -1, -1, 28, 17, -1,
	 0,  1, 11, 20, -1, -1, -1,  2, 21, -1, -1, -1,
	 1,  2, 12, 21, 20, 10, -1,  3, 22, 30, -1,  0,
	 2,  3, 13, 22, 21, 11, -1,  4, 23, 31, 20,  1,
	 3,  4, 14, 23, 22, 12, -1,  5, 24, 32, 21,  2,
	 4,  5, 15, 24, 23, 13, -1,  6, 25, 33, 22,  3,
	 5,  6, 16, 25, 24, 14, -1,  7, 26, 34, 23,  4,
	 6,  7, 17, 26, 25, 15, -1,  8, 27, 35, 24,  5,
	 7,  8, 18, 27, 26, 16, -1,  9, 28, 36, 25,  6,
	 8,  9, 19, 28, 27, 17, -1, -1, 29, 37, 26,  7,
	 9, -1, -1, 29, 28, 18, -1, -1, -1, 38, 27,  8,
	10, 11, 21, 30, -1, -1,  1, 12, 31, -1, -1, -1,
	11, 12, 22, 31, 30, 20,  2, 13, 32, 40, -1, 10,
	12, 13, 23, 32, 31, 21,  3, 14, 33, 41, 30, 11,
	13, 14, 24, 33, 32, 22,  4, 15, 34, 42, 31, 12,
	14, 15, 25, 34, 33, 23,  5, 16, 35, 43, 32, 13,
	15, 16, 26, 35, 34, 24,  6, 17, 36, 44, 33, 14,
	16, 17, 27, 36, 35, 25,  7, 18, 37, 45, 34, 15,
	17, 18, 28, 37, 36, 26,  8, 19, 38, 46, 35, 16,
	18, 19, 29, 38, 37, 27,  9, -1, 39, 47, 36, 17,
	19, -1, -1, 39, 38, 28, -1, -1, -1, 48, 37, 18,
	20, 21, 31, 40, -1, -1, 11, 22, 41, -1, -1, -1,
	21, 22, 32, 41, 40, 30, 12, 23, 42, 50, -1, 20,
	22, 23, 33, 42, 41, 31, 13, 24, 43, 51, 40, 21,
	23, 24, 34, 43, 42, 32, 14, 25, 44, 52, 41, 22,
	24, 25, 35, 44, 43, 33, 15, 26, 45, 53, 42, 23,
	25, 26, 36, 45, 44, 34, 16, 27, 46, 54, 43, 24,
	26, 27, 37, 46, 45, 35, 17, 28, 47, 55, 44, 25,
	27, 28, 38, 47, 46, 36, 18, 29, 48, 56, 45, 26,
	28, 29, 39, 48, 47, 37, 19, -1, 49, 57, 46, 27,
	29, -1, -1, 49, 48, 38, -1, -1, -1, 58, 47, 28,
	30, 31, 41, 50, -1, -1, 21, 32, 51, -1, -1, -1,
	31, 32, 42, 51, 50, 40, 22, 33, 52, 60, -1, 30,
	32, 33, 43, 52, 51, 41, 23, 34, 53, 61, 50, 31,
	33, 34, 44, 53, 52, 42, 24, 35, 54, 62, 51, 32,
	34, 35, 45, 54, 53, 43, 25, 36, 55, 63, 52, 33,
	35, 36, 46, 55, 54, 44, 26, 37, 56, 64, 53, 34,
	36, 37, 47, 56, 55, 45, 27, 38, 57, 65, 54, 35,
	37, 38, 48, 57, 56, 46, 28, 39, 58, 66, 55, 36,
	38, 39, 49, 58, 57, 47, 29, -1, 59, 67, 56, 37,
	39, -1, -1, 59, 58, 48, -1, -1, -1, 68, 57, 38,
	40, 41, 51, 60, -1, -1, 31, 42, 61, -1, -1, -1,
	41, 42, 52, 61, 60, 50, 32, 43, 62, 70, -1, 40,
	42, 43, 53, 62, 61, 51, 33, 44, 63, 71, 60, 41,
	43, 44, 54, 63, 62, 52, 34, 45, 64, 72, 61, 42,
	44, 45, 55, 64, 63, 53, 35, 46, 65, 73, 62, 43,
	45, 46, 56, 65, 64, 54, 36, 47, 66, 74, 63, 44,
	46, 47, 57, 66, 65, 55, 37, 48, 67, 75, 64, 45,
	47, 48, 58, 67, 66, 56, 38, 49, 68, 76, 65, 46,
	48, 49, 59, 68, 67, 57, 39, -1, 69, 77, 66, 47,
	49, -1, -1, 69, 68, 58, -1, -1, -1, 78, 67, 48,
	50, 51, 61, 70, -1, -1, 41, 52, 71, -1, -1, -1,
	51, 52, 62, 71, 70, 60, 42, 53, 72, 80, -1, 50,
	52, 53, 63, 72, 71, 61, 43, 54, 73, 81, 70, 51,
	53, 54, 64, 73, 72, 62, 44, 55, 74, 82, 71, 52,
	54, 55, 65, 74, 73, 63, 45, 56, 75, 83, 72, 53,
	55, 56, 66, 75, 74, 64, 46, 57, 76, 84, 73, 54,
	56, 57, 67, 76, 75, 65, 47, 58, 77, 85, 74, 55,
	57, 58, 68, 77, 76, 66, 48, 59, 78, 86, 75, 56,
	58, 59, 69, 78, 77, 67, 49, -1, 79, 87, 76, 57,
	59, -1, -1, 79, 78, 68, -1, -1, -1, 88, 77, 58,
	60, 61, 71, 80, -1, -1, 51, 62, 81, -1, -1, -1,
	61, 62, 72, 81, 80, 70, 52, 63, 82, 90, -1, 60,
	62, 63, 73, 82, 81, 71, 53, 64, 83, 91, 80, 61,
	63, 64, 74, 83, 82, 72, 54, 65, 84, 92, 81, 62,
	64, 65, 75, 84, 83, 73, 55, 66, 85, 93, 82, 63,
	65, 66, 76, 85, 84, 74, 56, 67, 86, 94, 83, 64,
	66, 67, 77, 86, 85, 75, 57, 68, 87, 95, 84, 65,
	67, 68, 78, 87, 86, 76, 58, 69, 88, 96, 85, 66,
	68, 69, 79, 88, 87, 77, 59, -1, 89, 97, 86, 67,
	69, -1, -1, 89, 88, 78, -1, -1, -1, 98, 87, 68,
	70, 71, 81, 90, -1, -1, 61, 72, 91, -1, -1, -1,
	71, 72, 82, 91, 90, 80, 62, 73, 92, -1, -1, 70,
	72, 73, 83, 92, 91, 81, 63, 74, 93, -1, 90, 71,
	73, 74, 84, 93, 92, 82, 64, 75, 94, -1, 91, 72,
	74, 75, 85, 94, 93, 83, 65, 76, 95, -1, 92, 73,
	75, 76, 86, 95, 94, 84, 66, 77, 96, -1, 93, 74,
	76, 77, 87, 96, 95, 85, 67, 78, 97, -1, 94, 75,
	77, 78, 88, 97, 96, 86, 68, 79, 98, -1, 95, 76,
	78, 79, 89, 98, 97, 87, 69, -1, 99, -1, 96, 77,
	79, -1, -1, 99, 98, 88, -1, -1, -1, -1, 97, 78,
	80, 81, 91, -1, -1, -1, 71, 82, -1, -1, -1, -1,
	81, 82, 92, -1, -1, 90, 72, 83, -1, -1, -1, 80,
	82, 83, 93, -1, -1, 91, 73, 84, -1, -1, -1, 81,
	83, 84, 94, -1, -1, 92, 74, 85, -1, -1, -1, 82,
	84, 85, 95, -1, -1, 93, 75, 86, -1, -1, -1, 83,
	85, 86, 96, -1, -1, 94, 76, 87, -1, -1, -1, 84,
	86, 87, 97, -1, -1, 95, 77, 88, -1, -1, -1, 85,
	87, 88, 98, -1, -1, 96, 78, 89, -1, -1, -1, 86,
	88, 89, 99, -1, -1, 97, 79, -1, -1, -1, -1, 87,
	89, -1, -1, -1, -1, 98, -1, -1, -1, -1, -1, 88
};

} // End of anonymous namespace

} // End of Groovie namespace
