Rare Witch Roundtable Podcast
Go Back   The Rare Witch Project Forums > General > Creative Cavern

Creative Cavern We'd love to see your artwork, read your stories, or play your games. So let your creative juices go wild. Images are enabled in this forum.

Thread Tools
Old 17th April 2023, 01:39 AM
CaptainDredlokk CaptainDredlokk is offline
Join Date: Oct 2010
Location: Hell
Total Awards: 1
You're Appreciated! 
I managed to get the first bit of functionality out of the CPU opponent in my poker game. It's able to look at its cards and "bluff" as to how good or bad its hand is if it has a high enough bluff stat paired with a high enough dice roll. As it currently stands, an AI with a perfect stat and an AI with a stat as low as possible can both successfully perform an action and blunder if they roll a 100 or a 0 respectively. I kinda like how this works and want to continue to use it, as it's cool to think that even an underdog who is truly bad at bluffing, has poor perception, or is overly-careful can still pull a brilliant move out of nowhere and shake up the game - keeps the player unpredictable also.

After doing so, it then has the option to draw cards. I need to add a betting phase before this, however I haven't refined how I want the betting function to work just yet. I also need to look at how bluffing works in relation to drawing and discarding cards - bluffing your hand as exceptional makes little sense if you're just going to drop cards. I'm thinking a combination of stats can be used here, where if the player has a hand that's "not great but serviceable" based on their perception roll and a high enough action score (what the CPU uses to decide if it's going to bet/call, raise, or fold) in conjunction with its aggressiveness roll, and their bluff roll will be able to bypass drawing and play the "my hand is so good I really don't need to draw" gambit, vs a player who has just as good of an initial bluff roll but really no good hand or isn't quite as ballsy as another CPU in terms of stats, (and rolls) it will instead pass a poker face that is impossible to be read by opponents. As of right now, the CPU simply passes the inverse of its hand value, unless its hand is average (as the inverse of average is just average in the code logic) in which case it passes a "poker face."

It took a minute to really wrap my head around the decision tree for drawing and discarding. As of now, the CPU will try and go for the most statistically likely hand - if it has a pair already, it'll try and build upon that pair/trips. If it has nothing, it will then look at its hand to see how many "approaching straights" and "approaching flushes" it can find. If there is a tie, (3 cards of the same suit vs 3 cards within 5 values of eachother) it will try for a flush, since it's much more likely to get a flush than a straight. Then it tries for a flush. It will then group all of the cards to be kept into "good cards" and all of the cards to be discarded into "bad cards," and parse the positions of the bad cards from the physical hands into a vector called "selections," which is passed to the function by address and back to the calling function to be used by the existing hand discard method, slightly rearranged for CPU usage.

Eventually I wanna play with the CPU stats a bit more - maybe make an exceptionally aggressive player who has a lower perception (which kind of serves as the "intelligence" stat) more likely to say "screw this pair - I wanna go right for a flush" - but I'm a bit worried that over-complicating the draw function is going to make it perform extremely poor randomly. It would definitely add to the unpredictability of it, but I don't want that to be at the cost of random bouts of incoherent behavior.

All four players (P1 is user, P2-4 are CPU's) putting in a $5 ante, getting their cards dealt, and all but the first player pass tells to the table - some of them are bluffs, some of them are not (I think player 2 bluffs - awful hand with a poker face that says otherwise, but I didn't save the screenshot)

Player 3 discarding cards 1, 2, and 5 (or 0, 1, and 4 in the actual data structure) due to them not matching the pair that they already have, and managing to turn their pair of 8's into a three of a kind. (As well as giving a new tell when they get their hand) All of the text displayed here including the hand is of course going to be behind the scenes in the final product - it's displayed for testing and verification purposes here however to make sure everything is behaving correctly. (hence the temporary "this is a test" and iter counts lol) There are a ton of moving parts and data to these functions so I had a lot of bug fixing and flow-charting to get it to take the shape of something I was happy with.

Player 4 finds no pairs, so it sends its entire hand to the "bad cards" vector, and creates two copies of it - flushCheck and straightCheck - so it can modify them during each pass without losing the order from the bad cards. It then goes through flushCheck and straightCheck and removes sets of cards - all matching suit in the flush vector, and (from left to right) sets of cards that are no more than 4 lower than the highest card. (which is always the leftmost card) - and pushes them to the back of a vector of card vectors - flushCards and straightCards (I'm horrible at variable naming lol) - then repeats the process until it has removed all cards from flushCheck and straightCheck. Then it finds the biggest sub-vector among flushCards and straightCards (with ties being broken by the largest flush) and if there are ties, chooses the first element in the supervector. (as due to the sorting, the first is always going to comprise of the leftmost cards, which are always the highest value cards on a "card rank" level) Then just like with pairs, parses the suit and value to the actual physical locations of the player's physical hand, passes the "bad cards" to the selection vector, and uses the selection vector to select the bad cards to discard.

Some code snippets under the hood.

It's really not anything too impressive at all, however it took a surprising amount of work to get this far. (work and school don't help with progress lol) I've got a lot of cleaning up and refining once I get a true MVP down, and I'd like to refactor everything in main into a "game" class that allows the player to choose between 5 card draw, 7 card stud, Texas Hold 'Em, and maybe some other card games too like Blackjack. Definitely want to refactor all of the raw pointers into smart pointers too, as I understand it's way safer to do so in modern iterations of C++. I'm pretty proud of it as my first real "big" project on my own however - learning a whole lot about the C++ syntax and how data behaves.
Reply With Quote
Old 16th July 2023, 08:20 PM
CaptainDredlokk CaptainDredlokk is offline
Join Date: Oct 2010
Location: Hell
Total Awards: 1
You're Appreciated! 
I finished the MVP for my primitive terminal-based poker game. It definitely could use a bit of refinement - I need to tweak the CPU so CPU players with really high perception stats aren't "mind readers," (they almost always can see through other player's tells to know if their hand is good or bad) sit down and watch a lot of poker to get an idea of how it's played professionally to make the CPU behave more realistically, (they behave "as expected" right now... just a little too strong in terms of perception, and I'm not sure they really bet/call/fold at a ratio that makes sense in the context of IRL poker) and implement 7-Card Stud and Texas Hold 'Em (Stud will be easy; no drawing and just modifying the hand-evaluating algorithm to sort the hand once again based on "best possible hand" before evaluating left to right. Hold 'Em will be a bit more difficult, as you must do the same but do it with a river)

Some pictures:

I'm glad to see it as a fully-functional game with enough features to be its own self-contained 5-Card Draw program. I'm not sure if I'm going to do the improvements/refinements and then work on refactoring it into a fully graphical game just yet. Really focusing on finishing the project has taken me away from further Comp Sci studies (which idk if it is necessarily a bad thing because the actual work and problem-solving involved taught me a LOT in of itself) and I really wanna continue learning data structures and try my hand at Python and JS. Really cool to see it go from just a dumb little script that prints some playing cards to a full blown game with CPU's that kinda sorta act like people lol.

If you're bored and wanna play it or just look at the code, feel free to check it out here.
Reply With Quote
Old 11th December 2023, 10:33 PM
Mr. Airplane's Avatar
Mr. Airplane Mr. Airplane is offline he/they
a banana peel
Join Date: Jul 2008
Total Awards: 6
You're Appreciated! RWP Podcast Rarity Chatterbox INFECTED - B1K1 
I have taken on a nonsense project to convert as many consoles as I can to rackmount.

I've been working on this Famicom frontplate and mounting system for the past two months, and I think it's finally almost time to design the case itself.


Reply With Quote
Old 7th January 2024, 02:38 AM
neen's Avatar
neen neen is offline he/they
u ‾ ‾ u
Join Date: Jul 2001
Location: new england
Total Awards: 3
RWP Donator RWP Podcast INFECTED - B1K1 
will finish this within this year, whether i like it or not

Reply With Quote

User Tag List

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

All times are GMT. The time now is 02:07 PM.

Forums powered by vBulletin® Copyright © Jelsoft Enterprises Ltd.
Website © 2000-∞ The RWP