Archive

Posts Tagged ‘code’

ActionScript 3 Dice Poker Hand Evaluator

August 28, 2008 5 comments

So, here is a class I wrote today. Jesse Freeman asked me to do this project, so I did. He showed me the approach that this class uses for being a singleton.

/** 
 * <p>Original Author:  aidan coyne</p>
 * <p>Class File: PokerLogic.as
 * 
 * <p>Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:</p>
 * 
 * <p>The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.</p>
 * 
 * <p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.</p>
 * 
 * <p>Licensed under The MIT License</p>
 * <p>Redistributions of files must retain the above copyright notice.</p>
 *
 * <p>Revisions<br/> 
 * 0.1  Initial version Aug 28, 2008</p>
 *
 */
package //com.wordpress.raptros 
{
    /** written by (raptros-v76) Aidan Coyne while working at @radical.media.
    */

    //import flash.display.Sprite; //this isn't actually a sprite.

    /** Logic singleton for a simple poker dice game.
    *   At first I intended to do a lookup table system
    *   but I soon learned I would have to hand write every combination.
    *   No. Instead, I did this.
    */
    public class PokerLogic //extends Sprite //not anymore!
    {
        private static var __instance:PokerLogic;
        private static var __primes:Array = new Array(2, 3, 5, 7, 11, 13);

        /** this is supposed to be a singleton
         *
         */
        public function PokerLogic(enforcer:SingletonEnforcer)
        {
        }
        
        public static function get instance():PokerLogic //use this to get an`instance of PokerLogic.
        {                     
            if(PokerLogic.__instance == null) 
            {
                PokerLogic.__instance = new PokerLogic(new SingletonEnforcer());
            }
            return PokerLogic.__instance;
        }

        /** @param hand1 array containing dice rolls
          *  @param hand2 array containing dice rolls
          *  @return 1 for hand1, 2 for hand 2, 0 if tied
          */
        public function compareHands(hand1:Array, hand2:Array):int
        {
            var rank1:Object = rankHand(hand1);
            var rank2:Object = rankHand(hand2);
            if (rank1.rank == rank2.rank)
                return 0;
            else if (rank1.rank > rank2.rank)
                return 1;
            else 
                return 2;
        }

        /** @param hand array containing dice rolls
        *  @return an object ranking the hand.
        *  first number (object.rank) will be between 16 and 6 hundred million
        * under 100:high card; 1000 to 7000: 1 pair
        * 10,000 to 70,000: 2 pairs; 100,000 to 700,000; 3 of a kind
        * 1,000,000 to 7,000,000: full house; 8,000,000 or 9,000,000: straight
        * 10,000,000 to 70,000,000: 4 of a kind;
        * 100,000,000 to 600,000,000: 5 of a kind.
        * second number (object.type) see findHandType
        */
        public function rankHand(hand:Array):Object
        {
            //count number of each type of card
            var counts:Array = new Array(0, 0, 0, 0, 0, 0);
            for each (var card:int in hand)
            {
                counts[card - 1]++;
            }
            var type:int=findHandType(counts);
            var rank:int=0;
            switch (type)
            {
                case 0: //high card
                    for (card=0; card < counts.length; card++)
                    {
                        //in high card, there are no repeats
                        if(counts[card] == 1)
                            rank+=card;
                    }

                break;
                case 1: //1 pair
                    rank=rankOnePair(counts);
                break;
                case 2: //2 pairs
                    rank=rankTwoPairs(counts);
                break;
                case 3: //3 of a kind
                    rank=rankThree(counts);
                break;
                case 4: //full house
                    rank=rankFullHouse(counts);
                break;
                case 5: //straight
                    rank=rankStraight(counts);
                break;
                case 6: //4 of a kind
                    rank=rankFour(counts);
                break;
                case 7: //5 of a kind
                    rank=rankFive(counts);
                break;
            }
			return {rank:rank, type:type};
        }
        /** finds the type of the hand: (going from 0 to 7)
        {high card, 1 pair, 2 pair, 3kind, fullhouse, straight, 4kind, 5kind}
        */
        private function findHandType(counts:Array):int
        {
            var flags:Array= new Array(1, 0, 0, 0, 0, 0, 0, 0);
            var ones:int=0;
            for (var die:int = 1; die <= counts.length; die++)
            {
                var diceCount:int = counts[die-1];
                switch(diceCount)
                {
                    case 1:
                        ones++;
                    break;
                    case 2:
                        if (flags[1] > 0)
                            flags[2]++;
                        if (flags[3] > 0)
                            flags[4]++;
                        flags[1]++;
                    break;
                    case 3:
                        if (flags[1] > 0)
                            flags[4]++;
                        flags[3]++;
                    break;
                    case 4:
                        flags[6]++;
                    break;
                    case 5:
                        flags[7]++;
                    break;
                }
            }
            //test for a straight
            if (ones == 5)
			{
				if (counts[0] == 0 || counts[counts.length -1] == 0)
	                flags[5]++;
			}
            for (var flag:int = flags.length - 1; flag >= 0; flag--)
            {
                if (flags[flag] > 0)
				{
                    return flag;
				}
            }
            return -1; //should not be reached. might be a good idea to actually test for...
        }
        private function rankOnePair(counts:Array):int
        {
            var rank:int=0;
            var multi:int=1;
            //using the primes trick, plus knowledge that non-pair cards 
            // are unique in hand
            for (var card:int=1; card<=counts.length; card++)
            {
                if (counts[card-1] == 1)
                    multi *= PokerLogic.__primes[card-1];
                else if (counts[card-1] == 2)
                    rank = card * 1000;
            }
            rank += multi;
            return rank;
        }
        private function rankTwoPairs(counts:Array):int
        {
            var rank:int=0;
            var multi:int=0;
            for (var card:int=1; card<=counts.length; card++)
            {
                if (counts[card-1] == 1)
                    multi = card;
                else if (counts[card-1] == 2)
                {
                    if (rank > 0)
                        rank += card*10000;
                    else
                        rank +=card*1000;
                }
            }
            rank += multi;
            return rank;
        }
        private function rankThree(counts:Array):int
        {
            var rank:int=0;
            var multi:int=1;
            for (var card:int=1; card<=counts.length; card++)
            {
                if (counts[card-1] == 1)
                    multi *= PokerLogic.__primes[card-1];
                else if (counts[card-1] == 3)
                    rank = card * 100000;
            }
            rank += multi;
            return rank;
        }
        private function rankFullHouse(counts:Array):int
        {
            var rank:int=0;
            for (var card:int=1; card<=counts.length; card++)
            {
                if (counts[card-1] == 3)
                    rank+=card*1000000;
                else if (counts[card-1] == 2)
                    rank+=card*100000;
            }
            return rank;
        }
        private function rankStraight(counts:Array):int
        {
            var rank:int=8000000;
            if (counts[0] == 0)
                rank=9000000;
            return rank;
        }
        private function rankFour(counts:Array):int
        {
            var rank:int=0;
            for (var card:int=1; card<=counts.length; card++)
            {
                if (counts[card-1] == 4)
                    rank+=card*10000000;
                else if (counts[card-1] == 1)
                    rank+=card;
            }
            return rank;
        }
        private function rankFive(counts:Array):int
        {
            var rank:int=0;
            for (var card:int=1; card<=counts.length; card++)
            {
                if (counts[card-1] == 5)
                    rank+=card*100000000;
            }
            return rank;
        }
    }
}
//singleton stuf borrowed from Jesse Freeman over at flashartofwar.com
internal class SingletonEnforcer { }


Here is a test class.
package 
{
	import flash.display.Sprite;

	public class DicePokerTest extends Sprite
	{
		public function DicePokerTest()
		{
			var types:Array = new Array("High Card", "One Pair", "Two Pair", "Three of a Kind", "Full House", "Straight", "Four of a Kind", "Five of a Kind");
			var logic:PokerLogic=PokerLogic.instance;
			for (var run:Number=0; run < 5; run++)
			{
				trace("Test " + run);
				var hand1:Array = makeRandomHand();
				var hand2:Array = makeRandomHand();
				var rank1:Object = logic.rankHand(hand1);
				var rank2:Object = logic.rankHand(hand2);
				trace("Hand 1: " + hand1 +" has value: " + rank1.rank + ", and is a " + types[rank1.type]);
				trace("Hand 2: " + hand2 +" has value: " + rank2.rank + ", and is a " + types[rank2.type]);

				var winner:Number=logic.compareHands(hand1, hand2);
				trace("Winner is hand"+winner);
			}

		}

		private function makeRandomHand():Array
		{
			var hand:Array = new Array(diceRoll(), diceRoll(), diceRoll(), diceRoll(), diceRoll());
			return hand;
		}
		private function diceRoll():int
		{
			return ((Math.random()*1000)%6)+1;
		}
	}
}

Enjoy.

Follow

Get every new post delivered to your Inbox.