Skip to content

Instantly share code, notes, and snippets.

@mgldev
Created November 16, 2013 12:42
Show Gist options
  • Save mgldev/7499736 to your computer and use it in GitHub Desktop.
Save mgldev/7499736 to your computer and use it in GitHub Desktop.
So I was told about the Lizard and Spock extension to Rock, Paper Scissors and I wanted to see how the current OOP approach would extend to the introduction of the new winning methods and roles.
<?php
class DrawException extends DomainException {}
abstract class Hand {
public function beats(Hand $hand) {
$this->rejectDraw($hand);
return $this->assess($hand);
}
protected abstract function assess(Hand $hand);
public function __toString() {
return get_class($this);
}
public function rejectDraw(Hand $hand) {
if ($hand === $this) {
throw new DrawException('No player wins, round is a draw');
}
}
}
interface Wrappable {}
interface Cuttable {}
interface Bluntable {}
interface Beheadable {}
interface Vapourisable {}
interface Crushable {}
interface Poisonable {}
interface Edible {}
interface Disprovable {}
interface Smashable {}
class Rock extends Hand implements Wrappable {
protected function assess(Hand $hand) {
$retval = ['result' => false, 'method' => null];
switch (true) {
case $hand instanceof Bluntable:
$retval['result'] = true;
$retval['method'] = 'Blunted';
break;
case $hand instanceof Crushable:
$retval['result'] = true;
$retval['method'] = 'Crushed';
break;
}
return $retval;
}
}
class Paper extends Hand implements Cuttable, Edible {
protected function assess(Hand $hand) {
$retval = ['result' => false, 'method' => null];
switch (true) {
case $hand instanceof Wrappable:
$retval['result'] = true;
$retval['method'] = 'Wrapped';
break;
case $hand instanceof Disprovable:
$retval['result'] = true;
$retval['method'] = 'Disproven';
break;
}
return $retval;
}
}
class Scissors extends Hand implements Bluntable, Crushable {
protected function assess(Hand $hand) {
$retval = ['result' => false, 'method' => null];
switch (true) {
case $hand instanceof Cuttable:
$retval['result'] = true;
$retval['method'] = 'Cut to death';
break;
case $hand instanceof Beheadable:
$retval['result'] = true;
$retval['method'] = 'Beheaded';
break;
}
return $retval;
}
}
class Lizard extends Hand implements Beheadable, Crushable {
public function assess(Hand $hand) {
$retval = ['result' => false, 'method' => null];
switch (true) {
case $hand instanceof Poisonable:
$retval['result'] = true;
$retval['method'] = 'Poisoned';
break;
case $hand instanceof Edible:
$retval['result'] = true;
$retval['method'] = 'Eaten';
break;
}
return $retval;
}
}
class Spock extends Hand implements Disprovable, Poisonable {
public function assess(Hand $hand) {
$retval = ['result' => false, 'method' => null];
switch (true) {
case $hand instanceof Smashable:
$retval['result'] = true;
$retval['method'] = 'Smashed';
break;
case $hand instanceof Vapourisable:
$retval['result'] = true;
$retval['method'] = 'Vapourised';
break;
}
return $retval;
}
}
$hands = [
'r' => new Rock,
'p' => new Paper,
'sc' => new Scissors,
'l' => new Lizard,
'sp' => new Spock
];
while (true) {
echo "\n\nChoose hand [r (rock), p (paper), sc (scissors), l (lizard), sp (spock)]: ";
$choices = [
'computer' => array_keys($hands)[rand(0, count($hands) - 1)],
'player' => strtolower(trim(fgets(STDIN)))
];
$computerHand = $hands[$choices['computer']];
$playerHand = $hands[$choices['player']];
echo "Player chose $playerHand\n";
echo "Computer chose $computerHand\n";
try {
$result = $playerHand->beats($computerHand);
if ($result['result']) {
echo sprintf("Player wins, %s beats %s by being %s\n", $playerHand, $computerHand, $result['method']);
} else {
echo sprintf("Computer wins, %s beats %s but I don't know by which method\n", $computerHand, $playerHand);
}
} catch (DrawException $ex) {
echo $ex->getMessage() . "\n";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment