微信公众平台开发—24点游戏

因为申请的是个人未认证的订阅号,开启开发者模式以后没有菜单,只能使用接收消息—回复消息的方式来开发

一、实现思路

1、24点题库

第一步是建一张题库表,基础字段是:"num1"、"num2"、"num3"、"num4"、"答案"五个,如果未来需要"最难题排行"功能,需要再加入"答题数、答对数、命中率"三个字段

我的题库来自http://www.cnblogs.com/grenet/archive/2013/02/28/2936965.html

我把内容复制到excel里,按逗号切割了一下,然后又复制到数据库表里,因为想操作方便点,就去掉了带有数字"10"的题目

2、出题

先计算上一题结果,因为有404道题,从404中取一个随机数,作为题目id查询题目返回

3、计算答案

(1)先要把可能接收到的全角括号、长短横杠、"X"替换成能识别的"+-*/"

(2)然后再判断答案里的4个数字是否和题目里的一致,如果题目是"1 2 3 5"回答是"4+4+4+4"就不能通过

(3)借助ScriptEngineManager类和ScriptEngine类将表达式eval成结果,判断是否是"24"

(4)完成判断以后根据回复时间给出用户得分,用时越少得分越多,然后更新用户的"积分、答题数、答对数、命中率"和题目的"答题数、答对数、命中率"

4、排行榜

按用户表的积分大小倒序输出排名即可,需要注意的是如果前10名没有当前用户,要再输出一行当前用户的排名

5、答题状态

出题后用户会切换成答题状态,回复的内容除了关键字都会当做答案来计算,回复"24"、"答案"、"公告"和正确答案后会再切换成正常状态

二、核心源码

package org.xs.dntown.wx.game24.modules.web;

import java.text.NumberFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Random;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.xs.dntown.wx.common.utils.MessageUtil;
import org.xs.dntown.wx.common.web.BaseController;
import org.xs.dntown.wx.core.modules.entity.UserInfo;
import org.xs.dntown.wx.core.modules.entity.enums.ModuleEnum;
import org.xs.dntown.wx.core.modules.entity.req.BaseMsgReq;
import org.xs.dntown.wx.core.modules.service.LogService;
import org.xs.dntown.wx.core.modules.service.UserService;
import org.xs.dntown.wx.game24.modules.entity.Game24UserInfo;
import org.xs.dntown.wx.game24.modules.entity.QuestionInfo;
import org.xs.dntown.wx.game24.modules.entity.enums.StepEnum;
import org.xs.dntown.wx.game24.modules.service.Game24UserService;
import org.xs.dntown.wx.game24.modules.service.QuestionService;

/**
 * 核心Controller
 */
@Controller(value = "game24CoreController")
@RequestMapping("game24")
public class CoreController extends BaseController {
	
	@Autowired
	private Game24UserService game24UserService;
	
	@Autowired
	private QuestionService questionService;
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private LogService logService;
	
	/**
	 * 文本消息
	 */
	@ResponseBody
	@RequestMapping(value = "msg", produces = { "text/plain;charset=utf-8" })
	public String textMsg(HttpServletRequest request) throws Exception {
		String result = "";
		String openId = "";
		String userName = "";
		String content = "";
		try {
			
			//得到接收消息实体
			BaseMsgReq msgReq = (BaseMsgReq)request.getAttribute("msgReq");
			openId = msgReq.getFromUserName();
			content = msgReq.getContent();
			
			//得到用户信息实体
			UserInfo userInfo = (UserInfo)request.getAttribute("userInfo");
			userName = userInfo.getUserName();
			
			log.info("收到消息:" + msgReq.getContent());
			
			//更新模块
			userService.setModule(msgReq.getFromUserName(), ModuleEnum.game24.getValue());
			
			//得到game24用户信息实体
			Game24UserInfo gUserInfo = game24UserService.getByOpenId(userInfo.getOpenId());
			if(gUserInfo == null) {
				log.info("新增game24用户");
				
				//如果没有就新增
				gUserInfo = new Game24UserInfo();
				gUserInfo.setOpenId(userInfo.getOpenId());
				gUserInfo.setModuleStep(StepEnum.normal.getValue());
				gUserInfo.setStepTime(new Date());
				gUserInfo.setIsAnswered(false);
				game24UserService.add(gUserInfo);
			}
			
			//刷新模块(1小时)
			long timeDiff = new Date().getTime() - userInfo.getModuleTime().getTime();
			long hoursDiff = timeDiff / (1000 * 60 * 60);
			if(hoursDiff >= 1) {
				game24UserService.setStep(userInfo.getOpenId(), StepEnum.normal.getValue());
				gUserInfo.setModuleStep(StepEnum.normal.getValue());
			}
			
			log.info("开始转入步骤");
			//出题
			if(msgReq.getContent().equals("24")) {
				
				//计算上一道题
				if(!StringUtils.isEmpty(gUserInfo.getQuestionId()) && gUserInfo.getModuleStep().equals(StepEnum.answer.getValue())) {
					//处理答题结果
					finishAnswer(gUserInfo, msgReq);
				}
				
				log.info("开始下一题");
				//下一题
				Random r = new Random();
				String questionId = String.valueOf(r.nextInt(403) + 1);
				gUserInfo.setQuestionId(questionId);
				gUserInfo.setModuleStep(StepEnum.answer.getValue());
				gUserInfo.setStepTime(new Date());
				gUserInfo.setIsAnswered(false);
				//更新模块
				game24UserService.update(gUserInfo);
				//返回题目
				QuestionInfo questionInfo = questionService.getById(questionId);
				result = "请听题:" + questionInfo.getNum1() + "、" + questionInfo.getNum2() + "、" + questionInfo.getNum3() + "、" + questionInfo.getNum4();
				logService.addInfoLog(openId, userName, content, result, ModuleEnum.game24.getValue(), StepEnum.answer.getValue());
				result = MessageUtil.msgReqToXml(msgReq, result);
				log.info(result);
				return result;
			} 
			//答案
			else if(msgReq.getContent().equals("答案")) {
				
				//返回答案
				if(!StringUtils.isEmpty(gUserInfo.getQuestionId())) {
					
					log.info("返回答案");
					
					//完成答题
					finishAnswer(gUserInfo, msgReq);
					
					//设置步骤
					gUserInfo.setModuleStep(StepEnum.normal.getValue());
					gUserInfo.setStepTime(new Date());
					game24UserService.update(gUserInfo);
					
					//答案
					String answer = questionService.getAnswer(gUserInfo.getQuestionId());
					logService.addInfoLog(openId, userName, content, answer, ModuleEnum.game24.getValue(), StepEnum.answer.getValue());
					result = MessageUtil.msgReqToXml(msgReq, answer);
					log.info(result);
					return result;
				}
			}
			//排行榜
			else if(msgReq.getContent().equals("排行") || msgReq.getContent().equals("排行榜")) {
				
				log.info("返回排行榜");
				
				result += "【排行榜】
";
				
				boolean flag = false;
				List<Game24UserInfo> list = game24UserService.getTopScope(1000);
				if(list != null && list.size() > 0) {
					for (int i = 0; i < list.size(); i++) {
						if(list.get(i).getOpenId().equals(gUserInfo.getOpenId())) {
							flag = true;
						}
						//TODO 优化
						UserInfo sUserInfo = userService.getByOpenId(list.get(i).getOpenId());
						if(sUserInfo != null) {
							result += "No." + (i + 1) + " 『" + sUserInfo.getUserName() + "』(" + list.get(i).getScore() + "分)
";
						}
					}
				}
				
				if(!flag) {
					result += "No." + (Integer.parseInt(game24UserService.getRankScope(gUserInfo.getScore()))) + " 『" + userInfo.getUserName() + "』(" + gUserInfo.getScore() + "分)";
				} else {
					result = result.substring(0, result.length() - 1);
				}
				
				logService.addInfoLog(openId, userName, content, result, ModuleEnum.game24.getValue(), StepEnum.normal.getValue());
				result = MessageUtil.msgReqToXml(msgReq, result);
				log.info(result);
				return result;
			}
			
			//如果是新进来就刷新状态
			if(msgReq.getContent().equals("24点")) {
				
				//完成答题
				if(!StringUtils.isEmpty(gUserInfo.getQuestionId())) {
					finishAnswer(gUserInfo, msgReq);
				}
				
				//设置步骤
				gUserInfo.setModuleStep(StepEnum.normal.getValue());
				gUserInfo.setStepTime(new Date());
				game24UserService.update(gUserInfo);
			}
			
			//如果是答题状态
			if(gUserInfo.getModuleStep().equals(StepEnum.answer.getValue())) {
				
				//返回处理答题结果
				result = finishAnswer(gUserInfo, msgReq);
				logService.addInfoLog(openId, userName, content, result, ModuleEnum.game24.getValue(), StepEnum.answer.getValue());
				result = MessageUtil.msgReqToXml(msgReq, result);
				log.info(result);
				return result;
			}
			
			//返回game24公告
			result += "『24点游戏』
";
			result += "【规则】
";
			result += "利用 + - * / ( ) 列出综合算式
结果是24即可
";
			result += "【说明】
";
			result += "1、输入“24”:开始答题
";
			result += "2、输入“答案”:查看答案
";
			result += "3、输入“排行”:查看排行
";
			result += "4、输入“公告”:返回首页";
			logService.addInfoLog(openId, userName, content, result, ModuleEnum.game24.getValue(), StepEnum.normal.getValue());
			result = MessageUtil.msgReqToXml(msgReq, result);
		} catch (Exception e) {
			log.debug("执行失败");
			logService.addErrorLog(openId, userName, content, "", ModuleEnum.game24.getValue(), StepEnum.normal.getValue(), e);
			e.printStackTrace();
		}
		
		//返回消息
		log.info(result);
		return result;
	}
	
	/**
	 * 处理答题结果
	 */
	private String finishAnswer(Game24UserInfo gUserInfo, BaseMsgReq msgReq) {
		
		log.info("处理答题结果");
		
		String result = "";
		
		//题目
		QuestionInfo questionInfo = questionService.getById(gUserInfo.getQuestionId());
		
		//计算
		String answer = msgReq.getContent();
		answer = answer.replace("(", "(").replace(")", ")").replace("÷", "/").replace("/", "/").replace("×", "*").replace("-", "-").replace("—", "-").replace(" ", "");
		//计算表达式结果
		ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine se = manager.getEngineByName("js");
        Double res = (double) 0;
        try {
        	
        	//校对答案
        	boolean flag = true;
        	String nums = answer.replace("(", "").replace(")", "").replace("*", "").replace("/", "").replace("-", "").replace("+", "");
        	if(nums.length() != 4) {
        		flag = false;
        	} else {
	        	char[] strs = nums.toCharArray();
	        	Arrays.sort(strs);
	        	if(!String.valueOf(strs).equals(String.valueOf(questionInfo.getNum1()) + String.valueOf(questionInfo.getNum2()) + String.valueOf(questionInfo.getNum3()) + String.valueOf(questionInfo.getNum4())))
	        	{
	        		flag = false;
	        	}
        	}
        	
        	if(flag) {
        		res =(Double) se.eval(answer);
        	} else {
				res = 0.0;
			}
		} catch (ScriptException e) {
			log.debug("运算失败");
			//e.printStackTrace();
		}
        
        //回答正确
        if(res == 24) {
        	
        	log.info("回答正确");
        	
        	//计算用时
        	long timeDiff = new Date().getTime() - gUserInfo.getStepTime().getTime();
			long secondsDiff = timeDiff / (1000);
        	
			int score = 0;
			//30秒以内加5分
			if(secondsDiff < 30) {
				score = 5;
			} 
			//60秒以内加3分
			else if(secondsDiff < 60) {
				score = 3;
			} 
			//加1分
			else {
				score = 1;
			}
			
			result = "答对了!用时" + secondsDiff + "s,积分 +" + score;
			
			//更新用户积分、次数、答对次数、命中率
			gUserInfo.setScore(gUserInfo.getScore() + score);
			gUserInfo.setRightTimes(gUserInfo.getRightTimes() + 1);
			gUserInfo.setTimes(gUserInfo.getTimes() + 1);
			NumberFormat numberFormat = NumberFormat.getInstance();
			numberFormat.setMaximumFractionDigits(2);
			gUserInfo.setHitRate(Float.valueOf(numberFormat.format((float) gUserInfo.getRightTimes() / (float) gUserInfo.getTimes() * 100)));
			gUserInfo.setModuleStep(StepEnum.normal.getValue());
			gUserInfo.setStepTime(new Date());
			gUserInfo.setIsAnswered(false);
			
			//更新试题次数、答对次数、命中率
			questionInfo.setRightTimes(questionInfo.getRightTimes() + 1);
			questionInfo.setTimes(questionInfo.getTimes() + 1);
			numberFormat.setMaximumFractionDigits(2);
			questionInfo.setHitRate(Float.valueOf(numberFormat.format((float) questionInfo.getRightTimes() / (float) questionInfo.getTimes() * 100)));
        } 
        //回答错误
        else {
        	
        	log.info("回答错误");
        	
        	//如果第一次回答
        	if(!gUserInfo.getIsAnswered()) {
        	
	        	//更新用户积分、次数、答对次数、命中率
				gUserInfo.setTimes(gUserInfo.getTimes() + 1);
				NumberFormat numberFormat = NumberFormat.getInstance();
				numberFormat.setMaximumFractionDigits(2);
				gUserInfo.setHitRate(Float.valueOf(numberFormat.format((float) gUserInfo.getRightTimes() / (float) gUserInfo.getTimes() * 100)));
				gUserInfo.setIsAnswered(true);
				
				//更新试题次数、答对次数、命中率
				questionInfo.setTimes(questionInfo.getTimes() + 1);
				numberFormat.setMaximumFractionDigits(2);
				questionInfo.setHitRate(Float.valueOf(numberFormat.format((float) questionInfo.getRightTimes() / (float) questionInfo.getTimes() * 100)));
        	}
        	
        	//gUserInfo.setModuleStep(StepEnum.answer.getValue());
			//gUserInfo.setStepTime(new Date());
        	
        	result = "错误";
        }
        
        //更新game24用户
        game24UserService.update(gUserInfo);
        
        //更新题目
        questionService.update(questionInfo);
        
		return result;
	}
}

三、演示地址

四、源码地址

https://github.com/ctxsdhy/dntown

原文地址:https://www.cnblogs.com/ctxsdhy/p/5926109.html