GROOVIE: T11H Pente AI puzzle

This commit is contained in:
Die4Ever 2021-10-27 19:09:49 -05:00
parent a0cd941fa5
commit ffb1dc3610
No known key found for this signature in database
GPG Key ID: 7B8AAD15B16CE289
8 changed files with 1079 additions and 11 deletions

View File

@ -321,6 +321,7 @@ byte CakeGame::aiGetBestMove(int search_depth) {
void CakeGame::testCake() {
warning("starting CakeGame::testCake()");
uint32 oldSeed = _random.getSeed();
// test the draw condition, grouped by column
runCakeTestNoAi(/*move 1*/ "7777777" /*8*/ "6666666" /*15*/ "5555555" /*22*/ "34444444" /*30*/ "333333" /*36*/ "2222222" /*43*/ "01111111" /*51*/ "000000", false, true);
@ -328,6 +329,7 @@ void CakeGame::testCake() {
runCakeTest(1, "232232432445", false);
runCakeTest(123, "4453766355133466", false);
_random.setSeed(oldSeed);
warning("finished CakeGame::testCake()");
}

File diff suppressed because it is too large Load Diff

View File

@ -31,13 +31,40 @@ namespace Groovie {
/*
* Pente puzzle at the end of the game.
*/
struct pentePlayerTable;
struct penteTable;
class PenteGame {
public:
PenteGame();
void run(byte *scriptVariables);
private:
int *allocs(int param_1, int param_2);
void penteSub02Frees(penteTable *param_1);
void penteSub05BuildLookupTable(penteTable *table);
penteTable *penteSub01Init(byte width, byte height, byte length);
void penteSub03Scoring(penteTable *table, byte move_y, byte move_x, bool whose_turn);
void penteSub07RevertScore(penteTable *table_1, byte y, byte x);
byte penteScoreCaptureSingle(penteTable *table, byte x, byte y, int slopeX, int slopeY);
uint penteSub04ScoreCapture(penteTable *table, byte y, byte x);
void penteSub08MaybeAnimateCapture(short param_1, byte *param_2, short *param_3, short *param_4);
void penteSub11RevertCapture(penteTable *table, byte y, byte x, byte y2);
int penteSub10AiRecurse(penteTable *table_1, char depth, int parent_score);
uint penteSub09Ai(uint y_1, int param_2, int param_3, penteTable *table_4, byte depth);
void penteOp(byte *vars);
void test();
void testGame(uint32 seed, Common::Array<int> moves, bool playerWin);
Common::RandomSource _random;
byte globalY;
byte globalX;
char global2;
short globalPlayerMove;
short global1;
penteTable *game_state_table;
};
} // End of Groovie namespace

View File

@ -824,6 +824,7 @@ void TriangleGame::ensureSamanthaWin(uint32 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
@ -837,6 +838,7 @@ void TriangleGame::test() {
testGame(3, {24, 32, 17, 42, 23, 53, 16, 39, 11, 29, 10, 44, 6, 33, 7, 63, 12, 28, 18, 31, 13, 204, 8, 204, 4, 38, 3, 43}, false);
testGame(3, {6, 32, 10, 42, 11, 53, 7, 23, 3, 15, 12, 22, 18, 43, 13, 33, 8, 35, 4, 31, 1, 204, 17, 204, 16, 204, 19, 63 }, false);
_random.setSeed(oldSeed);
warning("finished TriangleGame::test");
}

View File

@ -2181,6 +2181,26 @@ void Script::o2_playsound() {
playBackgroundSound(fileref, loops);
}
void Script::o_wipemaskfromstring58() {
// used in pente when pieces are captured
Common::String vidName;
uint16 instStart = _currentInstruction;
uint32 fileref = getVideoRefString(vidName);
setBitFlag(10, true);
// Show the debug information just when starting the playback
if (fileref != _videoRef) {
debugC(0, kDebugScript, "Groovie::Script: WIPEMASKFROMSTRING58 %d ('%s')", fileref, vidName.c_str());
debugC(2, kDebugVideo, "\nGroovie::Script: @0x%04X: Playing mask video %d ('%s') via 0x58 (o_wipemaskfromstring58)", instStart - 1, fileref, vidName.c_str());
}
// Play the video
if (!playvideofromref(fileref)) {
// Move _currentInstruction back
_currentInstruction = instStart - 1;
}
}
void Script::o2_check_sounds_overlays() {
uint16 val1 = readScript8or16bits();
uint8 val2 = readScript8bits();
@ -2394,7 +2414,7 @@ Script::OpcodeFunc Script::_opcodesV2[NUM_OPCODES] = {
&Script::o2_setscriptend,
&Script::o2_playsound,
&Script::o_invalid,
&Script::o_invalid, // 0x58
&Script::o_wipemaskfromstring58, // 0x58
&Script::o2_check_sounds_overlays,
&Script::o2_preview_loadgame
};

View File

@ -245,6 +245,7 @@ private:
void o_musicdelay();
void o_hotspot_outrect();
void o_stub56();
void o_wipemaskfromstring58();
void o_stub59();
void o2_bf0on();

View File

@ -65,13 +65,20 @@ static inline void copyPixel(byte *dst, const byte *src) {
*(uint32 *)dst = *(const uint32 *)src;
}
// Overwrites one pixel of destination regardless of the alpha value
// Overwrites one pixel of destination if the src pixel is visible
static inline void copyPixelIfAlpha(byte *dst, const byte *src) {
if (src[kAIndex] > 0) {
copyPixel(dst, src);
}
}
// Overwrites one pixel if it's part of the mask
static inline void copyPixelIfMask(byte *dst, const byte *mask, const byte *src) {
if (mask[kAIndex] > 0) {
copyPixel(dst, src);
}
}
// Copies one pixel to destination but respects the alpha value of the source
static inline void copyPixelWithA(byte *dst, const byte *src) {
if (src[kAIndex] == 255) {
@ -142,6 +149,7 @@ uint16 ROQPlayer::loadInternal() {
_flagOne = ((_flags & (1 << 1)) != 0);
_flagTwo = ((_flags & (1 << 2)) != 0);
_altMotionDecoder = ((_flags & (1 << 14)) != 0);
_flagMasked = ((_flags & (1 << 10)) != 0);
// Read the file header
ROQBlockHeader blockHeader;
@ -249,7 +257,13 @@ void ROQPlayer::buildShowBuf() {
// Select the destination buffer according to the given flags
int destOffset = 0;
Graphics::Surface *destBuf;
Graphics::Surface *maskBuf = NULL;
Graphics::Surface *srcBuf = _currBuf;
Graphics::Surface *destBuf = NULL;
if (_flagMasked) {
srcBuf = _bg;
maskBuf = _currBuf;
}
if (_flagOne) {
if (_flagTwo) {
destBuf = _overBuf;
@ -266,17 +280,24 @@ void ROQPlayer::buildShowBuf() {
int startX, startY, stopX, stopY;
calcStartStop(startX, stopX, _origX, _screen->w);
calcStartStop(startY, stopY, _origY, _screen->h);
assert(destBuf->format == _currBuf->format);
assert(destBuf->format == srcBuf->format);
assert(destBuf->format == _overBuf->format);
assert(destBuf->format.bytesPerPixel == 4);
for (int line = startY; line < stopY; line++) {
byte *in = (byte *)_currBuf->getBasePtr(MAX(0, -_origX) / _scaleX, (line - _origY) / _scaleY);
byte *in = (byte *)srcBuf->getBasePtr(MAX(0, -_origX) / _scaleX, (line - _origY) / _scaleY);
byte *inOvr = (byte *)_overBuf->getBasePtr(startX, line);
byte *out = (byte *)destBuf->getBasePtr(startX, line + destOffset);
byte *mask = NULL;
if (_flagMasked) {
mask = (byte *)maskBuf->getBasePtr(MAX(0, -_origX) / _scaleX, (line - _origY) / _scaleY);
}
for (int x = startX; x < stopX; x++) {
if (destBuf == _overBuf) {
if (_flagMasked) {
copyPixelIfMask(out, mask, in);
} else if (destBuf == _overBuf) {
copyPixelIfAlpha(out, in);
} else {
copyPixelWithA(out, in);
@ -296,6 +317,8 @@ void ROQPlayer::buildShowBuf() {
inOvr += _screen->format.bytesPerPixel;
if (!(x % _scaleX))
in += _screen->format.bytesPerPixel;
if (mask)
mask += _screen->format.bytesPerPixel;
}
}

View File

@ -93,9 +93,10 @@ private:
byte _codebook4[256 * 4];
// Flags
bool _flagOne; // Play only first frame and do not print the image to the screen
bool _flagTwo; // If _flagOne is set. Copy frame to the foreground otherwise to the background
bool _flagOne; //!< Play only first frame and do not print the image to the screen
bool _flagTwo; //!< If _flagOne is set. Copy frame to the foreground otherwise to the background
bool _altMotionDecoder; // Some ROQ vids use a variation on the copy codeblock
bool _flagMasked; //!< Clear the video instead of play it, used in pente
// Buffers
void buildShowBuf();