<?php
include_once("cardgamespage.class.php");
include_once("cards.class.php");
class GermanWhist extends CardGamesPage
{ var $pack;
var $hands = array();
var $computer = 0;
var $player = 1;
var $trumps = 0;
var $toplay = 0;
var $trickcount = 0;
var $trickswon = array(0=>0, 1=>0);
var $pagename = "gwhist.php";
var $currentcards = array();
var $playererror = "";
var $computererror = "";
var $packfolder = "big1";
function GermanWhist() // constructor
{ $this->CardGamesPage();
$this->title = "German Whist";
$this->css[] = "gwhist.css";
$this->js[] = "gwcardclick.js";
$this->breadcrumbs->AddCrumb("gwhist.php", "german whist");
if ($_GET["newgame"])
{ $this->NewGame();
} else
{ if ($this->GetFromSession())
{ if (count($this->currentcards) == 2)
{ if ($_GET["nexttrick"])
{ $this->FinaliseTrick();
}
} else
{ if ($_GET["cgo"])
{ $this->ComputerPlay();
} else
{ if ($_POST["ycard"])
{ $this->PlayerPlay();
}
}
}
} else
{ $this->NewGame();
}
}
} // end of fn GermanWhist (constructor)
function NewGame()
{ // first deal pack
unset($_SESSION["cards"]["gw"]);
$this->pack = new Cards($this->packfolder);
$this->pack->GetCards();
$this->pack->Shuffle();
$this->hands[0] = new Cards($this->packfolder);
$this->hands[1] = new Cards($this->packfolder);
// now deals from pack
for ($i = 1; $i <= 13; $i++)
{ $this->hands[0]->AddCard($this->pack->TakeCard());
$this->hands[1]->AddCard($this->pack->TakeCard());
}
$this->hands[0]->Sort();
$this->hands[1]->Sort();
$trumpcard = $this->pack->ShowCard();
$this->trumps = $trumpcard["suit"];
$this->toplay = rand(0, 1);
// now save to session
$this->SaveToSession();
} // end of fn NewGame
function SaveToSession()
{ $_SESSION["cards"]["gw"] =array("pack"=>$this->pack->cards,
"hands"=>array(0=>$this->hands[0]->cards, 1=>$this->hands[1]->cards),
"toplay"=>$this->toplay,
"trickcount"=>$this->trickcount,
"trumps"=>$this->trumps,
"currentcards"=>$this->currentcards,
"trickswon"=>$this->trickswon);
} // end of fn SaveToSession
function GetFromSession()
{ if ($_SESSION["cards"]["gw"])
{ foreach ($_SESSION["cards"]["gw"]["hands"] as $i=>$hand)
{ $this->hands[$i] = new Cards($this->packfolder);
foreach ($hand as $card)
{ $this->hands[$i]->AddCard($card);
}
}
$this->pack = new Cards($this->packfolder);
foreach ($_SESSION["cards"]["gw"]["pack"] as $card)
{ $this->pack->AddCard($card);
}
$this->toplay = $_SESSION["cards"]["gw"]["toplay"];
$this->trickcount = $_SESSION["cards"]["gw"]["trickcount"];
$this->trumps = $_SESSION["cards"]["gw"]["trumps"];
$this->currentcards = $_SESSION["cards"]["gw"]["currentcards"];
$this->trickswon = $_SESSION["cards"]["gw"]["trickswon"];
return true;
}
return false;
} // end of fn GetFromSession
function Display()
{ echo "<p><a href='http://en.wikipedia.org/wiki/German_Whist' target='_blank'>rules of german whist</a> (this game is the variant where only the last 13 tricks are scored)</p>\n<div class='gwTable'>\n<div class='packArea'>\n<div class='trumps'>trumps are ... ",
$this->pack->suits[$this->trumps]["name"], "</div>\n";
if ($this->pack->cards)
{ echo "card ", $this->trickcount + 1, " to play for ...<br />";
$this->pack->DisplayCard($this->pack->ShowCard(), 1);
} else
{ echo array_sum($this->trickswon) < 13 ? "<p>playing tricks</p>" : "<p>game over</p>",
"<p>", (int)$this->trickswon[$this->player], " won by you</p><p>",
(int)$this->trickswon[$this->computer], " won by computer</p>";
}
echo"</div>\n<div class='message'>\n";
if ($this->PlayerToPlay($this->computer) && array_sum($this->trickswon) < 13)
{ $this->ComputerToPlay();
}
echo "</div>\n<div class='playAreaTop'>\n";
$this->ComputerShowPlayed();
echo "</div>\n<div class='playAreaBottom'>\n";
$this->PlayerShowPlayed();
echo "</div>\n<div class='message'>\n";
if ($this->PlayerToPlay($this->player) && array_sum($this->trickswon) < 13)
{ $this->YouToPlay();
}
echo "</div>\n</div>\n";
if ($this->hands[$this->player]->cards)
{ $this->hands[$this->player]->DisplayInSuits((count($this->currentcards)) < 2 && $this->PlayerToPlay($this->player));
}
$this->NewGameLink();
// $this->hands[$this->computer]->DisplayInSuits();
} // end of fn DisplayTable
function NewGameLink()
{ echo "<p><a href='", $this->pagename, "?newgame=1'>new game</a></p>\n";
} // end of fn NewGameLink
function ComputerShowPlayed()
{ if ($this->computererror)
{ echo $this->computererror;
} else
{ if ($card = $this->currentcards[$this->toplay == $this->computer ? 0 : 1])
{ $this->hands[$this->computer]->DisplayCard($card);
}
}
} // end of fn ComputerShowPlayed
function PlayerShowPlayed()
{ if ($this->playererror)
{ echo $this->playererror;
} else
{ if ($card = $this->currentcards[$this->toplay == $this->player ? 0 : 1])
{ $this->hands[$this->player]->DisplayCard($card);
}
}
} // end of fn PlayerShowPlayed
function ComputerToPlay()
{ if (count($this->currentcards) == 2)
{ $this->NextTrickLink();
} else
{ echo "<a href='", $this->pagename, "?cgo=1'>computer to play</a>\n";
}
} // end of fn ComputerToPlay
function YouToPlay()
{ if (count($this->currentcards) == 2)
{ $this->NextTrickLink();
} else
{ echo "<form class='yourgo' action='", $this->pagename,
"' method='POST'>you to play ...\n<select name='ycard' id='ycard'>\n";
foreach ($this->hands[$this->player]->cards as $card)
{ echo "<option value='", $card["suit"], ":", $card["number"], "'>",
$this->hands[$this->player]->CardName($card), "</option>\n";
}
echo "</select>\n<input type='submit' value='play' />\n</form>\n";
}
} // end of fn YouToPlay
function NextTrickLink()
{ echo "won by ",
$this->WhoWon() == $this->player ? "you" : "computer",
" ... <a href='", $this->pagename, "?nexttrick=1'>next trick</a>\n";
} // end of fn NextTrickLink
function TryToWin()
{ if ($this->pack->cards)
{ // playing for pack
$cardPlayFor = $this->pack->ShowCard();
if ($cardPlayFor["suit"] == $this->trumps)
{ return true;
} else
{ return $cardPlayFor["number"] > 10;
}
} else
{ // playing for tricks now so try to win
return true;
}
} // end of fn TryToWin
function ComputerPlay()
{ // check that it is the computer's go
if ($this->PlayerToPlay($this->computer))
{ // check if computer wants to win trick
$tryToWin = $this->TryToWin();
if (count($this->currentcards) == 1)
{ // then following
$possible = array();
$cardord = -1;
// check for follwing suit
foreach ($this->hands[$this->computer]->cards as $cardordcheck=>$cardcheck)
{ if ($cardcheck["suit"] == $this->currentcards[0]["suit"])
{ $possible[] = $cardordcheck;
}
}
if (!$possible) // i.e. none of suit
{ $cantfollow = true;
foreach ($this->hands[$this->computer]->cards as $cardordcheck=>$cardcheck)
{ if ($tryToWin || ($cardcheck["suit"] != $this->trumps))
{ $possible[] = $cardordcheck;
if ($cardcheck["suit"] == $this->trumps)
{ $cantrump = true;
}
}
}
if (!$possible) // i.e. none of suit and only trumps
{ foreach ($this->hands[$this->computer]->cards as $cardcheckord=>$cardcheck)
{ $possible[] = $cardcheckord;
}
}
}
$possiblecards = array();
foreach ($possible as $possord)
{ $possiblecards[$possord] = $this->hands[$this->computer]->cards[$possord];
}
if ($tryToWin)
{ if ($cantrump)
{ // play lowest trump
$lowcard = 15;
$cardord = -1;
foreach ($possiblecards as $pcardord=>$pcard)
{ if ($pcard["suit"] == $this->trumps)
{ if ($pcard["number"] < $lowcard)
{ $lowcard = $pcard["number"];
$cardord = $pcardord;
$card = $pcard;
}
}
}
} else
{ if ($cantfollow)
{ // cant win so play lowest card
$card = $possiblecards[$cardord = $this->BestCard($possiblecards, 0)];
} else
{ // must have just suit so try to win
foreach ($possiblecards as $pcardord=>$pcard)
{ if ($pcard["number"] > $this->currentcards[0]["number"])
{ $cardord = $pcardord;
$card = $pcard;
}
$lowcard = $pcard;
$lowcardord = $pcardord;
}
if (!$card) // i.e. cant win
{ $cardord = $lowcardord;
$card = $lowcard;
}
}
}
} else
{ // play weakest card
$card = $possiblecards[$cardord = $this->BestCard($possiblecards, false)];
}
if ($cardord < 0)
{ $card = $possiblecards[$cardord = $possible[rand(0, count($possible) - 1)]];
}
return $this->PlayCard($card, $cardord, 1, $this->computer);
} else
{ // computer has first go so any card is valid
$cardord = -1;
if ($this->pack->cards)
{ //exclude trumps if still playing for pack
$cardstouse = array();
foreach ($this->hands[$this->computer]->cards as $ctuord=>$ctu)
{ if ($ctu["suit"] != $this->trumps)
{ $cardstouse[$ctuord] = $ctu;
}
}
if (!$cardstouse)
{ $cardstouse = $this->hands[$this->computer]->cards;
}
} else
{ $cardstouse = $this->hands[$this->computer]->cards;
}
$card = $cardstouse[$cardord = $this->BestCard($cardstouse, $tryToWin)];
if ($cardord < 0)
{ $card = $this->hands[$this->computer]->cards[$cardord = rand(0, count($this->hands[$this->computer]->cards) - 1)];
}
return $this->PlayCard($card, $cardord, 0, $this->computer);
}
}
return false;
} // end of fn ComputerPlay
function BestCard($cards, $getbest = 1)
{
$bestnum = $getbest ? 0 : 15;
$bestord = -1;
foreach ($cards as $cardord=>$card)
{ if ($getbest)
{ if ($card["number"] > $bestnum)
{ $bestord = $cardord;
$bestnum = $card["number"];
}
} else
{ if ($card["number"] < $bestnum)
{ $bestord = $cardord;
$bestnum = $card["number"];
}
}
}
return $bestord;
} // end of fn BestCard
function PlayerPlay()
{ // check that it is the player's go
if ($this->PlayerToPlay($this->player))
{ $post = explode(":", $_POST["ycard"]);
foreach ($this->hands[$this->player]->cards as $cardord=>$card)
{ if ($card["suit"] == $post[0] && $card["number"] == $post[1])
{ if (count($this->currentcards) == 1)
{ // then following
$suit = $this->currentcards[0]["suit"];
if ($this->currentcards[0]["suit"] != $post[0])
{ // then check for empty suit in hand
foreach ($this->hands[$this->player]->cards as $checkcard)
{ if ($checkcard["suit"] == $this->currentcards[0]["suit"])
{ $this->playererror = "you must follow suit";
return false;
}
}
}
// valid card
return $this->PlayCard($card, $cardord, 1, $this->player);
} else
{ if (!$this->currentcards)
{ // then leading and any card works
return $this->PlayCard($card, $cardord, 0, $this->player);
}
}
break;
}
}
}
return false;
} // end of fn PlayerPlay
function PlayCard($card, $cardord = 0,$go = 0, $player = 0)
{ unset($this->hands[$player]->cards[$cardord]);
$this->hands[$player]->Compact();
$this->currentcards[$go] = $card;
$this->SaveToSession();
return true;
} // end of fn PlayCard
function PlayerToPlay($player = 0)
{ return (($this->toplay + count($this->currentcards)) % 2) == $player;
} // end of fn PlayerToPlay
function WhoWon()
{ if ($this->currentcards[0]["suit"] == $this->currentcards[1]["suit"])
{ $go = $this->currentcards[0]["number"] > $this->currentcards[1]["number"] ? 0 : 1;
} else
{ // check for follower being trumps
$go = $this->currentcards[1]["suit"] == $this->trumps ? 1 : 0;
}
return ($this->toplay + $go) % 2;
} // end of fn WhoWon
function FinaliseTrick()
{ $this->toplay = $this->WhoWon();
$this->trickcount++;
$this->currentcards = array();
if ($this->pack->cards)
{ // then still playing for pack
$this->hands[$this->toplay]->AddCard($this->pack->TakeCard());
$this->hands[1 - $this->toplay]->AddCard($this->pack->TakeCard());
$this->hands[0]->Sort();
$this->hands[1]->Sort();
} else
{ // we are now playing tricks
$this->trickswon[$this->toplay]++;
}
$this->SaveToSession();
} // end of fn FinaliseTrick
} // end of class defn GermanWhist
?>
<?php
class Cards
{ var $cards = array();
var $suits = array(0 => array("name"=>"clubs"), 1 => array("name"=>"diamonds"), 2 => array("name"=>"hearts"), 3 => array("name"=>"spades"));
var $cardWidth = 40;
var $cardTopHeight = 15;
var $cardFullHeight = 50;
var $cardfolder = "basic";
var $numbers = array(2=>array("name"=>"2", "initial"=>"2", "value"=>2),
3=>array("name"=>"3", "initial"=>"3", "value"=>3),
4=>array("name"=>"4", "initial"=>"4", "value"=>4),
5=>array("name"=>"5", "initial"=>"5", "value"=>5),
6=>array("name"=>"6", "initial"=>"6", "value"=>6),
7=>array("name"=>"7", "initial"=>"7", "value"=>7),
8=>array("name"=>"8", "initial"=>"8", "value"=>8),
9=>array("name"=>"9", "initial"=>"9", "value"=>9),
10=>array("name"=>"10", "initial"=>"T", "value"=>10),
11=>array("name"=>"Jack", "initial"=>"J", "value"=>11),
12=>array("name"=>"Queen", "initial"=>"Q", "value"=>12),
13=>array("name"=>"King", "initial"=>"K", "value"=>13),
14=>array("name"=>"Ace", "initial"=>"A", "value"=>14));
function Cards($pack = "") // constructor
{ if ($pack)
{ $this->GetPackConfig($pack);
}
} // end of fn Cards (constructor)
function GetPackConfig($pack)
{ $this->cardfolder = $pack;
if ($fhandle = fopen($_SERVER["DOCUMENT_ROOT"] . "/pcards/" . $pack . "/pack.cfg", "r"))
{ $parameters = array();
while ($line = fgets($fhandle))
{ if ($row = explode(":", trim($line)))
{ $parameters[$row[0]] = $row[1];
}
}
if ($parameters["cardWidth"])
{ $this->cardWidth = $parameters["cardWidth"];
}
if ($parameters["cardFullHeight"])
{ $this->cardFullHeight = $parameters["cardFullHeight"];
}
if ($parameters["cardTopHeight"])
{ $this->cardTopHeight = $parameters["cardTopHeight"];
}
fclose($fhandle);
}
} // end of fn GetPackConfig
function SaveHand($hand = 0)
{ if (!is_array($_SESSION["cards"]["hands"])) $_SESSION["cards"]["hands"] = array();
$_SESSION["cards"]["hands"][$hand] = array();
foreach ($this->cards as $card)
{ $_SESSION["cards"]["hands"][$hand][] = $card;
}
} // end of fn SaveHand
function EmptyCards()
{ $this->cards = array();
} // end of fn Empty
function ShowCard()
{ if ($this->cards)
{ return $this->cards[count($this->cards) - 1];
} else
{ return array();
}
} // end of fn ShowCard
function TakeCard()
{ if ($this->cards)
{ return array_pop($this->cards);
} else
{ return array();
}
} // end of fn TakeCard
function AddCard($card)
{ $this->cards[] = $card;
} // end of fn AddCard
function GetCards($hand = -1)
{ $this->EmptyCards();
if ($hand = -1)
{ // initialise as sorted full deck
for ($suit = 0; $suit < 4; $suit++)
{ for ($number = 14; $number > 1; $number--)
{ $this->cards[] = array("suit"=>$suit, "number"=>$number);
}
}
} else
{ // get from session
if (is_array($_SESSION["cards"]["hands"][$hand]))
{ foreach ($_SESSION["cards"]["hands"][$hand] as $card)
{ $this->cards[] = array("suit"=>$card["suit"], "number"=>$card["number"]);
}
}
}
} // end of fn GetCards
function DisplayInLine()
{ echo "<div class='suit'>\n";
foreach ($this->cards as $order=>$card)
{ $this->DisplayCard($card, !$this->cards[$order + 1]);
}
echo "</div>\n";
} // end of fn DisplayInLine
function DisplayInSuits($doJS = false)
{ echo "<div class='suits'>\n",
$doJS ? "<div class='suitsHeader'>click on card to play</div>" : "",
"<div class='suit'>\n";
foreach ($this->cards as $order=>$card)
{ if (isset($current_suit))
{ if ($current_suit != $card["suit"])
{ $current_suit = $card["suit"];
echo "</div>\n<div class='suit'>\n";
}
} else
{ $current_suit = $card["suit"];
}
$this->DisplayCard($card, $this->cards[$order + 1]["suit"] !== $current_suit, $doJS);
}
echo "</div>\n<br />\n</div>";
} // end of fn DisplayInSuits
function DisplayCard($card, $full = 1, $doJS = false)
{
echo "<div class='card'><img ";
if ($doJS)
{ echo "onclick='CardClick(\"", $card["suit"], ":", $card["number"], "\");' ";
}
echo "src='/pcards/", $this->cardfolder, "/",
$this->suits[$card["suit"]]["name"],
$this->numbers[$card["number"]]["initial"],
$full ? "" : "_top",
".jpg' alt='", $this->CardName($card), "' width='", $this->cardWidth, "' height='",
$full ? $this->cardFullHeight : $this->cardTopHeight, "'/></div>\n";
} // end of fn DisplayCard
function CardName($card)
{ return $this->numbers[$card["number"]]["name"] . " of "
. $this->suits[$card["suit"]]["name"];
} // end of fn CardName
function Sort()
{ $oldpack = $this->cards;
$this->cards = array();
while ($oldpack)
{ $high = array("suit"=>4, "number"=>0);
$highcard = -1;
foreach($oldpack as $cardnum=>$oldcard)
{ if ($oldcard["suit"] < $high["suit"])
{ $high = $oldcard;
$highcard = $cardnum;
} else
{ if (($oldcard["suit"] == $high["suit"]) && ($oldcard["number"] > $high["number"]))
{ $high = $oldcard;
$highcard = $cardnum;
}
}
}
$this->cards[] = $oldpack[$highcard];
unset($oldpack[$highcard]);
}
} // end of fn Sort
function Compact()
{ $this->cards = $this->CompactCards($this->cards);
} // end of fn Compact
function CompactCards($cards = array())
{ $newcards = array();
foreach ($cards as $oldcard)
{ $newcards[] = $oldcard;
}
return $newcards;
} // end of fn Compact
function Shuffle()
{ $oldpack = $this->cards;
$this->cards = array();
while ($oldpack)
{ $card = rand(0, count($oldpack) - 1);
$this->cards[] = $oldpack[$card];
unset($oldpack[$card]);
// clear oldpack down
$oldpack = $this->CompactCards($oldpack);
}
} // end of fn Shuffle
} // end of class defn Cards
?>