簡單的擲骰器
許多游戲和游戲系統都需要骰子。讓我們先從簡單的部分入手:擲一個六面骰子。實際上,滾動一個六面骰子就是從 1 到 6 之間選擇一個隨機數字。在 PHP 中,這十分簡單:echo rand(1,6);。
在許多情況下,這基本上很簡單。但是在處理機率游戲時,我們需要一些更好的實現。PHP 提供了更好的隨機數字生成器:mt_rand()。在不深入研究兩者差別的情況下,可以認為 mt_rand 是一個更快、更好的隨機數字生成器:echo mt_rand(1,6);。如果把該隨機數字生成器放入函數中,則效果會更好。
清單 1. 使用 mt_rand() 隨機數字生成器函數
- function roll () {
- return mt_rand(1,6);
- }
- echo roll();
然後可以把需要滾動的骰子類型作為參數傳遞給函數。
清單 2. 將骰子類型作為參數傳遞
- 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
從這裡開始,我們可以繼續根據需要一次滾動多個骰子,返回結果數組;也可以一次性滾動多個不同類型的骰子。但是大多數任務都可以使用這個簡單的腳本。
隨機名稱生成器
如果正在運行游戲、編寫故事或者一次性創建大批字符,有時會疲於應付不斷出現的新名字。讓我們看一看可用於解決此問題的一個簡單隨機名稱生成器。首先,讓我們創建兩個簡單數組 — 一個用於名字,一個用於姓氏。
清單 3. 名字和姓氏的兩個簡單數組
- $male = array(
- "William",
- "Henry",
- "Filbert",
- "John",
- "Pat",
- );
- $last = array(
- "Smith",
- "Jones",
- "Winkler",
- "Cooper",
- "Cline",
- );
然後就可以從每個數組中選擇一個隨機元素:echo $male[array_rand($male)] . ' ' . $last[array_rand($last)];。要一次性提取多個名稱,只需混合數組並根據需要提取。
清單 4. 混合名稱數組
- shuffle($male);
- shuffle($last);
- for ($i = 0; $i <= 3; $i++) {
- echo $male[$i] . ' ' . $last[$i];
- }
基於此基本概念,我們可以創建保存名字和姓氏的文本文件。如果在文本文件的每一行中存放一個名字,則可以輕松地用換行符分隔文件內容以構建源代碼數組。
清單 5. 創建名稱的文本文件
- $male = explode('n', file_get_contents('names.female.txt'));
- $last = explode('n', file_get_contents('names.last.txt'));
構建或查找一些好的名字文件(代碼歸檔 中附帶了一些文件),此後我們絕不再需要為名字煩惱。
場景生成器
利用構建名字生成器使用的相同基本原理,我們可以構建場景生成器。此生成器不但在角色扮演游戲中十分有用,而且在需要用到偽隨機環境集合(可用於角色扮演、即興創作、寫作等情況)的情況下也十分有用。我最喜歡的游戲之一,Paranoia 在其 GM Pack 中包括了 “任務混合器(mission blender)”。任務混合器可用於在快速滾動骰子時整合完整任務。讓我們整合自己的場景生成器。
考慮以下場景:您醒來後發現自己迷失於叢林中。您知道自己必須趕去紐約,但是不知道原因。您可以聽到附近的狗叫聲及清晰的敵方搜尋者的聲音。您渾身發冷、不住顫抖,而且沒有武器。該場景中的每一句話都介紹場景的特定方面:
“您醒來後發現自己迷失於叢林中” — 這句話將建立設置。
“您知道自己必須趕去紐約” — 這句話將描述目標。
“您可以聽到狗叫聲” — 這句話將介紹敵人。
“您渾身發冷、不住顫抖,而且沒有武器” — 這句話將添加復雜度。
就像創建名字和姓氏的文本文件一樣,首先分別創建設置、目標、敵人和復雜度的文本文件。代碼歸檔中附帶了樣例文件。在擁有這些文件後,生成場景的代碼與生成名稱的代碼基本相同。
清單 6. 生成場景
- $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] . "
n";
我們可以通過添加新文本文件向場景中添加元素,也可能希望添加多重復雜度。添加到基本文本文件中的內容越多,場景隨時間的變化就越多。
牌組創建器(Deck builder)和裝備(shuffler)
如果您要玩紙牌並且要處理與紙牌相關的腳本,我們需要用裝備中的工具整合一副牌組構建器。首先,讓我們構建一副標准紙牌。需要構建兩個數組 — 一個用於保存同花色的組牌,而另一個用於保存牌面。如果稍後需要添加新組牌或牌類型,則這樣做將獲得很好的靈活性。
清單 7. 構建一副標准撲克牌
- $suits = array (
- "Spades", "Hearts", "Clubs", "Diamonds"
- );
- $faces = array (
- "Two", "Three", "Four", "Five", "Six", "Seven", "Eight",
- "Nine", "Ten", "Jack", "Queen", "King", "Ace"
- );
然後構建一副牌數組來保存所有紙牌值。只需使用一對 foreach 循環即可完成此操作。
清單 8. 構建一副牌數組
- $deck = array();
- foreach ($suits as $suit) {
- foreach ($faces as $face) {
- $deck[] = array ("face"=>$face, "suit"=>$suit);
- }
- }
在構建了一副撲克牌數組後,我們可以輕松地洗牌並隨機抽出一張牌。
清單 9. 洗牌並隨機抽出一張牌
- 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' => '');
1