[Scummvm-git-logs] scummvm master -> a1eed24c224138f7cab4cf061d97885e06dac263

bluegr noreply at scummvm.org
Sun May 21 20:30:33 UTC 2023


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
a1eed24c22 SCI: More work on the Hoyle 5 poker logic


Commit: a1eed24c224138f7cab4cf061d97885e06dac263
    https://github.com/scummvm/scummvm/commit/a1eed24c224138f7cab4cf061d97885e06dac263
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2023-05-21T23:30:12+03:00

Commit Message:
SCI: More work on the Hoyle 5 poker logic

Changed paths:
    engines/sci/engine/hoyle5poker.cpp


diff --git a/engines/sci/engine/hoyle5poker.cpp b/engines/sci/engine/hoyle5poker.cpp
index c0052cc501d..03ea7d546a9 100644
--- a/engines/sci/engine/hoyle5poker.cpp
+++ b/engines/sci/engine/hoyle5poker.cpp
@@ -30,6 +30,8 @@ namespace Sci {
 
 #ifdef ENABLE_SCI32
 
+//#define DEBUG_POKER_LOGIC
+
 // The logic for the poker game in Hoyle Classic Games (Hoyle 5) is hardcoded
 // in PENGIN16.DLL, which is then loaded and invoked via the kWinDLL kernel call.
 // Note that the first player is the left one.
@@ -42,10 +44,10 @@ enum Hoyle5PokerSuits {
 };
 
 enum Hoyle5Operations {
-	kCheckPlayerAction = 1,	// localproc_0df8
-	kCheckWinner = 2,	// localproc_3020
-	kCheckDiscard = 3,	// PokerHand::think
-	kCheckHand = 4		// PokerHand::whatAmI
+	kCheckPlayerAction = 1, // localproc_0df8
+	kCheckWinner = 2,       // localproc_3020
+	kCheckDiscard = 3,      // PokerHand::think
+	kCheckHand = 4          // PokerHand::whatAmI
 };
 
 enum Hoyle5PlayerActions {
@@ -55,6 +57,24 @@ enum Hoyle5PlayerActions {
 	kPlayerActionRaise = 1
 };
 
+enum Hoyle5DiscardActions {
+	kDiscardActionKeep = 0,
+	kDiscardActionDiscard = 1
+};
+
+enum Hoyle5HandType {
+	kHandTypeFiveOfAKind = 1 << 8,   // 256, five of a kind
+	kHandTypeStraightFlush = 1 << 7, // 128, straight flush
+	kHandTypeFourOfAKind = 1 << 6,   //  64, four of a kind
+	kHandTypeFullHouse = 1 << 5,     //  32, full house
+	kHandTypeFlush = 1 << 4,         //  16, flush
+	kHandTypeStraight = 1 << 3,      //   8, straight
+	kHandTypeThreeOfAKind = 1 << 2,  //   4, three of a kind
+	kHandTypeTwoPairs = 1 << 1,      //   2, two pairs
+	kHandTypeOnePair = 1 << 0,       //   1, one pair
+	kHandTypeHighCard = 0            //   0, high card
+};
+
 enum Hoyle5PokerData {
 	kOperation = 0,
 	kTotalChips = 1,
@@ -73,8 +93,8 @@ enum Hoyle5PokerData {
 	kTotalBetPlayer3 = 14,
 	kTotalBetPlayer4 = 15,
 	// 16: related to the current bet
-	kCurrentPlayer = 17,	// hand number
-	kCurrentStage = 18,	// Stage 1: Card changes, 2: Betting
+	kCurrentPlayer = 17, // hand number
+	kCurrentStage = 18,  // Stage 1: Card changes, 2: Betting
 	kCard0 = 19,
 	kSuit0 = 20,
 	kCard1 = 21,
@@ -89,16 +109,16 @@ enum Hoyle5PokerData {
 	// 29 - 38: next clockwise player's cards (number + suit)
 	// 39 - 48: next clockwise player's cards (number + suit)
 	// 49 - 58: next clockwise player's cards (number + suit)
-	kUnkVar = 59,		  // set by localproc_0df8 to global 906
+	kUnkVar = 59, // set by localproc_0df8 to global 906
 	// ---- Return values - start ---------------------------
-	kPlayerAction = 60,    // flag, checked by localproc_0df8
+	kPlayerAction = 60,   // flag, checked by localproc_0df8
 	kWhatAmIResult = 61,  // bitmask, 0 - 128, checked by PokerHand::whatAmI. Determines what kind of card each player has
 	kWinningPlayers = 62, // bitmask, winning players (0000 - 1111 binary), checked by localproc_3020
-	kDiscardCard0 = 63,	  // flag, checked by PokerHand::think
-	kDiscardCard1 = 64,	  // flag, checked by PokerHand::think
-	kDiscardCard2 = 65,	  // flag, checked by PokerHand::think
-	kDiscardCard3 = 66,	  // flag, checked by PokerHand::think
-	kDiscardCard4 = 67,	  // flag, checked by PokerHand::think
+	kDiscardCard0 = 63,   // flag, checked by PokerHand::think
+	kDiscardCard1 = 64,   // flag, checked by PokerHand::think
+	kDiscardCard2 = 65,   // flag, checked by PokerHand::think
+	kDiscardCard3 = 66,   // flag, checked by PokerHand::think
+	kDiscardCard4 = 67,   // flag, checked by PokerHand::think
 	// ---- Return values - end -----------------------------
 	// 77 is a random number (0 - 32767)
 	kLastRaise1 = 78,
@@ -116,7 +136,7 @@ enum Hoyle5PokerData {
 	// 90 is a number
 };
 
-#if 0
+#ifdef DEBUG_POKER_LOGIC
 Common::String getCardDescription(int16 card, int16 suit) {
 	Common::String result;
 
@@ -191,7 +211,7 @@ void debugInputData(SciArray* data) {
 #endif
 
 int getCardValue(int card) {
-	return card == 1 ? 14 : card;	// aces are the highest valued cards
+	return card == 1 ? 14 : card; // aces are the highest valued cards
 }
 
 int getCardTotal(SciArray *data, int player) {
@@ -283,25 +303,25 @@ int checkHand(SciArray *data, int player = 0) {
 		(cards[0] == cards[1] && cards[2] == cards[3] && cards[3] == cards[4]);
 
 	if (pairs == 1 && sameRank == 2)
-		return 1 << 0;	// 1, one pair
+		return kHandTypeOnePair;
 	else if (pairs == 2 && !isFullHouse)
-		return 1 << 1;	// 2, two pairs
+		return kHandTypeTwoPairs;
 	else if (sameRank == 3 && !isFullHouse)
-		return 1 << 2;	// 4, three of a kind
+		return kHandTypeThreeOfAKind;
 	else if (orderedCards == 5 && sameSuit < 5)
-		return 1 << 3;	// 8, straight
+		return kHandTypeStraight;
 	else if (orderedCards < 5 && sameSuit == 5)
-		return 1 << 4;	// 16, flush
+		return kHandTypeFlush;
 	else if (isFullHouse)
-		return 1 << 5;	// 32, full house
+		return kHandTypeFullHouse;
 	else if (sameRank == 4)
-		return 1 << 6;	// 64, four of a kind
+		return kHandTypeFourOfAKind;
 	else if (orderedCards == 5 && sameSuit == 5)
-		return 1 << 7;	// straight flush
+		return kHandTypeStraightFlush;
 	else if (sameRank == 5)
-		return 1 << 8;	// 256, five of a kind
+		return kHandTypeFiveOfAKind;
 
-	return 0;	// high card
+	return kHandTypeHighCard;
 }
 
 struct Hand {
@@ -331,29 +351,148 @@ int getWinner(SciArray *data) {
 		return getCardTotal(data, 0) > getCardTotal(data, 1) ? playerHands[0].player : playerHands[1].player;
 }
 
+int16 findMostFrequentCard(int *cards, int16 ignoreCard = -1) {
+	int16 mostFrequentCard = 0;
+	int16 maxCount = 0;
+
+	for (int16 i = 0; i <= 4; ++i) {
+		int16 count = 0;
+		for (int j = 0; j <= 4; ++j) {
+			if (cards[i] == cards[j])
+				count++;
+		}
+
+		if (count > maxCount && cards[i] != ignoreCard) {
+			maxCount = count;
+			mostFrequentCard = cards[i];
+		}
+	}
+
+	return mostFrequentCard;
+}
+
+void handleDiscard(SciArray *data) {
+	int16 player = data->getAsInt16(kCurrentPlayer);
+
+	int cards[5] = {
+		data->getAsInt16(kCard0 + 10 * player),
+		data->getAsInt16(kCard1 + 10 * player),
+		data->getAsInt16(kCard2 + 10 * player),
+		data->getAsInt16(kCard3 + 10 * player),
+		data->getAsInt16(kCard4 + 10 * player),
+	};
+
+	int hand = checkHand(data, player);
+	int16 cardToKeep = findMostFrequentCard(cards);
+	int16 cardToKeep2 = -1;
+	if (hand != kHandTypeFiveOfAKind) {
+		cardToKeep2 = findMostFrequentCard(cards, cardToKeep);
+	}
+
+	data->setFromInt16(kDiscardCard0, kDiscardActionKeep);
+	data->setFromInt16(kDiscardCard1, kDiscardActionKeep);
+	data->setFromInt16(kDiscardCard2, kDiscardActionKeep);
+	data->setFromInt16(kDiscardCard3, kDiscardActionKeep);
+	data->setFromInt16(kDiscardCard4, kDiscardActionKeep);
+
+	switch (hand) {
+	case kHandTypeFiveOfAKind:
+	case kHandTypeStraightFlush:
+	case kHandTypeFullHouse:
+	case kHandTypeFlush:
+	case kHandTypeStraight:
+		// Nothing is discarded
+		break;
+	case kHandTypeThreeOfAKind:
+	case kHandTypeFourOfAKind:
+	case kHandTypeOnePair:
+	case kHandTypeTwoPairs:
+		// Discard the odd ones out. We don't have a full house case in this branch
+		for (int i = 0; i <= 4; ++i) {
+			if (cards[i] == cardToKeep && hand != kHandTypeTwoPairs)
+				data->setFromInt16(kDiscardCard0 + i, kDiscardActionKeep);
+			else if ((cards[i] == cardToKeep || cards[i] == cardToKeep2) && hand == kHandTypeTwoPairs)
+				data->setFromInt16(kDiscardCard0 + i, kDiscardActionKeep);
+			else
+				data->setFromInt16(kDiscardCard0 + i, kDiscardActionDiscard);
+		}
+		break;
+	case kHandTypeHighCard:
+		// Everything is discarded
+		data->setFromInt16(kDiscardCard0, kDiscardActionDiscard);
+		data->setFromInt16(kDiscardCard1, kDiscardActionDiscard);
+		data->setFromInt16(kDiscardCard2, kDiscardActionDiscard);
+		data->setFromInt16(kDiscardCard3, kDiscardActionDiscard);
+		data->setFromInt16(kDiscardCard4, kDiscardActionDiscard);
+		break;
+	}
+}
+
+void handleRaiseOrCall(SciArray *data) {
+	// Raise if the player has money, call otherwise
+	int16 player = data->getAsInt16(kCurrentPlayer);
+	int16 bet = data->getAsInt16(kCurrentBet);
+	int16 playerBet = data->getAsInt16(kTotalBetPlayer1 + player);
+	int16 chips = data->getAsInt16(kTotalChipsPlayer1 + player);
+	
+	if (playerBet < bet && chips > bet)
+		data->setFromInt16(kPlayerAction, kPlayerActionRaise);
+	else
+		data->setFromInt16(kPlayerAction, kPlayerActionCall);
+}
+
+void handlePlayerAction(SciArray *data) {
+	// TODO: This implementation is somewhat better than completely
+	// random actions, but it's still severely lacking
+	warning("The Poker player action logic has not been implemented yet");
+
+	int16 player = data->getAsInt16(kCurrentPlayer);
+	int hand = checkHand(data, player);
+	bool shouldBluff = g_sci->getRNG().getRandomBit();
+
+	if (shouldBluff) {
+		handleRaiseOrCall(data);
+		return;
+	}
+
+	switch (hand) {
+	case kHandTypeFiveOfAKind:
+	case kHandTypeStraightFlush:
+	case kHandTypeFullHouse:
+	case kHandTypeFlush:
+	case kHandTypeStraight:
+	case kHandTypeThreeOfAKind:
+	case kHandTypeFourOfAKind:
+	case kHandTypeTwoPairs:
+		handleRaiseOrCall(data);
+		break;
+	case kHandTypeOnePair:
+		data->setFromInt16(kPlayerAction, kPlayerActionCall);
+		break;
+	case kHandTypeHighCard:
+		data->setFromInt16(kPlayerAction, kPlayerActionFold);
+		// TODO: kPlayerActionCheck
+		break;
+	}
+}
+
 reg_t hoyle5PokerEngine(SciArray *data) {
 	int16 operation = data->getAsInt16(kOperation);
-	Common::RandomSource& rng = g_sci->getRNG();
 
-	//debugInputData(data);
+#ifdef DEBUG_POKER_LOGIC
+	debug("*** Before running operation %d", operation);
+	debugInputData(data);
+#endif
 
 	switch (operation) {
 	case kCheckPlayerAction:
-		// TODO: logic for player actions
-		data->setFromInt16(kPlayerAction, (int16)rng.getRandomNumber(3) - 2);
-		warning("The Poker player action logic has not been implemented yet");
+		handlePlayerAction(data);
 		break;
 	case kCheckWinner:
 		data->setFromInt16(kWinningPlayers, 1 << getWinner(data));
 		break;
 	case kCheckDiscard:
-		// TODO: logic for card discard
-		data->setFromInt16(kDiscardCard0, (int16)rng.getRandomBit());
-		data->setFromInt16(kDiscardCard1, (int16)rng.getRandomBit());
-		data->setFromInt16(kDiscardCard2, (int16)rng.getRandomBit());
-		data->setFromInt16(kDiscardCard3, (int16)rng.getRandomBit());
-		data->setFromInt16(kDiscardCard4, (int16)rng.getRandomBit());
-		warning("The Poker card discard logic has not been implemented yet");
+		handleDiscard(data);
 		break;
 	case kCheckHand:
 		data->setFromInt16(kWhatAmIResult, checkHand(data));
@@ -363,6 +502,11 @@ reg_t hoyle5PokerEngine(SciArray *data) {
 		break;
 	}
 
+#ifdef DEBUG_POKER_LOGIC
+	debug("*** After running operation %d", operation);
+	debugInputData(data);
+#endif
+
 	return TRUE_REG;
 }
 




More information about the Scummvm-git-logs mailing list