Paper Climbing Scissors Lizard Spock in PHP

So I am new to PHP and am creating an RPSLS implementation, just to be run on the command line. I have a semi-problem, but I have two problems.

1) The code below doesn't seem to affect the else condition when player 2 hits player one and I can't figure out why?

2) It's an incredibly repetitive set of conventions. What would be a more efficient implementation? I would really like to understand how to do it better.

thank

<?php

// Assign moves to integers (1 = Rock, 2 = Paper, 3 = Scissors, 4 = Lizard, 5 = Spock)
echo 'Welcome to Rock, Paper Scissors, Lizard, Spock';
echo "\n";

// Randomize Moves
$player1 = rand(1, 5);
$player2 = rand(1, 5);

// Declare wins
$rock_wins = array(3, 4);
$paper_wins = array(1, 5);
$scissors_wins = array(2, 4);
$lizard_wins = array(5, 2);
$spock_wins = array(3, 1);

// Conditional logic for wins
if ($player1 == $player2) {
    echo "Tie.";
    echo "\n";
} elseif ($player1 == 1) {
        if (in_array($player2, $rock_wins)) {
            echo "Player 1 wins";
            echo "\n";
        }
} elseif ($player1 == 2) {
    if (in_array($player2, $paper_wins)) {
            echo "Player 1 wins";
            echo "\n";
        }
} elseif ($player1 == 3) {
    if (in_array($player2, $scissors_wins)) {
            echo "Player 1 wins";
            echo "\n";
        }
}
elseif ($player1 == 4) {
    if (in_array($player2, $lizard_wins)) {
            echo "Player 1 wins";
            echo "\n";
        }
}
elseif ($player1 == 5) {
    if (in_array($player2, $spock_wins)) {
            echo "Player 1 wins";
            echo "\n";
        }
} else {
    echo "Player 2 wins";
}

?>

      

+3


source to share


4 answers


You can code your logic in a two dimensional array:

<?php
$play = function ($player1, $player2) {
    $rock = 1;
    $paper = 2;
    $scissors = 3;
    $lizard = 4;
    $spock = 5;
    $matches = array(
        $rock => array($scissor, $lizard),
        $paper => array($rock, $spock),
        $scissors => array($paper, $lizard),
        $lizard => array($spock, $paper),
        $spock => array($scissor, $rock),
    );

    return in_array($player2, $matches[$player1]);
};

// Assign moves to integers (1 = Rock, 2 = Paper, 3 = Scissors, 4 = Lizard, 5 = Spock)
echo 'Welcome to Rock, Paper Scissors, Lizard, Spock';
echo "\n";

// Randomize Moves
$player1 = rand(1, 5);
$player2 = rand(1, 5);

if ($player1 == $player2) {
    echo "Draw!\n";
} else if (Game::play($player1, $player2)) {
    echo "Player 1 wins\n";
} else {
    echo "Player 2 wins\n";
}

      



Obviously, the improvement is endless:

  • you can replace the function with a closure (either a class with a method play

    or a nested function inside a factory function) in a 2d array, so you don't instantiate for every call
  • you can use constants instead of variables for breed, paper, etc.
  • you have to check that the inputs are within valid values, etc.

    <?php
    class Game {
        const ROCK = 1;
        const PAPER = 2;
        const SCISSORS = 3;
        const LIZARD = 4;
        const SPOCK = 5;
        const MATCHES = array(
            self::ROCK => array(self::SCISSOR, self::LIZARD),
            self::PAPER => array(self::ROCK, self::SPOCK),
            self::SCISSORS => array(self::PAPER, self::LIZARD),
            self::LIZARD => array(self::SPOCK, self::PAPER),
            self::SPOCK => array(self::SCISSOR, self::ROCK),
        );
    
        public static function play($player1, $player2) {
            if (!self::isValid($player1) || !self::isValid($player2)) {
                throw new Exception('Invalid input!');
            }
            return in_array($player2, self::matches[$player1]);
        }
    
        public static function isValid($num) {
            return array_key_exists(self::MATCHES, $num);
        }
    }
    
          

+4


source


As Mark B pointed out in the comments, there are better ways to solve this problem, but for your situation, the reason player 2 will never win is because you have this condition as else based on what $player1

is k. you should have a different value based on the if $player2

in the array.

Just remove the inner part if the constraints are away and you have:

if ($player1 == $player2) {
    echo "Tie.";
    echo "\n";
} elseif ($player1 == 1) {

} elseif ($player1 == 2) {

} elseif ($player1 == 3) {

} elseif ($player1 == 4) {

} elseif ($player1 == 5) {

} else {
    echo "Player 2 wins";
}

      



The only possible way to win in this case is player 2: if is $player2

not equal $player1

and $player1

not equal 1

through 5

.

So, if you set $player1

to 6

, Player 2 "wins", but that doesn't make sense in the context of the game.

+1


source


You say that you are new to php and I assume that you are relatively new to programming. With this in mind, I would like to focus on some basic principles.

So, to answer your question 2), here are a few things to consider:

  • Add nice comments to your code - it would be helpful here to document the RPSLS rules. I had to find the rules for this game, and it looks like at least one person misunderstood the rules. I find that ways of approaching a problem often become clear as I write comments.

  • Use constants for values ​​that will not change, i.e. use ROCK instead of 1, PAPER instead of 2, etc. Other enumeration languages ​​do this, but in php you can use "define" to bind each named constant to its value. This should make the program easier to read and make it easier to find any errors - if you try to use a constant that was not defined, you will get a warning.

  • If possible, the structure of the program should follow the "logical" way of thinking about the problem. For example, the gist of the program looks like this:

    if (player 1 beats player 2) {
        echo "Player 1 wins\n";
    }
    elseif (player 2 beats player 1) {
        echo "Player 2 wins\n";
    }
    else {
        echo "Tie.";
    }
    
          

Pulling them together, here's an alternate way to do what you want:

<?php

// As we'll use these as array indices, we'll start at 0 
define ('ROCK', 0); 
define ('PAPER', 1); 
define ('SCISSORS', 2); 
define ('LIZARD', 3); 
define ('SPOCK', 4); 

/* 
    A reasonable place to document the rules ....
*/
$winning_conditions = array();
$winning_conditions[ROCK] = array(SCISSORS, LIZARD);
$winning_conditions[SCISSORS] = array(PAPER, LIZARD);
$winning_conditions[LIZARD] = array(SPOCK, PAPER);
$winning_conditions[SPOCK] = array(SCISSORS, ROCK);
$winning_conditions[PAPER] = array(ROCK, SPOCK);

// Randomize Moves
$player1 = rand(0, 4);
$player2 = rand(0, 4);

if (in_array($player2, $winning_conditions[$player1]) {
    echo "Player 1 wins\n";
}
elseif (in_array($player1, $winning_conditions[$player2]) {
    echo "Player 2 wins\n";
}
else {
    echo "Tie.\n";
}

?>

      

And with a few additions (perhaps using php associative arrays) it should be possible to improve the output to something like:

Player 2 wins (Lizard poisons Spock)

      

0


source


Player 2 never wins because you only check what player 1 is and you never check which player 2 is.

Try something like this to make it REALLY easy.

//Here you store your player
$player['one'] = rand(1,5);
$player['two'] = rand(1,5);
//Here are all of your pieces
$pieces = array (
  1 => "Rock",
  2 => "Paper",
  3 => "Scissors",
  4 => "Lizard",
  5 => "Spock",
);
if ($player['one']==$player['two']) {
  echo "<p>Draw!</p>";
} elseif (
     ( ($player['one'] == 1) && ( ($player['two']==4) || ($player['two']==3) ) )
  || ( ($player['one'] == 2) && ( ($player['two']==5) || ($player['two']==1) ) )
  || ( ($player['one'] == 3) && ( ($player['two']==2) || ($player['two']==4) ) )
  || ( ($player['one'] == 4) && ( ($player['two']==5) || ($player['two']==2) ) )
  || ( ($player['one'] == 5) && ( ($player['two']==3) || ($player['two']==2) ) )
) {
  echo "<p>Player 1 Wins</p>";
} else {
  echo "<p>Player 2 Wins</p>";
}
echo "
  <p>Player 1:" . $pieces[$player['one']] . "&nbsp;Player2: " . $pieces[$player['two']] . "</p>
";

      

-1


source







All Articles