场景生成器
利用构建名字生成器使用的相同基本原理,我们可以构建场景生成器。此生成器不但在角色扮演游戏中十分有用,而且在需要用到伪随机环境集合(可用于角 色扮演、即兴创作、写作等情况)的情况下也十分有用。我最喜欢的游戏之一,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' => '');