An attempt to clone the video poker machines found in casinos. Try it out here.
This is a little video poker project I created in my spare time. The goal was to make a server-run python virtual deck of cards which clients could talk to. I decided to have the server return a JSON object with the current hand, the client could then query the server with their discard and retrieve the draw. It would also be the server's responsibility to determine whether the hand won.
Later on, I plan to have the server handle bets and winnings.
I've also written an example client for it in HTML/Javascript/JQuery/Ajax. You can try it out here or make a direct call to the back end here.#!/usr/bin/python
import random
import json
import cgi
print "Content-type: text/html"
print
form = cgi.FieldStorage()
suits = ['H', 'D', 'S', 'C']
deck = []
hand = []
draw = False
seed = 0
# create the deck
for suit in suits:
for cval in range(2,15):
deck.append([suit, cval])
# get or generate the seed
if "s" in form:
seed = int(form.getvalue("s"))
else:
seed = random.randint(0,99999999999)
# seed the generator
random.seed(seed)
# shuffle the deck
random.shuffle(deck)
# deal the hand
for i in range(5):
hand.append(deck.pop())
skeep = ""
keep = []
if "d" in form:
draw = True
skeep = form.getvalue("d")
# deal draw
i = 0
for ccard in hand:
if skeep[i] == "O":
hand[i] = deck.pop()
i += 1
class Result:
aPair = False
firstPair = False
secondPair = False
threeKind = False
fourKind = False
fullHouse = False
jacksOrHigher = False
straight = False
flush = False
wintext = ""
nums = []
suits = []
result = Result()
for card in hand:
nums.append(card[1])
suits.append(card[0])
for s in ["H","D","S","C"]:
if suits.count(s) == 5:
result.flush = True
list.sort(nums)
for i in range(2,15):
if nums.count(i) > 1:
result.aPair = True
if nums.count(i) == 4:
result.fourKind = True
if nums.count(i) == 3:
result.threeKind = True
if result.firstPair:
result.fullHouse = True
if nums.count(i) == 2:
if result.threeKind:
result.fullHouse = True
if result.firstPair:
result.secondPair = True
result.firstPair = True
if i > 10:
result.jacksOrHigher = True
if not result.aPair:
if max(nums) - min(nums) == 4:
result.straight = True
result.wintext = "No Win"
if result.jacksOrHigher:
result.wintext = "Jacks or Better"
if result.secondPair:
result.wintext = "Two Pair"
if result.threeKind:
result.wintext = "Three of a Kind"
if result.straight:
result.wintext = "Straight"
if result.flush:
result.wintext = "Flush"
if result.fullHouse:
result.wintext = "Full House"
if result.fourKind:
result.wintext = "Four of a Kind"
if result.straight and result.flush:
result.wintext = "Straight Flush"
# output json
# hand, draw, result
print json.dumps([hand, draw, result.wintext, seed])
var time = 300;
var keep = [true, true, true, true, true];
var seed;
var manseed = false;
function hideHelds() {
$(".heldcard").each(function(i, item) {
$(item).css("visibility","hidden");
});
}
function dealCard(i, card) {
console.log("dealing card... " ) ;
console.log(card);
$("#card" + i).removeClass("back").html(getCard(card[0], card[1]));
try {
document.getElementById("audio").currentTime = 0;
document.getElementById("audio").play();
} catch(err) { console.log("something went wrong with the audio."); }
}
function toggleCard(v) {
var index = v.currentTarget.id.replace("card", "")-1;
keep[index] = !keep[index];
$("#heldcard"+(index+1)).css("visibility",(keep[index]?"hidden":"visible"));
}
function draw() {
var skeep = "";
for (i=0;i<5;i++) {
skeep += keep[i]?"O":"X";
}
deal(skeep);
}
function deal(skeep) {
var url = "/cgi-bin/poker.py";
if(skeep==null) {
keep = [true, true, true, true, true];
toggleLinks(false);
hideHelds();
if(manseed) {
url += "?s=" + $("#manseed").val();
manseed = false;
}
} else {
toggleLinks(true);
console.log("draw. holding: " + skeep);
url += "?s="+seed+"&d="+skeep;
}
console.log("retrieving hand: " + url);
$.getJSON(url, function(data) {
var hand = data[0];
var result = data[2];
var draw = data[1];
var wait = 1;
seed = data[3];
$("#seed").html(seed);
console.log(hand);
$.each(hand, function(i, card) {
if(keep[i] || (!draw)) {
setTimeout("dealCard("+(i+1)+", [\"" + card[0] + "\", " + card[1] + "])", wait * time);
$("#card"+(i+1)).empty().addClass("back");
wait++;
}
});
console.log("Result: " + result);
if((!draw)&&result=="No Win") {
$("#wintext").html("");
} else {
setTimeout("$(\"#wintext\").html(\""+result+"\")", 1300);
}
});
}
function toggleLinks(dealVis) {
$("#drawLink").toggle(!dealVis);
$("#dealLink").toggle(dealVis);
}
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" type="text/javascript"></script>
<script>
if (typeof console == "undefined" || typeof console.log == "undefined") var console = { log: function() {} };
</script>
<link rel="stylesheet" type="text/css" href="css/card.css" />
<script type="text/javascript" src="js/card.js"></script>
<script type="text/javascript" src="js/deal.js"></script>
<style>
body {
background-color: #0009a0;
}
</style>
<script language="javascript">
$(document).ready(function() {
$(".card").bind("click", toggleCard);
$("body").keypress(key);
deal();
});
function key(e) {
console.log(e);
}
</script>
</head>
<body>
<div style="padding: 10px; background-color: #FFF; border: solid 1px #000;">
Developed by Ben Friedland. View a write-up on the code for this <a href="/samples/poker.php">here</a>.
</div>
<div id="heldcard1" class="heldcard">HELD</div>
<div id="heldcard2" class="heldcard">HELD</div>
<div id="heldcard3" class="heldcard">HELD</div>
<div id="heldcard4" class="heldcard">HELD</div>
<div id="heldcard5" class="heldcard">HELD</div>
<div class="clear"></div>
<div id="card1" class="card back"></div>
<div id="card2" class="card back"></div>
<div id="card3" class="card back"></div>
<div id="card4" class="card back"></div>
<div id="card5" class="card back"></div>
<input type="button" id="dealLink" onclick="deal()" value="deal">
<input type="button" id="drawLink" onclick="draw()" value="draw">
<div class="clear"></div>
<div id="wintext" class="wintext"></div>
<audio src="audio/card-flip.mp3" id="audio" preload="auto"></audio>
<script language="javascript">
function replay() {
$("#manseed").val($("#seed").html());
manseed = true;
deal();
}
</script>
<div id="debug" style="border: solid 3px black; background-color: #FFC; padding: 20px;">
<b>Debug Area:</b><br />
Seed used to generate this hand: <span id="seed" style="font-weight: bold;"></span>
[<a href="#" onclick="replay()">replay this hand</a>] <br />
Play a new hand based on the seed: <input type="text" id="manseed">
<input type="button" onclick="manseed=true; deal();" value="play"> <br />
</div>
</body>
</html>
function getCard(suit, val) {
var red = (suit=="H" || suit=="D");
var cval = val;
var csuit;
var royal = false;
switch (suit) {
case "H":
csuit = "♥"
break;
case "D":
csuit = "♦"
break;
case "S":
csuit = "♠"
break;
case "C":
csuit = "♣"
break;
}
switch (val) {
case 11:
cval = "J";
royal = true;
break;
case 12:
cval = "Q";
royal = true;
break;
case 13:
cval = "K";
royal = true;
break;
case 14:
cval = "A";
royal = true;
break;
}
var ret = "<table border=\"0\" width=\"100%\" class=\"" + (red?"red":"") + "\">" +
" <tr>" +
" <td class=\"card-corner\" align=\"center\">" +
" <div class=\"corner-val\">" + cval + "</div>" +
" <div class=\"corner-suit\">" + csuit + "</div>" +
" </td>" +
" <td align=\"right\">" +
" " + (royal?"<img src=\"images/royal/" + cval + ".png\">":"") +
" </td>" +
" </tr>" +
" <tr>" +
" <td colspan=\"2\" align=\"center\" class=\"big-suit\">" +
" " + csuit +
" </td>" +
" </tr>" +
"</table>";
return ret;
}
.heldcard {
width: 107px;
font-size: 22px;
text-align: center;
font-family: sans-serif;
font-weight: bold;
color: FFF;
margin-right: 10px;
float: left;
padding: 10px;
visibility: hidden;
}
.wintext {
width: 107px;
font-size: 22px;
text-align: center;
font-family: sans-serif;
font-weight: bold;
color: FFF;
padding: 10px;
}
.card {
-moz-border-radius: 5px;
border-radius: 5px;
-moz-box-shadow: 3px 3px 0px #000;
-webkit-box-shadow: 3px 3px 0px #000;
box-shadow: 3px 3px 0px #000;
width: 107px;
height: 150px;
background-color: #FFF;
padding: 10px;
font-size: 40px;
float: left;
margin-right: 10px;
cursor: hand;
}
.card table {
font-size: 30px;
font-weight: bold;
}
.card-corner {
font-size: 30px;
line-height: 20px;
width: 20px;
}
.corner-suit {
padding-left: 0px;
padding-top: 5px;
font-size: 25px;
}
.big-suit {
font-size: 90px;
font-weight: 900;
}
.back {
background: url('../images/cardback.gif');
}
.red { color: red; }
.clear { clear: both; }