30 game scripts you can write in PHP, Part 1: Creating 10 fundamental scripts

PHP is an easy-to-use, easy-to-learn, widely accessible programming language. It's well suited for developing simple scripts you can use to help you in all kinds of games. Whether you play simple pen-and-paper games by yourself, complex tabletop role-playing games with a group of people, or online games of any kind, this series will have something for you. Each article in this "30 game scripts you can write in PHP" series will cover 10 scripts in 300 words or less (3d10 stands for "roll three 10-sided dice") simple enough for even a beginning developer, but useful enough for a seasoned game player. The goal is to give you something you can modify to suit your needs, so you can impress your friends and players by busting out your laptop at your next gaming session.

Duane O'Brien, PHP developer, 自由职业者

Duane O'Brien has been a technological Swiss army knife since the Oregon Trail was text only. His favorite color is sushi. He has never been to the moon.


developerWorks Contributing author
        level

18 November 2008

Also available in Russian Japanese Vietnamese Spanish

Getting started

As both a game master/storyteller and a developer, I frequently find myself writing little utilities and scripts to help me when running, planning, and playing games. Sometimes I need a quick idea. Other times, I just need a whole pile of names for Non-Player Characters (NPCs). Occasionally, I need to geek out on numbers, work out some odds, or integrate some word puzzles into a game. Many of these tasks become more manageable with a little bit of script work ahead of time.

This article will explore 10 fundamental scripts that can be used in various types of games. The code archive contains the full source for each script we will discuss, and you can see the scripts in action at chaoticneutral.

We will blaze through these scripts pretty quickly. The topic of finding a host or setting up a server will not be covered. There are many Web hosting companies that offer PHP, and the XAMPP installer is easy to use if you want to set up your own. We won't spend a lot of time talking about PHP best practices or game design techniques. These scripts are designed to be simple to understand, simple to use, and quick to pick up.


A basic die roller

Many games and game systems need dice. Let's start with something simple: rolling a single six-sided die. Essentially, there's no difference between rolling a six-sided die and picking a random number between 1 and 6. In PHP, this is simple: echo rand(1,6);.

In many cases, that would be more or less fine. But when we deal with games of chance, we want something a little better. PHP provides a better random number generator: mt_rand(). Without going into detail on the differences between the two, it is safe to assume that mt_rand is a faster and better random number generator: echo mt_rand(1,6);. We'll be happier overall if we put this in a function.

Listing 1. Using the mt_rand() random number-generator function
function roll () {
    return mt_rand(1,6);
}

echo roll();

Then we can pass the type of die we want to roll as a parameter to the function.

Listing 2. Passing the type of die as a parameter
function roll ($sides) {
    return mt_rand(1,$sides);
}

echo roll(6);   // roll a six-sided die
echo roll(10);  // roll a ten-sided die
echo roll(20);  // roll a twenty-sided die

From here, we can go on to rolling multiple die at once, returning an array of results, or rolling multiple die of different kinds all at once, depending on our needs. But this simple script can be used for most tasks.


Random name generator

If you're running games, writing stories, or creating a bunch of characters all at once, sometimes it's hard to keep coming up with new names. Let's look at a simple random name generator you can use to solve this problem. Starting off, let's make two simple arrays — one with first names, one with last names.

Listing 3. Two simple arrays of first and last names
$male = array(
    "William",
    "Henry",
    "Filbert",
    "John",
    "Pat",
);

$last = array(
    "Smith",
    "Jones",
    "Winkler",
    "Cooper",
    "Cline",
);

Then we can just pick a random element from each array: echo $male[array_rand($male)] . ' ' . $last[array_rand($last)];. To pull a bunch of names at once, we can simply shuffle the arrays and pull as many as we like.

Listing 4. Shuffling the name arrays
shuffle($male);
shuffle($last);
for ($i = 0; $i <= 3; $i++) {
    echo $male[$i] . ' ' . $last[$i];
}

Taking this basic concept, we can create text files to hold our first and last names. If we put one name per line in our text file, we can easily split the file contents on the newline character to build our source arrays.

Listing 5. Creating text files for our names
$male = explode('\n', file_get_contents('names.female.txt'));
$last = explode('\n', file_get_contents('names.last.txt'));

Build or find some good name files (a couple are included in the code archive), and we will never want for names again.


Scenario generator

Taking the same basic principles we used to make the name generator, we can make what's called a scenario generator. This is useful in role-playing games or other situations where we need to come up with a pseudo-random set of circumstances that can be used for role-play, improvisation, writing, etc. One of my favorite games, Paranoia, includes something called a "mission blender" in its GM Pack. The mission blender can be used to put together a full mission at the quick roll of a die. Let's put together our own scenario generator.

Take the following scenario: You wake up lost in the woods. You know you have to get to New York, but you don't know why. You can hear the barking of dogs and the unmistakable sound of hostile searchers nearby. You are cold, shivering, and without a weapon. Each sentence in that scenario introduces a specific aspect of the scenario:

  • "You wake up lost in the woods" — This establishes the setting.
  • "You know you have to get to New York" — This describes an objective.
  • "You can hear the barking of dogs" — This introduces an antagonist.
  • "You are cold, shivering, and without a weapon" — This adds a complication.

Just like we created text files for our first and last names, start by making a text file each for settings, objectives, antagonists, and complications. Sample files are included in the code archive. Once we have these files, the code to generate a scenario looks much the same as the code to generate names.

Listing 6. Generating a scenario
$settings = explode("\n", file_get_contents('scenario.settings.txt'));
$objectives = explode("\n", file_get_contents('scenario.objectives.txt'));
$antagonists = explode("\n", file_get_contents('scenario.antagonists.txt'));
$complications = explode("\n", file_get_contents('scenario.complications.txt'));

shuffle($settings);
shuffle($objectives);
shuffle($antagonists);
shuffle($complications);

echo $settings[0] . ' ' . $objectives[0] . ' ' . $antagonists[0] . ' ' 
. $complications[0] . "<br />\n";

We can add elements to our scenarios by adding new text files, or we may wish to add multiple complications. The more we add to our base text files, the more varied our scenarios will be over time.


Deck builder and shuffler

If you play cards and are interested in working on any scripts that are card-related, we want to put together a deck builder with a built in shuffler. To start, let's build a basic deck of standard playing cards. We need to build up two arrays — one to hold suits and one to hold faces. This will allow flexibility later if we want to add new suits or card types.

Listing 7. Building a basic deck of playing cards
$suits = array (
    "Spades", "Hearts", "Clubs", "Diamonds"
);

$faces = array (
    "Two", "Three", "Four", "Five", "Six", "Seven", "Eight",
    "Nine", "Ten", "Jack", "Queen", "King", "Ace"
);

Then build a deck array to hold all the card values. We can do this simply using a pair of foreach loops.

Listing 8. Building a deck array
$deck = array();

foreach ($suits as $suit) {
    foreach ($faces as $face) {
        $deck[] = array ("face"=>$face, "suit"=>$suit);
    }
}

Once we have a deck array built, we can easily shuffle the deck and draw a random card.

Listing 9. Shuffling the deck and drawing a random card
shuffle($deck);

$card = array_shift($deck);

echo $card['face'] . ' of ' . $card['suit'];

From here, it's a short path to drawing hands of a set number of cards or building a multideck shoe.


Odds calculator: Card draw

Because we built the deck the way we did, keeping track of the face and suit individually for each card, we can make use of the deck programmatically to do something like calculate the odds of getting a specific card. Start by drawing out two hands of five cards each.

Listing 10. Drawing two hands of five cards each
$hands = array(1 => array(), 2=>array());

for ($i = 0; $i < 5; $i++) {
    $hands[1][] = implode(" of ", array_shift($deck));
    $hands[2][] = implode(" of ", array_shift($deck));
}

Then we can look in the deck to see how many cards are left and what the odds are of drawing a specific card. How many cards are left is an easy one. That's just a count of how many elements there are in the $deck array. To get the odds of drawing a specific card, we need a function to walk through the whole deck and evaluate the remaining cards to see if they match.

Listing 11. Calculating the odds of drawing specific card
function calculate_odds($draw, $deck) {
    $remaining = count($deck);
    $odds = 0;
    foreach ($deck as $card) {
        if (  ($draw['face'] == $card['face'] && $draw['suit'] == 
$card['suit'] ) ||
              ($draw['face'] == '' && $draw['suit'] == $card['suit'] ) ||
              ($draw['face'] == $card['face'] && $draw['suit'] == '' ) ) {
            $odds++;
        }
    }
    return $odds . ' in ' $remaining;
}

Now we can pick the card we are trying to draw. To make this easy, pass in an array that looks just like a card. We can look for a specific card.

Listing 12. Looking for a specific card
$draw = array('face' => 'Ace', 'suit' => 'Spades');

echo implode(" of ", $draw) . ' : ' . calculate_odds($draw, $deck);

Or we can look for a card of a given face or suit.

Listing 13. Looking for a card of a given face or suit
$draw = array('face' => '', 'suit' => 'Spades');
$draw = array('face' => 'Ace', 'suit' => '');

Simple poker dealer

Now that we've got a deck builder and something to help work out the odds of drawing specific cards, we can put together a really simple dealer to practice poker hands. For the purpose of this example, we build a dealer for five-card draw. The dealer will provide five cards from the deck. You specify which cards you want to discard by number, and the dealer will replace these cards with fresh ones from the deck. We won't bother putting in draw limits or house rules, though you may find that a rewarding personal exercise.

As shown in the previous section, generate and shuffle a deck, then create a single hand of five cards. Display these cards by their array index so that you can specify which cards to return. You might do it by using checkboxes to indicate which cards you are replacing.

Listing 14. Using checkboxes to indicate cards you are replacing
foreach ($hand as $index =>$card) {
    echo "<input type='checkbox' name='card[" . $index . "]'> 
" . $card['face'] . ' of ' . $card['suit'] . "<br />";
}

Then, evaluate the input array $_POST['card'] to see which cards have been checked for replacement.

Listing 15. Evaluating the input
$i = 0;
while ($i < 5) {
    if (isset($_POST['card'][$i])) {
        $hand[$i] = array_shift($deck);
    }
}

Using this script, you can try your hand — pun intended — at figuring out the best ways to handle a specific set of cards.


Hangman player

Hangman is essentially a word-guessing game. Given a word of a certain length, we have a limited number of letter guesses. If you guess a letter that appears in the word correctly, all occurrences of the letter are filled in. After a set number of wrong guesses (typically six), you've lost the game. To put together a crude game of hangman, we need to start with a word list. For now, let's make it a simple array.

Listing 16. Creating a word list
$words = array (
    "giants",
    "triangle",
    "particle",
    "birdhouse",
    "minimum",
    "flood"
);

Using techniques covered earlier, we can move these words to an external word list text file and import them as we like.

Once we've got a list of words, we need to pick one out at random, display a blank for each letter, and start taking guesses. We need to keep track of right and wrong guesses from guess to guess. We'll do this cheaply by just serializing the guess arrays and passing them along with each guess. If we wanted to keep people from cheating by viewing the page source, we'd want to do something a little more secure.

Build up arrays to hold our letters, and our right/wrong guesses. For right guesses, we'll fill an array with the letters as keys and periods as values.

Listing 17. Building arrays to hold letters and guesses
$letters = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
'p','q','r','s','t','u','v','w','x','y','z');
$right = array_fill_keys($letters, '.');
$wrong = array();

Now we need a little but of code to evaluate guesses and show the word as it progresses through the guessing game.

Listing 18. Evaluating guesses and displaying progress
if (stristr($word, $guess)) {
    $show = '';
    $right[$guess] = $guess;
    $wordletters = str_split($word);
    foreach ($wordletters as $letter) {
        $show .= $right[$letter];
    }
  
} else {
    $show = '';
    $wrong[$guess] = $guess;
    if (count($wrong) == 6) {
        $show = $word;
    } else {
        foreach ($wordletters as $letter) {
            $show .= $right[$letter];
        }
    }
}

In the source archive, we can see how we serialize the guess arrays and pass them from guess to guess.


Crossword helper

I know it's bad form, but sometimes when you're working on a crossword puzzle, you just get stuck trying to find a five-letter word that starts with C and ends with T. Using the same word list we put together for Hangman, we can easily search for words that fit a certain pattern. First, establish a way to pass in words. To make this easy, replace missing letters with periods: $guess = "c...t";. Since regular expressions treat a period as a single character, we can easily walk the word list, looking for matches.

Listing 19. Walking the word list
foreach ($words as $word) {
    if (preg_match("/^" . $_POST['guess'] . "$/",$word)) {
        echo $word . "<br />\n";
    }
}

Depending on the quality of our word list and the accuracy of our guess, we should be able to get a reasonable list of words to use for possible matches. You'll have to decide yourself if "chest" or "cheat" is a better match for "a five-letter word that means 'to not play by the rules.'"


Mad Libber

Mad Libs is a word game where the player takes a short story and replace key types of words with different words of the same type to create a new, sillier version of the same story. Take the following text: "I was walking in the park when I found a lake. I jumped in and swallowed too much water. I had to go to the hospital." Start by replacing the word types with different word tokens. Start and end each token with an underscore to prevent accidental string matches.

Listing 20. Replacing word types with word tokens
$text = "I was _VERB_ing in the _PLACE_ when I found a _NOUN_.  
I _VERB_ed in, and _VERB_ed too much _NOUN_.  I had to go to the _PLACE_.";

Next, create a couple basic word lists. For this example, we won't get too fancy.

Listing 21. Creating a couple of basic word lists
$verbs = array('pump', 'jump', 'walk', 'swallow', 'crawl', 'wail', 'roll');
$places = array('park', 'hospital', 'arctic', 'ocean', 'grocery', 'basement', 
    'attic', 'sewer');
$nouns = array('water', 'lake', 'spit', 'foot', 'worm', 
    'dirt', 'river', 'wankel rotary engine');

Now we can repeatedly evaluate the text to replace the tokens as needed.

Listing 22. Evaluating the text
while (preg_match("/(_VERB_)|(_PLACE_)|(_NOUN_)/", $text, $matches)) {
    switch ($matches[0]) {
        case '_VERB_' :
            shuffle($verbs);
            $text = preg_replace($matches[0], current($verbs), $text, 1);
            break;
        case '_PLACE_' :
            shuffle($places);
            $text = preg_replace($matches[0], current($places), $text, 1);
             break;
        case '_NOUN_' :
            shuffle($nouns);
            $text = preg_replace($matches[0], current($nouns), $text, 1);
            break;
    }
}

echo $text;

Obviously, this is a simple and crude example. The more precise our word lists, and the more time we put into our base text, the better our results will be. We've already used text files to create lists of names and basic word lists. Using the same principle, we can create lists of words broken up by type and use them to create more diverse Mad Libs.


Lotto picker

Picking the right six numbers in a lotto is, to say the least, statistically improbable. Nevertheless, many people still pay to play, and if you like numbers, it can be entertaining to see the trends. Let's throw together a script that lets us keep track of winning numbers and provides the six least-picked numbers in our list.

(Disclaimer: This will not help you win the lotto, so please don't spend your money on tickets. This is just for fun.)

We save winning lotto picks in a text file. We separate individual numbers by comma and put each set of numbers on its own line. When we get the file contents, split on newlines, and split each line on commas, we get something that looks like Listing 23.

Listing 23. Saving winning lotto picks in a text file
$picks = array(
    array('6', '10', '18', '21', '34', '40'),
    array('2', '8', '13', '22', '30', '39'),
    array('3', '9', '14', '25', '31', '35'),
    array('11', '12', '16', '24', '36', '37'),
    array('4', '7', '17', '26', '32', '33')
);

Obviously, that's not much of a base file for drawing stats. But it's a start, and enough to illustrate the principles.

Set a base array to hold the pick range. For example, if we pick numbers from 1 to 40 (e.g., $numbers = array_fill(1,40,0);, then walk through our picks, incrementing appropriate matching values.

Listing 24. Walking through our picks
foreach ($picks as $pick) {
    foreach ($pick as $number) {
        $numbers[$number]++;
    }
}

Finally, sort the numbers based on value. This should put the least-picked numbers at the front of the array.

Listing 25. Sorting the numbers based on value
asort($numbers);

$pick = array_slice($numbers,0,6,true);

echo implode(',', array_keys($pick));

By regularly adding actual lotto picks to the text file containing our list of picks, we can trend number-picking over the long term. It's interesting to see how often some numbers appear.


Summary

This article is a resource for you to get a jump into using PHP to help enrich your gaming experience. In Part 2 of this "30 game scripts you can write in PHP" series, we build on the code found here and go into more involved scripts that can give you even more benefit.


Download

DescriptionNameSize
10 PHP scriptsos-php-gamescripts1-php10games1.zip377KB

Resources

Learn

Get products and technologies

  • Innovate your next open source development project with IBM trial software, available for download or on DVD.
  • Download IBM product evaluation versions, and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=351161
ArticleTitle=30 game scripts you can write in PHP, Part 1: Creating 10 fundamental scripts
publish-date=11182008