Dice are required for many games and gaming systems. Let's start with the easy part: rolling a six-sided die. Essentially, rolling a six-sided die is simply choosing a random number between 1 and 6. In PHP, this is very simple: echo rand(1,6);.
In many cases, this is basically simple. But when dealing with games of chance, we need some better implementation. PHP provides a better random number generator: mt_rand(). Without delving too deeply into the differences between the two, mt_rand can be thought of as a faster and better random number generator: echo mt_rand(1,6);. It would be even better if you put this random number generator into a function.
1. Use mt_rand() random number generator function:
function roll () { return mt_rand(1,6); } echo roll();
You can then pass the type of dice to be rolled as a parameter to the function.
2. Pass the dice type 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 continue to roll multiple dice at once as needed and return an array of results; we can also roll multiple dice of different types at once. But most tasks can be done using this simple script.
If you're running a game, writing a story, or creating a large number of characters all at once, it can sometimes be overwhelming to deal with the constant stream of new names. Let's take a look at a simple random name generator that can be used to solve this problem. First, let's create two simple arrays—one for first names and one for last names.
3. Two simple arrays of first name and last name:
$male = array( "William", "Henry", "Filbert", "John", "Pat", ); $last = array( "Smith", "Jones", "Winkler", "Cooper", "Cline", );
You can then select a random element from each array: echo $male[array_rand($male)] . ' ' . $last[array_rand($last)];. To extract multiple names at once, just mix the arrays and extract as needed.
4. Mixed name array
shuffle($male); shuffle($last); for ($i = 0; $i <= 3; $i++) { echo $male[$i] . ' ' . $last[$i]; }
Based on this basic concept, we can create a text file that holds first and last names. If you store a name on each line of a text file, you can easily separate the file contents with newlines to build an array of source code.
5. Create a text file of name
$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 (some are included in the code archive) and we'll never have to worry about names again.
Using the same basic principles we used to build the name generator, we can build the scene generator. This generator is useful not only in role-playing games, but also in situations where you need to use a collection of pseudo-random environments (which can be used for role-playing, improvisation, writing, etc.). One of my favorite games, Paranoia, includes a "mission blender" in its GM Pack. The Mission Mixer can be used to combine complete missions while rolling the dice quickly. Let's put together our own scene generator.
Consider the following scenario: You wake up and find yourself lost in the jungle. You know you have to get to New York, but you don’t know why. You can hear dogs barking nearby and the distinct sounds of enemy seekers. You're cold, shaking, and unarmed. Each sentence in the scene introduces a specific aspect of the scene:
Just like you created the text files for First Name and Last Name, first create separate text files for Settings, Objectives, Enemies, and Complexity. Sample files are included in the code archive. Once you have these files, the code to generate the scene is basically the same as the code to generate the name.
6. Generate scene
$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')); $complicati**** = explode("n", file_get_contents('scenario.complicati****.txt')); shuffle($settings); shuffle($objectives); shuffle($antagonists); shuffle($complicati****); echo $settings[0] . ' ' . $objectives[0] . ' ' . $antagonists[0] . ' ' . $complicati****[0] . "<br />n";
We can add elements to the scene by adding new text files, and we may wish to add multiple levels of complexity. The more content you add to the basic text file, the more the scene changes over time.
Deck builder and shuffler
If you're going to play poker and you're going to be dealing with card-related scripts, we need to put together a deck builder with the tools in the rig. First, let's build a standard deck of cards. Two arrays need to be constructed - one to hold the group of cards of the same suit, and another to hold the face of the card. This gives you great flexibility if you need to add new decks or card types later.
7. Construct a standard 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 card values. This can be done simply using a pair of foreach loops.
8. Construct a deck of card arrays
$deck = array(); foreach ($suits as $suit) { foreach ($faces as $face) { $deck[] = array ("face"=>$face, "suit"=>$suit); } }
After constructing an array of playing cards, we can easily shuffle the deck and randomly draw a card.
9. Shuffle the cards and randomly draw a card
shuffle($deck); $card = array_shift($deck); echo $card['face'] . ' of ' . $card['suit'];
现在,我们就获得了抽取多副牌或构建多层牌盒(multideck shoe)的捷径。
由于构建扑克牌时会分别跟踪每张牌的牌面和花色,因此可以通过编程方式利用这副牌来计算得到特定牌的几率。首先每只手分别抽出五张牌。
10. 每只手抽出五张牌
$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)); }
然后可以查看这副牌,看看剩余多少张牌以及抽到特定牌的机率是多少。查看剩余的牌数十分简单。只需要计算 $deck 数组中包含的元素数。
要获得抽到特定牌的机率,我们需要一个函数来遍历整副牌并估算其余牌以查看是否匹配。
11. 计算抽到特定牌的几率
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; }
现在可以选出尝试抽出的牌。为了简单起见,传入看上去类似某张牌的数组。我们可以查找特定的一张牌。
12. 查找指定的一张牌
$draw = array('face' => 'Ace', 'suit' => 'Spades'); echo implode(" of ", $draw) . ' : ' . calculate_odds($draw, $deck);
或者可以查找指定牌面或花色的牌。
13. 查找指定牌面或花色的牌
$draw = array('face' => '', 'suit' => 'Spades'); $draw = array('face' => 'Ace', 'suit' => '');
现在已经得到牌组构建器和一些工具,可以帮助计算出抽出特定卡的机率,我们可以整合一个真正简单的发牌器来进行发牌。出于本例的目的,我们将构建一个可以抽出五张牌的发牌器。发牌器将从整副牌中提供五张牌。使用数字指定需要放弃哪些牌,并且发牌器将用一副牌中的其他牌替换这些牌。我们无需指定发牌限制或特殊规则,但是您可能会发现这些是非常有益的个人经验。
如上一节所示,生成并洗牌,然后每只手五张牌。按数组索引显示这些牌,以便可以指定返回哪些牌。您可以使用表示要替换哪些牌的复选框来完成此操作。
14. 使用复选框表示要替换的牌
foreach ($hand as $index =>$card) { echo "<input type='checkbox' name='card[" . $index . "]'> " . $card['face'] . ' of ' . $card['suit'] . "<br />"; }
然后,计算输入 array $_POST['card'],查看哪些牌已被选择用于替换。
15. 计算输入
$i = 0; while ($i < 5) { if (isset($_POST['card'][$i])) { $hand[$i] = array_shift($deck); } }
使用此脚本,您可以尝试找到处理特定一组牌的最佳方法。
Hangman 实质上是一款猜字游戏。给定单词的长度,我们使用有限的几次机会猜这个单词。如果猜出了出现在该单词中的一个字母,则填充该字母出现的所有位置。在猜错若干次(通常为六次)后,您就输了比赛。要构建一个简陋的 hangman 游戏,我们需要从单词列表开始。现在,让我们把单词列表制作成一个简单的数组。
16. 创建单词列表
$words = array ( "giants", "triangle", "particle", "birdhouse", "minimum", "flood" );
使用前面介绍的技术,我们可以把这些单词移动到外部单词列表文本文件中,然后根据需要导入。
在得到单词列表后,需要随机选出一个单词,将每个字母显示为空,然后开始猜测。我们需要在每次进行猜测时跟踪正确和错误的猜测。只需序列化猜测数组并在每次猜测时传递它们,就可实现跟踪目的。如果需要阻止人们通过查看页面源代码侥幸猜对,则需要执行一些更安全的操作。
构建数组以保存字母和正确/错误的猜测。对于正确的猜测,我们将用字母作为键并用句点作为值填充数组。
17. 构建保存字母和猜测结果的数组
$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();
现在需要一些代码来评估猜测并在完成猜字游戏的过程中显示该单词。
18. 评估猜测并显示进度
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]; } } }
在源代码归档 中,可以看到如何序列化猜测数组并将该数组从一次猜测传递到另一次猜测中。
我知道这样做不合适,但是有时在玩纵横拼字谜时,您不得不费劲地找出以 C 开头并以 T 结尾、包含五个字母的单词。使用为 Hangman 游戏构建的相同单词列表,我们可以轻松地搜索符合某个模式的单词。首先,找到一种传输单词的方法。为了简单起见,用句点替换缺少的字母:$guess = "c...t";。由于正则表达式将把句点处理为单个字符,因此我们可以轻松地遍历单词列表以查找匹配。
19. 遍历单词列表
foreach ($words as $word) { if (preg_match("/^" . $_POST['guess'] . "$/",$word)) { echo $word . "<br />n"; } }
根据单词列表的质量及猜测的准确度,我们应当能够得到合理的单词列表以用于可能的匹配。您必须自己决定 "表示 '不按规则玩' 的由五个字母组成的单词" 的谜底是 "chest" 还是 "cheat"。
米德里比斯是一款文字游戏,玩家在游戏中得到一个简短的故事并用同一类型的不同单词替换主要类型的单词,从而创建同一个故事的更无聊的新版本。阅读以下文本:"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." 开始用其他单词标记替换单词类型。开始和结束标记带有下划线用于阻止意外的字符串匹配。
20. 用单词标记替换单词类型
$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_.";
接下来,创建几个基本单词列表。对于本例,我们也不会做得太复杂。
21. 创建几个基本单词列表
$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');
现在可以重复地评估文本来根据需要替换标记。
22. 评估文本
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;
很明显,这是一个简单而粗糙的示例。单词列表越精确,并且花在基本文本上的时间越多,结果就越好。我们已经使用了文本文件创建名称列表及基本单词列表。使用相同原则,我们可以创建按类型划分的单词列表并使用这些单词列表创建更加变化多端的米德里比斯游戏。
全部选中乐透的六个正确号码 —— 退一步说 —— 在统计学上是不可能的。不过,许多人仍然花钱去玩,而且如果您喜欢号码,则查看趋势图可能很有趣。让我们构建一个脚本,该脚本将允许跟踪赢奖号码并在列表中提供选择次数最少的 6 个号码。(免责声明:这不会帮助您中乐透奖,因此请不要花钱购买奖券。这只是为了娱乐)。
把赢奖的乐透选择保存到文本文件中。用逗号分隔各个号码并把每组号码放在单独一行中。使用换行符分隔文件内容并使用逗号分隔行后,可以得到类似清单 23 的内容。
23. 把选择的赢奖乐透保存到文本文件中
$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') );
很明显,这不足以成为绘制统计数据的基本文件。但是它是一个开端,并且足以演示基本原理。
设置一个基本数组以保存选择范围。例如,如果选择 1 到 40 之间(例如,$numbers = array_fill(1,40,0);)的号码,则遍历我们的选择,递增相应的匹配值。
24. 遍历选择
foreach ($picks as $pick) { foreach ($pick as $number) { $numbers[$number]++; } }
最后,根据值将号码排序。此操作应当会把最少选择的号码放在数组的前部。
25. 根据值将号码排序
asort($numbers); $pick = array_slice($numbers,0,6,true); echo implode(',', array_keys($pick));
通过有规律地向包含中奖号码列表的文本文件添加实际的乐透中奖号码,可以发现选号的长期趋势。查看某些号码的出现频率十分有趣。