微信公众平台开发初探(二)——WeiPHP下“猜数字”游戏的实现

猜数字游戏(又叫宾果Bingo游戏),游戏规则如下——

游戏开始,系统会生成一个四位整数,且这四位整数每一位数字都是不同的。接下去由游戏参与者开始猜这个四位数字。每猜测一次,系统会告诉游戏参与者本次猜测中有几个数字出现在答案中,但是位置不对(用B来表示);有几个数字不仅在答案中,而且位置也对了(用A来表示)。

举例说明,如果最终答案是7439。我的猜测是1234,那么系统会告诉我1A1B,因为其中一个数字(3)位置正确,所以1A;另有一个数字(4)位置不对,但是答案中有这个数字,所以1B。
因此,当玩家猜出4A0B时,就是猜对答案的时候。

本篇教程之所以采用这个游戏作为案例,是因为它用到了微信平台开发中比较重要的一个模式(用户操作需要考虑上下文的模式),在WeiPHP中,set_user_status这个函数(字面意思:设置用户状态)帮我们很好解决了这个问题,它的原理是将该用户之前发的消息缓存起来。

这个猜数字游戏并没有用到太多的微信公众号接口,仅仅是很简单的一个消息窗口就可以完成这个游戏的流程——
1. 当用户输入“猜数字”时,开始进入游戏(调用插件),从这句话开始用户所有的输入都会被缓存,直到游戏结束。如果是游戏刚开始,那么我们应该向客户端返回一串提示语,告诉用户游戏开始并提示用户进行数字输入。
2. 接下去是游戏主体部分,用户每次输入,我们都对用户输入内容缓存,同时计算出应该告诉用户的aAbB,同时把这个内容也进行缓存。
3. 直到用户输入“退出”/“答案”。游戏结束。

从这个流程来看,所有的内容都可以在WeixinAddonModel.class.php中完成。
接下去我们来看一下reply方法传入的两个参数,其中第一个参数$dataArr在第一篇教程中已经提到过,用户本次用微信客户端消息处发出的消息就存在$dataArr['Content']中(注意这里Content首字母大写),而第二个参数$keywordArr在前一篇教程中并没有提到,从字面意思看,它是“关键词数组”,每次都会被跟着传进reply方法,那么它实际上就是实现上下文缓存用的。

在这个插件中,我这样设计$keywordArr的数据结构——
$keywordArr['step']用于存储当前猜测的步骤数,初始化时为0;
$keywordArr['answer']用于存储初始化时候生成的答案;
$keywordArr['userInput'] 用数组方式存储用户的每一次输入;
$keywordArr['response'] 用数组方式存储对用户每一次输入的返回结果。
具体代码看下面注释就可以了。
完整插件可从百度云获取:http://pan.baidu.com/s/1jGGWKrs

<?php 

namespace Addons\BingoGame\Model;
use Home\Model\WeixinModel;

/**
 * BingoGame的微信模型
 * @author: Emptyset<21324784@qq.com>
 */
class WeixinAddonModel extends WeixinModel{

    function reply($dataArr, $keywordArr = array()) {
        $config = getAddonConfig ( 'BingoGame' ); // 获取后台插件的配置参数   
        //dump($config);
        if (empty($keywordArr) && $dataArr['Content'] == 'BingoGame' || $dataArr['Content'] == '猜数字') {
            $this -> gameStart($dataArr,$keywordArr);
            $text = "游戏开始了!我已经想好了一个四个数字互不相同的四位数。"; 
            $text .= "\n【游戏规则:假如答案是2134,如果猜测2043,那么我会回复1A2B,因为其中有1个数字位置对了,有2个数字位置不对,但是在答案中有。】";
            $text .= "\n请输入一个四个数字各不相同的四位数(例如:1034)。";
            $text .= "或者输入:\n退出:结束游戏\n答案:查看答案";
            $this -> replyText($text);
        } else if ($dataArr['Content']=='退出' || $dataArr['Content']=='结束' || $dataArr['Content']=='exit' || $dataArr['Content']=='quit') {
            $this -> replyText("已经结束游戏");
            return true;
        } else if ($dataArr['Content']=='答案') {
            $this -> replyText("答案是:".$keywordArr["answer"]."。笨死了,这都猜不出来~游戏结束了!");
            return true;
        }else {
            switch ($keywordArr['status']) {
                case 'trial' :          //用户处在尝试答案阶段
                    //首先保证输入合法
                    if ($this -> inputValid($dataArr['Content'])) {
                        $step = $keywordArr['step'];
                        $step++;
                        $keywordArr['step'] = $step;
                        $keywordArr['userInput'] []= $dataArr['Content'];
                        $response = $this -> computeResult($dataArr['Content'],$keywordArr['answer']);
                        $keywordArr['response'] []= $response;
                        if ($response == '4A0B') {
                            set_user_status('BingoGame',$keywordArr);
                            $this -> replyText("恭喜你答对了!一共猜测了".$step."次");
                            return true;
                        } else {
                            set_user_status('BingoGame',$keywordArr);
                            $this -> replyText($response);
                        }                       
                    } else {
                        set_user_status('BingoGame',$keywordArr);
                        $text = "亲,说好的要输入一个四位整数的呢?四个数字都不能有重复的哟~";
                        $this -> replyText($text);
                    }
                    break;
                default :
                    break;
            }
        }
    }

    //判断输入是否合法
    private function inputValid($input) {
        $pattern = "/^(?!.*?(\d).*?\1.*?$)\d{4}$/";
        return preg_match($pattern,$input);
    }

    //生成一个四位的无重复位的数字
    private function generateNumber() {
        //先生成最高位
        $number = array();
        $number[0] = mt_rand(1,9);
        $n = 0;
        while($n<4) {
            $number[$n] = mt_rand(0,9);
            $duplicate = false;
            for($i=0;$i<$n;$i++) {
                if($number[$n] == $number[$i]) {
                    $duplicate = true;
                }
            }
            if(!$duplicate) {
                $n++;
            }
        }
        return (string)($number[0]*1000 + $number[1]*100 + $number[2]*10 + $number[3]);
    }

    //游戏初始化
    private function gameStart(&$dataArr,&$keywordArr) {
        $keywordArr['step'] = 0;
        $keywordArr['status'] = 'trial';
        $keywordArr['userInput'] = array();
        $keywordArr['userInput'] []= $dataArr['Content'];
        $keywordArr['response'] = array();
        $keywordArr['response'] []= '';
        $keywordArr['answer'] = $this -> generateNumber();
        set_user_status('BingoGame',$keywordArr);
        return true;
    }

    //@description  根据合法输入返回结果
    //@return   string(4)   例如:2A1B
    private function computeResult($input, $answer) {
        $A = 0;
        $B = 0;
        //按位排查
        for($i=0;$i<4;$i++) {
            for($j=0;$j<4;$j++) {
                if($i==$j && $input[$i]==$answer[$j]) {
                    $A++;
                    break;
                } else if ($i!=$j && $input[$i]==$answer[$j]) {
                    $B++;
                    break;
                }
            }
        }
        $result = $A.'A'.$B.'B';
        return $result;
    }

}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值