Created
November 14, 2015 04:44
-
-
Save mickelsonm/5c9eee61cfc7137c3bcb to your computer and use it in GitHub Desktop.
Roulette Simulator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Table { | |
protected $bets = []; | |
protected $numbers = [ | |
0 => ['color' => 'green'], | |
1 => ['color' => 'red'], | |
2 => ['color' => 'black'], | |
3 => ['color' => 'red'], | |
4 => ['color' => 'black'], | |
5 => ['color' => 'red'], | |
6 => ['color' => 'black'], | |
7 => ['color' => 'red'], | |
8 => ['color' => 'black'], | |
9 => ['color' => 'red'], | |
10 => ['color' => 'black'], | |
11 => ['color' => 'black'], | |
12 => ['color' => 'red'], | |
13 => ['color' => 'black'], | |
14 => ['color' => 'red'], | |
15 => ['color' => 'black'], | |
16 => ['color' => 'red'], | |
17 => ['color' => 'black'], | |
18 => ['color' => 'red'], | |
19 => ['color' => 'red'], | |
20 => ['color' => 'black'], | |
21 => ['color' => 'red'], | |
22 => ['color' => 'black'], | |
23 => ['color' => 'red'], | |
24 => ['color' => 'black'], | |
25 => ['color' => 'red'], | |
26 => ['color' => 'black'], | |
27 => ['color' => 'red'], | |
28 => ['color' => 'black'], | |
29 => ['color' => 'black'], | |
30 => ['color' => 'red'], | |
31 => ['color' => 'black'], | |
32 => ['color' => 'red'], | |
33 => ['color' => 'black'], | |
34 => ['color' => 'red'], | |
35 => ['color' => 'black'], | |
36 => ['color' => 'red'], | |
]; | |
protected $lastNumber = -1; | |
public function spin() { | |
$this->lastNumber = mt_rand(0, 36); | |
return $this->lastNumber; | |
} | |
public function addBet(Bet $bet) { | |
$this->bets[] = $bet; | |
} | |
public function getBets() { | |
return $this->bets; | |
} | |
public function removeBets() { | |
$this->bets = []; | |
} | |
public function getNumberAttributes($number) { | |
return $this->numbers[$number]; | |
} | |
public function getLastNumber() { | |
return $this->lastNumber; | |
} | |
} | |
class Bet { | |
const BET_NUMBER = 'number', | |
BET_COLOR = 'color'; | |
protected $player; | |
protected $type; | |
protected $params; | |
protected $amount; | |
public function __construct(Player $player, $type, $params, $amount) { | |
$this->player = $player; | |
$this->type = $type; | |
$this->params = $params; | |
$this->amount = $amount; | |
} | |
public function getType() { | |
return $this->type; | |
} | |
public function getAmount() { | |
return $this->amount; | |
} | |
public function getParams() { | |
return $this->params; | |
} | |
public function getPlayer() { | |
return $this->player; | |
} | |
} | |
abstract class Player { | |
protected $name; | |
protected $cash = 0; | |
protected $lastBet; | |
protected $lastBetWon; | |
protected static $baseCash = 100; | |
public function __construct($name, $cash) { | |
$this->name = $name; | |
$this->addCash($cash); | |
} | |
public function resetCash() { | |
$this->cash = self::$baseCash; | |
} | |
public function getCash() { | |
return $this->cash; | |
} | |
public function addCash($amount) { | |
$this->cash += $amount; | |
} | |
public function bet(Table $table) { | |
$bet = $this->getBet($table); | |
if ($bet->getAmount() > $this->cash) { | |
return false; | |
} | |
$this->cash -= $bet->getAmount(); | |
$this->lastBet = $bet; | |
$table->addBet($bet); | |
} | |
public function setLastBetWon($win) { | |
$this->lastBetWon = $win; | |
} | |
/** | |
* | |
* @param Table $table | |
* @return Bet | |
*/ | |
public abstract function getBet(Table $table); | |
public function getName() { | |
return $this->name; | |
} | |
public function __toString() { | |
return 'Player [' . $this->name . "]: " . '$' . $this->cash . ''; | |
} | |
} | |
class Croupier { | |
public function handleRound(Table $table) { | |
$bets = $table->getBets(); | |
$number = $table->spin(); | |
foreach ($bets as $bet) { | |
/* @var $bet Bet */ | |
if ($this->betWins($table, $bet, $number)) { | |
$bet->getPlayer()->setLastBetWon(true); | |
$bet->getPlayer()->addCash($this->getReturn($bet)); | |
} | |
} | |
$table->removeBets(); | |
} | |
public function getReturn(Bet $bet) { | |
switch ($bet->getType()) { | |
case Bet::BET_COLOR: | |
return $bet->getAmount() * 2; | |
break; | |
case Bet::BET_NUMBER: | |
return $bet->getAmount() * 36; | |
break; | |
default: | |
return 0; | |
} | |
} | |
public function betWins(Table $table, Bet $bet, $number) { | |
$params = $bet->getParams(); | |
$attr = $table->getNumberAttributes($number); | |
switch ($bet->getType()) { | |
case Bet::BET_NUMBER: | |
return $number === $params['number']; | |
case Bet::BET_COLOR: | |
return $params['color'] === $attr['color']; | |
default: | |
return false; | |
} | |
} | |
} | |
class Simulator { | |
protected $players = []; | |
protected $croupier; | |
protected $table; | |
protected $playerOutcomes = []; | |
public function __construct(Croupier $croupier, Table $table) { | |
$this->croupier = $croupier; | |
$this->table = $table; | |
} | |
public function addPlayer(Player $player) { | |
$this->players[] = $player; | |
$this->playerOutcomes[$player->getName()] = 0; | |
} | |
public function runSimulation($games = 100000, $rounds = 20) { | |
for ($game = 0; $game < $games; $game++) { | |
foreach ($this->players as $player) { | |
/* @var $player Player */ | |
$player->resetCash(); | |
$startCash = $player->getCash(); | |
for ($round = 0; $round < $rounds; $round++) { | |
$player->bet($this->table); | |
$this->croupier->handleRound($this->table); | |
} | |
$win = $player->getCash() - $startCash; | |
$this->playerOutcomes[$player->getName()] += $win; | |
} | |
} | |
foreach ($this->playerOutcomes as $player => $outcome) { | |
echo 'Player [' . $player . ']: ' . $outcome / $games . "\r\n"; | |
} | |
} | |
} | |
class ColorPlayer extends Player { | |
public function getBet(Table $table) { | |
$nextColor = 'red'; | |
$nextAmount = 2; | |
if ($this->lastBetWon === false) { | |
$nextAmount *= 2; | |
$lastNumber = $table->getLastNumber(); | |
$attr = $table->getNumberAttributes($lastNumber); | |
if ($attr['color'] === 'red') { | |
$nextColor = 'black'; | |
} | |
} | |
return new Bet($this, Bet::BET_COLOR, ['color' => $nextColor], $nextAmount); | |
} | |
} | |
class LastNumberPlayer extends Player { | |
public function getBet(Table $table) { | |
$nextNumber = $table->getLastNumber() > -1 ? $table->getLastNumber() : 1; | |
return new Bet($this, Bet::BET_NUMBER, ['number' => $nextNumber], 2); | |
} | |
} | |
class RandomNumberPlayer extends Player { | |
public function getBet(Table $table) { | |
return new Bet($this, Bet::BET_NUMBER, ['number' => mt_rand(0, 36)], 2); | |
} | |
} | |
class RandomColorPlayer extends Player { | |
protected $colors = ['red', 'black']; | |
public function getBet(Table $table) { | |
return new Bet($this, Bet::BET_COLOR, ['color' => $this->colors[mt_rand(0, 1)]], 2); | |
} | |
} | |
class SingleNumberPlayer extends Player { | |
protected $number = 1; | |
public function setNumber($number) { | |
$this->number = $number; | |
} | |
public function getBet(Table $table) { | |
return new Bet($this, Bet::BET_NUMBER, ['number' => $this->number], 2); | |
} | |
} | |
$sim = new Simulator(new Croupier(), new Table()); | |
$sim->addPlayer(new ColorPlayer('Color', 50)); | |
$sim->addPlayer(new LastNumberPlayer('Number', 50)); | |
$singleNumber = new SingleNumberPlayer('SingleNumber', 50); | |
$singleNumber->setNumber(0); | |
$sim->addPlayer($singleNumber); | |
$sim->addPlayer(new RandomColorPlayer('RandomColor', 50)); | |
$sim->addPlayer(new RandomNumberPlayer('RandomNumber', 50)); | |
$sim->runSimulation(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment