PHP Game Making Part I: Algorithms and Design Patterns

cornerpicGeek Game

The Rice University MOOC course introducing Python owed part of its popularity to the fact that all of the projects involved game development. One of the first games was based on an old one called “Rock-paper-scissors” that has been revised and updated to Rock-paper-scissors-lizard-Spock. (For those of you who are Big Bang Theory fans, you may have seen it demonstrated on that show.) The game itself is pretty simple. Two players chant “Rock-paper-scissors-lizard-Spock” and as soon as “Spock” is spoken, they throw one of five hand gestures (see image in upper left corner for the five gestures.)

  • Rock – a Fist
  • Spock – Vulcan salute (hand with fingers separated at ring and middle fingers)
  • Paper – Flat hand
  • Lizard – Hand puppet shape with thumb and index finger forming ‘mouth’
  • Scissors – Two fingers in ‘cutting’ position

The winning outcome is determined by the following rules:

  • Scissors cut paper
  • Paper covers rock
  • Rock crushes lizard
  • Lizard poisons Spock
  • Spock dissenigrates scissors
  • Scissors decapitate lizard
  • Lizard eats paper
  • Paper disproves Spock
  • Spock vaporizes rock
  • Rock breaks scissors

Each gesture has two other gestures it can beat and two other gestures that beat it. For example, if a player throws a lizard gesture, it can beat paper and Spock, and it can be beaten by scissors and rock.

The Game in PHP

One of the main things that I came away with from the Python course was a more advanced and simpler way of calculating outcomes; primarily by the use of modular arithmetic. In PHP, some of you may have used the modulus (or modulo) operator (%) in setting up table lines for alternating colors something like the following algorithm:

$alternate = $counter % 2;
if($alternate)
{
  $shade = $dark;
}
else
{
  $shade = $light;
}
$alternate ++;

When a program employs modulus 2 (% 2) all outcomes are either 0 or 1, which translate to Boolean False and True, respectively. However, more can be done with modular arithmetic than alternate background shading in output.

To get started, take a look at Figure 1. Each of the gestures can defeat the two gestures counter clock-wise and is defeated by the two gestures clockwise of the gesture. For example, paper can defeat Spock and rock, but it is defeated by lizard and scissors.

Figure 1: Circle of wins and losses

Figure 1: Circle of wins and losses

Notice that each gesture has a number associated with it. That number will be used in determining the outcome. In this post I’d like to get started with the game playing against the computer. However, this being PHP, I’d like to develop a game two players can play against one another in future posts. (By the way, more than two players can play this game at the same time, but it gets cumbersome, and so throughout this series, we’ll just be using two players. Before going further, though, try out your luck against the computer:
Play

The moves of each player (you and the computer) is expressed in numbers associated with the circle. (Click below to continue.)

Calculating a Winner

Determining the winner in Python is easy using the following algorithm (shown using the numeric values in Figure 1):

?View Code PYTHON
    result= player_number - comp_number
    finalresult=result % 5
    if finalresult==1 or finalresult==2:
        print "Player wins!"
    elif finalresult > 2:
        print "Computer wins!"
    else:
        print "Player and computer tie!"

Guess what? The modulus operators in PHP and Python are different! For, example:

-4 % 5
Python = 1
PHP = -4

-3 % 5
Python = 2
PHP = -3

So, after trying every kind of modulus fix-up I could dream up, I was unable to get it to work based on the algorithm learned with Python. So, I added a class that generated the win/loss conditions. The algorithm was not pretty, and I’ve left it blank in the listing to avoid embarrassment. (Work out your own elegant solution and send it in through the Comments, and in Part II, we’ll see how to use a State Machine (State design pattern) to solve the problem.)

Throwing a Gesture

For both the computer and the UI, throwing one of the first gestures was easy to develop. Figure 2 shows the basic class diagram for the OOP setup used:

Figure 2: Class diagram for simple OOP RPSLS

Figure 2: Class diagram for simple OOP RPSLS

The HTML form data are all entered with radio buttons. So a single name can be used for all of the different gestures available in Rock, Paper, Scissors, Lizard, Spock (R-P-S-L-S.) In this example, all of the radio buttons share the name “move.”

<!doctype html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="rpsls.css">
<meta charset="UTF-8">
<title>Rock, paper, scissors, lizard, Spock</title>
</head>
<body>
<h2>Computer Challenge</h2>
<form action="Client.php" method="post" name="rpsls">
  <input type="radio" name="move" value="0" id="rock">
  <label for="rock">Rock</label>
  <br />
  <input type="radio" name="move" value="1" id="spock">
  <label for="spock">Spock</label>
  <br />
  <input type="radio" name="move" value="2" id="paper">
  <label for="paper">Paper</label>
  <br />
  <input type="radio" name="move" value="3" id="lizard">
  <label for="lizard">Lizard</label>
  <br />
  <input type="radio" name="move" value="4" id="scissors">
  <label for="scissors">Scissors</label>
  <p />
  <input type="submit" value="Make your move" name="go">
</form>
</body>
</html>

The important attribute in the HTML listing is the value passed. Note that all values conform to those in Figure 1. So, the Lizard gesture, for example, is assigned a value of 3.

The Client

The Client class called by the HTML form acts very much like a Client in that most of the work is done by making requests to other classes. The class itself gathers up the (human) Player’s move from the HTML form data ($_POST[‘move’]), requests a move from the Computer class, and then places the two moves in arguments and makes a request from the WinCalculator class to compare the two moves and determine the winner.

<?php
function __autoload($class_name)
{
    include $class_name . '.php';
}
class Client
{
    private $move;
    private $computerMove;
    private $winCalc;
 
    public function __construct()
    {
        if(isset($_POST['go']))
        {
            $this->move=$_POST['move'];
            echo "Player move: $this->move <br />";
        }
        $computer = new Computer();
        $this->computerMove=$computer->computerMakeMove();
        echo "Computer move: $this->computerMove <br />";
        $this->winCalc = new WinCalculator();
        $this->winCalc->calcWin($this->move, $this->computerMove);
    }
}
$worker = new Client();
?>

As you can see in the Client code, two lines make the request for the computer’s move. It instantiate a Computer instance and then uses the Computer’s computerMakeMove() method to get it’s move.

The Computer Move

The computer’s move is based on a random number between 0 and 4. An instance of the Computer object generates a value and returns it to the requesting Client.

<?php
class Computer
{
    private $throw;
 
    public function computerMakeMove()
    {
        $this->throw=rand(0,4);
        return $this->throw;
    } 
}
?>

The Computer class is a good example of the OOP principle that a class should only have a single responsibility. After calculating the computer’s move, it reruns it and it’s job is done.

The WinCalculator

After finding that the elegant Python modulus solution would not work in PHP, I tried to find an equally elegant algorithm using modular arithmetic in PHP to affect a solution but was unable to do so. So I put together a kludge that strong-armed the solution into submission and used it. In the back of my mind, I am certain that some simple, elegant PHP solution exists, but I have been unable to find it. (I’m hoping that one of you readers will be able to do so and complete the following class with a classy solution.)

<?php
class WinCalculator
{
    private $move;
    private $computerMove;
 
    public function calcWin($player,$computer)
    {
        $this->move = $player;
        $this->computerMove = $computer;     
 
       //Create your own algorithm
       //Use echo statements to display winner/tie
    }   
}
?>

As you can see from pressing the Play button, the solution works, but it was so ugly, that I could not bring myself to display it on this blog. I’ve started the WinCalculator class with the calcWin($player,$computer) method. The argument values represent values between 0 and 4 of the available moves in R-P-S-L-S. See if you can determine how to find the solution without using sledge hammer coding. Then go on to Part II and the State Machine!

Share

Copyright © 2013 William Sanders. All Rights Reserved.

0 Responses to “PHP Game Making Part I: Algorithms and Design Patterns”


  • No Comments

Leave a Reply