Poker Kingdoms


  • Tiger Hat

    Among my various game projects is the one that I’ve ‘Completed’ - Poker Kingdoms. The first public release is available for free on the Google Play Store (this is unlikely to see updates) or a PC version on itch.io for $1 which will grant a Steam key, if the Greenlight campaign ever ends.

    Part One: Prerelease

    This game was inspired by my Fiancee who was at the time obsessed with Candy Crush, and also loves Poker.

    I knocked the original version of the game together in a couple of evenings using ImpactJS and some fairly rudimentary artwork done in GIMP.

    The original vision of the game was a traditional tile-matcher, where you’d try to match poker hands, this just didn’t work, as any set of 5 cards is a valid poker hand, so had to exclude shorter hands, and that just didn’t work. The solution was to make it more Boggle like, and allow the player to trace any congruous set of 5 tiles to make a hand. Again, originally, this was only in 4 directions, but in the end, it worked far better with 8.

    OriginalVersion

    I dropped the game on the 'net on some basic hosting, and set it loose on the net - and got the attention of an ex-collegue who does some amazing artwork, who offered to give me some assets with some images like this:

    Spades


  • LDG

    Upvoted! And installed on Android.

    Very cool dude. Looks like the latest version’s on Unity – how was that conversion from ImpactJS for you?

    The characters are very cute. As you probably know I’m a fan of thick line art ;) Nice style and personality.


  • Tiger Hat

    @richtaur said:

    Looks like the latest version’s on Unity

    Yep. I’ll touch on that in part 2 :)


  • Tiger Hat

    Part Two: HTML5 is never quite ready

    I managed to clean up most of the prototype with new assets, and have something that was more publicly presentable. ImpactJS was the first time I’d worked in a framework, rather than an engine, but it became rapidly apparent that the Framework was designed for platform games, and I ended up not using and having to bypass much of what was there, mostly relying on the gameloop, and the object faking.

    I started running into troubles, the game was locking up on OSX, and I couldn’t test there, and the two leaderboard systems I implemented shut down almost as I implemented the features. I decided that Google’s Game Play Services would be a better option, whilst they do have a reputation for killing off services, they’re usually not ones that they’ve spent much promoting, and they put a huge effort into promoting GPGS.

    At about this time, I got a new job and that came with a Macbook air - my sound wasn’t working because it was in .ogg format and it’s not supported on OSX devices. Rookie mistake, it worked on Windows, without special drivers though, supplying MP3 files fixed the Apple bug.

    I ended up with a playable game on the web, all fancy and HTML5. Poker Kingdoms HTML5. (This link may not continue to work, I’m only vaguely aware of where it’s hosted).

    Great as an example, you can hit the page, play the game, it’ll keep your score, and I think there’s even achievements.

    The game was perfect for mobile, so I experimented with a mobile port, and here I ran into serious roadblocks, Google requires a secure authentication token, and clicks on Canvas are not considered secure. At the time, none of the cross-platform HTML5 builders were suitable, either their canvas performance was too slow, or they were pure canvas implementations, which had no other HTML elements.

    I resigned to having to build against something that was more proven than HTML5, and Unity was free, and supported the Python-Like Boo language, and I really dig python, so I began porting the game to Unity.


  • Tiger Hat

    Part Three: Mistakes

    The very early builds in Unity were built mainly by dropping the logic code into Unity, breaking them out of the giant data structures that JS prefers, and into Unity’s GameObject paradigm. Eventually I found there are some edge-case scenarios where UnityScript wasn’t good enough. That was fine it gave me the chance to play with Boo.

    Thankfully, because I wasn’t able to use much of the functionality of ImpactJS, my logic wasn’t overly tied to the engine, and worked almost immediately out of the box. The game pieced together reasonably rapidly, and in a few months, I had the version that is now available on the Play Store, and I released my project to the world.

    The sad realizations started to set in. Things you don’t think about. The concept seemed unique to me - it seemed certain to be worth playing to at least some people, but how do you get found, there are quite literally thousands of generic match-3 games, and nearly as many poker games, Poker Kingdoms just sat in the play store getting no attention, because it was uniquely similar. I still haven’t found the solution to this yet - and it’s a huge drawback; I need people to play so that I can collect metrics, and develop the other parts of the game beyond the MVP that it sits at now.

    The Play Store compounded that mistake, it’s not designed for discovery.

    There was also a lack of planning; Poker Kingdoms was a hasty port from javascript, and unityscript, and I was kind of feeling my way around Unity as I built it. Architecturally, it was nightmare, simple things like adding another player made the game break in amazing ways and bringing it back to a working state required an extreme effort. The quest, and tutorial features I wanted to make were going to be worse.

    Finally, Boo was a mistake, there is almost zero community support, so every example I had to translate from c#, and most plugins use c# and it’s non-trivial to use multiple script types in Unity (although it is possible - ask me how). The nail in that coffin came when it was announced that Boo was deprecated in Unity 5.

    The project stagnated.


  • LDG

    @salmonmoose said:

    it became rapidly apparent that the Framework was designed for platform games, and I ended up not using and having to bypass much of what was there

    This strikes me as a valuable insight that usually comes from hands-on experience. Geoff was talking about something similar last week – how Unity is a 3d platform and so doing 2d in there can feel like using a wrench for a hammer’s job. good stuff, developer++

    I think there’s even achievements.

    hahahaha! love it, I can relate to that. Programming is so much work that even nontrivial features like achievement integration can disappear from memory.


  • LDG

    @salmonmoose said:

    The sad realizations started to set in. Things you don’t think about.

    This! As I got into game dev and finally shipping games, I was shocked by the vast difference between making a little game for yourself and your friends to enjoy, versus putting something out there into the world that you hope will be positively received by the market. So much learning happens between finishing and shipping. Good stuff.


  • Tiger Hat

    @richtaur said:

    The characters are very cute. As you probably know I’m a fan of thick line art ;) Nice style and personality.

    I should really give a shout-out to Mike, who did the art - I can’t give him any money from the game, because no one is playing or buying it, but always try to give him a bit of promotion http://www.bigfatrobot.com/ the t-shirts are particularly cool.


  • Patron

    Yo, @salmonmoose, what do you think this forum is?!

    Go HTML5 or go home!


  • Tiger Hat

    Part Four: Joining the Real World™

    It was really hard to watch Poker Kingdoms languish on the play store, I’d poured a whole lot of time into it, and Mike had given me some great assets, everyone who I could get to play the game really enjoyed it, but I just couldn’t get people to play it. There was a lot of “I don’t know how to play Poker”, which is fair enough - I tried making an interactive tutorial, but it wasn’t happening; so I settled for a visual instructions.

    This was the start of my next set of problems.

    It was about now that I put the game on Greenlight (the link above; please vote, tell your friends, seriously) - and got a collection of really decent support, and some complete ass-hole responses. I tried to start adding features to the game, but porting from ImpactJS, to UnityScript, to Boo had left the game in a fragile state, and bound together in such a way that changing one system, would bring all the other systems crashing into a heap. Largely I blame this on the Javascript phase of development - it’s not a language that encourages compartmentalism.

    My stagnated project had no clear way to move forwards, and not only did it stagnate, but I did too, I actually rage-quit to the point of deleting my project folders and having a man-child tantrum. (I’m never programming again, I’m going to learn to crochet instead).

    After some prodding, I entered my first Ludum Dare, with the personal goal to “Finish a Game” which I managed and this gave me a lot of personal motivation, but I didn’t see a clear way forwards with Poker Kingdoms, by now, Boo had been deprecated, and any work I tried to do was now fighting Unity, and the game.

    I spent a large amount of time beating my head against the broken code (which still had outstanding bugs that would not die) - until I finally came across the realization that rebuilding it right would be for the best - get rid of the cruft, and build from scratch. Not only that, but because I was so familiar with the game logic, this would be a perfect project to try new things with, as I could focus on those rather than the game logic. The first manifestation of this was to build using Test Driven Development.


  • Jammer

    The entirety of this community is constantly impressing me. @salmonmoose thank you for writing such a thorough synopsis of your work on this. It is impressive and inspiring.


  • Tiger Hat

    Part Five: From Scratch

    As it stood, the game was an interesting example, but the single player experience gets boring after a while - the game had made no money, and asking for more assets was a hard call - everything I wanted to add had to be made with the assets I had, until I could generate some revenue and push out with creative content, rather than mechanical. The obvious choice was some multiplayer functionality.

    I started the game from scratch, by writing a series of tests. Poker is a very large problem, more-so than chess, and Poker Kingdoms extends the problem size significantly. But it’s made of some very basic things, and which fit very well into OOP design.

    A card can be defined with a couple of ENUMs, and a Bool (Face, Suit, and Flipped). A deck of cards is no more than a first in, last out queue of cards. The playboard is a 2D array of cards, and a selection, is a set of positions on that board.

    This design leaves 90% of the code in the Hand class, a Hand is any set of 5 cards. Defining a hand is a monumental task. The Hand logic runs through hand types in descending order of strength, and calls wrapper functions like IsStraightFlush() which in turn tests IsStraight() and IsFlush(). There’s a bit of weird logic in IsStraight() because you can have an Ace, 2, 3, 4, 5 straight, or you can have a Ten, Jack, Queen, King, Ace straight so you can’t just test for congruent numbers.

    This is where Test Driven Development really shone - I could write a series of tests and make sure my code always evaluated them as the correct hands.

        [Test]
        [Category("Straight")]
        public void AceHighStraight() {
            Hand hand = new Hand();
    
            hand.Add(new Card(Suits.HEARTS, Faces.JACK));
            hand.Add(new Card(Suits.SPADES, Faces.TEN));
            hand.Add(new Card(Suits.CLUBS, Faces.KING));
            hand.Add(new Card(Suits.DIAMONDS, Faces.QUEEN));
            hand.Add(new Card(Suits.SPADES, Faces.ACE));
    
            Assert.AreEqual(
                Hands.STRAIGHT,
                hand.GetHand()
            );
        }
    

    These tests are very quick to write, because I’ve built with the idea of testing from scratch, there are no magic numbers, and everything is human readable.

    Because I’ve nested my hand detection, a problem in IsStraight() will break IsStraightFlush(), and IsRoyalFlush(), but the fix will only be in one place. This is important, because I added the concept of Jokers Wild. Because of the implementation, any number of cards could be a joker, and the hand eval would have to work, this increases the logic paths significantly, detecting a straight when there are some number of missing cards is tricky, a Full House (3 & 2 matching faces) is also not trivial, especially when you start working with 4 jokers.

    Again, a series of tests;

        [Test]
        [Category("Straight")]
        public void TwoJokerStraight() {
            Hand hand = new Hand();
    
            hand.Add(new Card(Suits.SPADES, Faces.TWO));
            hand.Add(new Card(Suits.HEARTS, Faces.THREE));
            hand.Add(new Card(Suits.DIAMONDS, Faces.FOUR));
            hand.Add(new Card(Suits.SPECIAL, Faces.JOKER));
            hand.Add(new Card(Suits.SPECIAL, Faces.JOKER));
    
            Assert.AreEqual(
                Hands.STRAIGHT,
                hand.GetHand()
            );
        }
    

    and massage the code until it all falls into place - sometimes you’ll see an edge case bug, rather than fix the bug directly, build a test to support it, and then fix it. For instance, you cannot have a Straight with more than 2 Jokers, because 4 of a kind is stronger, and once you have 3 jokers, you can always make 4 of a kind. The astute will notice that these tests are incomplete, I test what hand I’m returned, but I don’t test if the hand evaluates correctly. 3 jokers should evaluate “IsStraight()” but not return that hand when tested.

    I rebuilt the entire logic of Poker Kingdoms with this mind-set, but also completely in pure c# outside of Unity3d or any other framework.


  • Tiger Hat

    Part Six: Lessons

    Decoupling the logic code was my attempt at taking some lessons from Web Development, and an attempt to build a game in Unity with a MVC (Model, View, Controller) approach. The most straight forwards way of working with Unity is to attach logic to Game Objects, and this works fairly well in games. However, the MonoBehaviour class that you build everything off is rather heavy, and in previous editions, I ran into performance issues generating temporary clones of objects, both because initializing new objects was costly, but also because the Garbage collector started to thrash.

    A side benefit, was that decoupling from Unity meant I could build and extend the game logic in a terminal window on my breaks, without looking like I was playing games. It also means, the game itself could be spun up under anything that could talk to a c# library.

    So, the structure in Unity is different from the usual GameObject=>Monobehaviour link, I have a secondary tree of objects, and the front-end pulls states from them so GameObject=>MonoBehaviour=>Card. This is a one way link, the Card object has no knowledge of the state of its related GameObject (although information can be pushed to it). This means that the game objects have no cross communication and are independent of the actual game state. Deleting them just means you can’t see what’s happening.

    I also made the code work in distinct phases - not quite a finite state machine, as there is no pathing, but at any time, you could tell exactly what each element was doing, and when the phase changed, I could spit out debug information and gather metrics on how long it took.

    The game was now back where I started, however it was decently engineered, and running on a supported platform, so adding new features became easy.

    The first addition was the concept of a player; the original game just maintained a score, that got tapped at various points, a second player would have created a nightmare of pathing. But now I had a dedicate phase progression, adding a player was just a new phase, and a new object type. Once multiple player objects were supported, subclassing those to Human and AI, meant I could make player vs player, or player vs AI, and even AI vs AI matches.

    All I had to do, was create an AI that could play poker.


  • LDG

    Thanks for taking the time to post all these great experiences from Poker Kingdoms. It’s really interesting to see the ups and downs with regard to tech (an all too familiar pain).

    @salmonmoose said:

    All I had to do, was create an AI that could play poker.

    Dun, dun, DUNNNNN.


  • Tiger Hat

    @geoffb said:

    Thanks for taking the time to post all these great experiences from Poker Kingdoms. It’s really interesting to see the ups and downs with regard to tech (an all too familiar pain).

    Yeah - I hoped they weren’t out of place and distracting from the AWL stuff, and would instead provide some different insight into what LostCast is all about :)


  • Tiger Hat

    Part Seven: AI Think AI Can

    Poker is a fairly large problem set, but not as large as actually playing poker (or a derivative). Thankfully, Poker Kingdoms does not have be able to watch the player for bluffs and other non-mechanical game devices that exist in the traditional game.

    What it does have to do, is scan the board for a playable hands, and rank them. On the surface, this seems like a similar problem to games like Puzzle Quest, scan the board and look for a pattern, and make a play. Puzzle Quest has 3 valid patterns (2, 2x1, 2x2) to search for. Poker Kingdoms has 11, and, by nature of the game, they are each 5 tiles, and, as raised in the early parts, can exist in any set of 5 congruous tiles.

    The developers of Puzzle Quest insist that there is no solid AI behind their game, it doesn’t plan its choices, and possibly doesn’t even rank them if multiples exist. The latter can’t work in Poker Kingdoms, every possible set of 5 cards produces a valid hand, but a High Card hand is not worth very much at all.

    For the curious, the 5x5 board which Poker Kingdoms seems to play best on, has just a bit more than 17,000 available moves at any point in time - some cards can be hidden, so we need to find out all possible results, not just all actual results as could be done in Puzzle Quest. That’s

    My initial attempt tried to be elegant, for each hand type, it would scan the board, and start a ‘walker’. Walkers collected a set of points, testing each available move from the last point, and spawning a new walker to follow that path.

    0>1    0<1    0 1    0 1
    v        v    ^        ^
    2 3    2 3    2>3    2<3
    
    0 1    0 1    0>1    0<1
      v    v        ^    ^
    2>3    2<3    2 3    2 3
    
    0 1    0 1    0<1    0>1
      ^    ^        v    v
    2<3    2>3    2 3    2 3
    
    0,1,3,2 && 0,2,3,1
    1,0,2,3 && 1,3,2,0
    2,0,1,3 && 2,3,1,0
    3,1,0,2 && 3,2,0,1
    
    • this is a subset of actual generated walks, I’ve ignored diagonal steps.

    As these walker progressed, they would check against their respective hands, and stop spawning if they were no longer valid. If they reached 5 valid cards, they’d add a selection to a growing list of valid moves, and eventually return the move that scored the most points.

    This worked.

    The computer could walk the board and find visible hands.

    Aside: part of my encapsulation means flipped cards are invisible to every other element of the game, the representation of face/suit is private, and the getter reads the flipped bool. I would have to go out of my way to let the computer cheat.

    Because it couldn’t read flipped cards, it could break if there was no sets of 5 congruous cards, and it took no risks (playing a flipped card scores higher).

    It was also game-breaking slow. On a high end machine, it was taking over a minute to scan the board in some cases - and even set as a background thread, this would stall the game play for far too long - I wasn’t building Civilization here, without the background thread, the game could lock up for long enough for Windows to think it had failed.


  • Patron

    In lieu of having the time to write a reply this deserves, I just wanted to inject some energy by saying that this is frigging awesome! Both the project and your dissection of it. I love getting the lowdown on what went on in the developer’s mind like that.

    …which I guess we all do, since we’re all fans of a certain podcast. Obvious remark is obvious.

    Anyhow: @salmonmoose for president!


  • Tiger Hat

    @David said:

    Anyhow: @salmonmoose for president!

    Nah, I’m a horrible leader - my professional life stagnated a bit because I live in Adelaide, and don’t want to be a manager. What you can do is go Vote for my Greenlight and tell your friends :) http://bit.ly/pokerkingdoms


  • Tiger Hat

    Part Eight: Advanced programming is for dummies

    There was an overwhelming sense of success getting a computer to play the game against me (and against itself), I’ve never really worked on AI, particularly beyond reactive states. But waiting for more than a minute each time the computer needed to make a move was not acceptable, or remotely fun. Especially when it would sometimes die, because it would not take risks.

    The risk taking problem was easy to solve - if you treat flipped cards as jokers, the computer will appear to take ‘guesses’ - this does create almost the opposite effect, as finding 5 jokers in a row, the computer assumes it is a Royal Flush, and always takes the shot. But it places the AI in a state where it can play against itself indefinitely.

    To get any use out of it, however, the speed issue needs to be fixed. The goal was to allow the game to run at the target framerate consistently, so any on-screen effects were not blocked by the CPU spikes. To measure this, I placed an animated poker chip on the screen, so I could see visually how things looked as well as reading the metric.

    Unity 5 brought the profiling tools to the public, this was a great chance to use them, and was another example of using a known project, to test new tools. The basics were pretty simple, play the game, and watch the performance graph, when it spikes, you can break down your function calls, and see how much time you’re wasting.

    Caching helped a lot, I was calling lots of functions repeatedly sometimes 4 or 5 times for each walker, for 11 hands, and 17,000 possible walks, none of these looked slow, but running them millions of times was causing me a huge hit. The second big loss of speed was using Collections, lists and dictionaries are convenient to work with, but come with a lot of baggage. I took each function and rewrote it to work with pure, fixed size arrays. This gained me a huge speed increase.

    Finally, a rework of the logic - it dawned on me that the original design for AI was flawed, there can only be one possible hand for each walk, and each walk is a hand (even if it’s just a high-card). So rather than regenerating the walks ever turn, I generated the finite set of walks, and tested the current hand of each. This got the processing time down to a fraction of a second, perfectly acceptable to play against as a human, I was wasting more time animating cards than running AI. But it still caused a glitch.

    Rather than go back down the complicated route of threading, I built a quick hack -

    private float maxRun = 1.0f / 100f;
    
    float frameStart = UnityEngine.Time.realtimeSinceStartup;
    float realTime = UnityEngine.Time.realtimeSinceStartup;
    int position = 0;
    
    while (realTime - frameStart < maxRun) {
        walks[position].GetHand()
        position++;
        realTime = UnityEngine.Time.realtimeSinceStartup;
    }
    

    Basically, at every frame, grab the start time, and start processing the list of walks, until the time elapsed is more than 1/100th of a second, and move on, and come back to that point next frame. The result is spikes in CPU usage, but no noticable frame rate drop (at 60fps). My spinning poker chip span smoothly through the whole event. Again, a simple script had done away with the problem with far less drama than more advanced methods.

    The AI is mechanically sound, but needs some tweaking to make it fair, and give it some variance.


  • Tiger Hat

    These entries are going to slow down a bit now - I’ve caught up with current development - so this will become more of a dev-diary than a postmortem.


  • Jammer

    @salmonmoose

    Sorry it took so long but I went to green light and up-voted Poker Kingdoms! In the description it said multiplayer maybe a direction the game is headed, if that does occur, I would be excited to read about implementing that feature into the game! Please, keep us updated on all that happens with this :D


Log in to reply