博主水平非常有限,欢迎巨佬们指正、建议!

2017年6月10日更新:
源码及数据库文件:https://github.com/daggerage/fun


背景

自前段时间不小心点错,升级了iOS10之后,就开始沉迷iMessage里的GamePigeon小游戏不能自拔。
CUP PONG有毒的操作,推推乐心机的决斗,都很棒。
然而这个叫“字谜”的游戏也真是紧张刺激…


游戏界面

游戏规则大概如上,6个字母,排出若干个单词,可以只用部分字母,但至少3个。
单词越长加分越高,1分钟内分数高者获胜。

这游戏运气好的时候能到5000多分,然而如果给的字母不太好拼的话,几百分、一千多也是经常的事…
然而这游戏似乎也没法作弊,用字典查还不如直接填上去来得快,反正填错了也不会扣分。
然后就萌生了能不能写个程序来代替我求解的想法。

思路

  1. 读取这6个字符,让它们做任意组合,再验证这个组合出来的单词存不存在。
  2. 验证的方式,可以是调用第三方库,可以是查询词典开放api,可以是将词典数据存到本地再做查询。
  3. 如果是单词,输出。

思路还是比较简单的,只是有一些实现上的细节问题。

  1. python或者java的相关第三方库我没找到。感觉应该不存在的,不用数据库怎么判断是否是合法单词?(jieba分词?没做更多了解)
  2. 词典开放api限制每小时查询次数为1000,而A66=720A^6_6=720,一次游戏就满了,还要换ip,速度也不能保证,麻烦。所以还是需要存到自己的数据库里。
  3. 全排列的算法..自己想的话还是有些头大,还是上网找找资料咯(太菜)。

实现及源码

经过将近一天的摸索踩坑,总算实现了:java+本地mysql

  1. 在网上找单词数据库,用MysqlWorkbench之类的GUI工具导入到本地数据库中(sql语句或txt、csv都行):在csdn上找到一个有大约1.5w单词的数据库(sql文件),由一个个的 INSERT 组成(找的这个版本很坑,竟然还有语法错误,需要手动改一下)。在数据库中建表,导入SQL。
  2. 输入长度为6的字符串,求出这6个单词的全排列,并利用HashSet求出全组合
  3. 查询数据库的单词与该HashSet的交集
  4. 输出


表结构,其实只用到ID和Word。(吐槽一下变量名竟然是拼音缩写,不过lx是啥?)

/*
* WordPuzzleSix.java
*/import java.sql.*;
import java.util.*;public class WordPuzzleSix {private final int LENGTH =6;private final int MIN_LENGTH=3;//单词最小长度private Connection conn;//存储数据库连接private HashSet<String> wordComb;//存储所有单词的组合private ArrayList<String> resultNames;//存储所有结果单词Stringprivate String chs;//存储输入字符串//初始化WordPuzzleSix(String chs){if(chs.length()==LENGTH){conn=getConn();this.chs=chs;wordComb=new HashSet<String>();}else{System.out.println("number of characters less than 3!");}}//获取数据库连接private  Connection getConn() {String driver = "com.mysql.jdbc.Driver";//MySQL数据库驱动String url = "jdbc:mysql://localhost:3306/fun?characterEncoding=utf-8&useSSL=false";//数据库路径,fun为数据库名String username = "root";String password = "";try {Class.forName(driver);//加载数据库驱动conn = DriverManager.getConnection(url, username, password);//获取数据库连接} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();}return conn;}//关闭数据库连接private void closeConn(){try {conn.close();}catch (SQLException e){e.printStackTrace();}}private void swap(char[] s,int a,int b){char temp;temp=s[a];s[a]=s[b];s[b]=temp;}//递归求全排列private void permuatation(char[] s,int start,int len) {if (start > len-1) {String word = "";for (int i = 0; i < len; i++) {word += s[i];}for (int i = MIN_LENGTH; i <= LENGTH; i++) {wordComb.add(word.substring(0,i));//利用HashSet求全组合}}else{for (int i = start; i < len; i++) {swap(s,start,i);permuatation(s,start+1,len);swap(s,start,i);}}}//构建SQL语句private String formatSql(HashSet<String> hs){String sql = "SELECT * FROM words WHERE word IN (";int i=0;for(String name:hs){if(i==0){sql+=String.format("'%s'",name);}else{sql+=String.format(",'%s'",name);}i++;}sql+=")";return sql;}private void printResult(){System.out.println("#####"+chs+"#####");int i=0;for (String name:resultNames){i++;System.out.println(i+" "+name);}}//主方法public void findAllWords(){//将读入的的String转成char[]char[] c=new char[LENGTH];for (int i = 0; i < LENGTH; i++) {c[i]=chs.charAt(i);}permuatation(c,0, LENGTH);//进行递归全排列resultNames=new ArrayList<String>();//记录最终结果String sql=formatSql(wordComb);try {Statement st=conn.createStatement();ResultSet rs=st.executeQuery(sql);//执行组合成的sql语句//取出查询到的结果集,只取word字段的值while (rs.next()){String name=rs.getString("word");resultNames.add(name);//添加到结果集中}}catch (SQLException e){e.printStackTrace();}//对结果集按字符串长度,升序排列resultNames.sort(new Comparator<String>() {@Override //重写compare方法public int compare(String o1, String o2) {return o1.length() - o2.length();}});printResult();closeConn();//别忘了关闭连接}//一开始使用的方法,已废弃private Word select(String word){PreparedStatement pstm;try {String sql = "SELECT * FROM words WHERE word=?";pstm=conn.prepareStatement(sql);pstm.setString(1,word);ResultSet rs = pstm.executeQuery();if(rs.next()){String wordName=rs.getString("word");Word w=new Word(wordName);return w;}}catch (SQLException e){e.printStackTrace();}return null;}}
//Select方法用到的实体(Entity)类,已废弃
class Word{public String word;Word(String word){this.word=word;}
}
/*
* Main.java
*/
import java.util.Scanner;public class Main {//主程序public static void main(String[] args) {Scanner s=new Scanner(System.in);while (true){String input=s.nextLine();//读取输入字符串if(!input.equals("quit")) {if(input.length()==6){long startTime=System.currentTimeMillis();WordPuzzleSix wps = new WordPuzzleSix(input);wps.findAllWords();long endTime=System.currentTimeMillis();long timeCost=endTime-startTime; //计算消耗时间System.out.println("time cost : "+timeCost+" ms");}else{System.out.println("number of characters less than 3!");}}else{break;}}s.close();}
}

最后结果:

总结

虽然程序很小很简单,但写一遍下来,也对之前不是很清楚的地方熟悉了很多吧。

用到的知识点:

  1. 数据库操作,定义(DML,DDL
  2. JDBC连接、操作MySQL数据库,以及流程优化
  3. 全排列算法的递归实现与改动
  4. ArrayListHashSet 以及ArrayList中sort 方法的使用(匿名内部类,方法重写)
  5. try...catch 异常处理
  6. Java I/O

实现方向的选择:

  1. 为什么用Java:感觉用Python会方便一些,但因为Windows10下python-mysql的包难以配置(很久之前试过,放弃了),总是有各种版本问题,而java的jdbc已经有储备,就用了Java。python还是在linux下方便,而我总不会因为玩个字谜游戏切去linux吧
  2. 关于怎么查单词:可以看到,select方法和Word实体类被抛弃了。其实一开始是用循环select的方法进行查询,即一共要进行900次左右的select,在只进行一次数据库连接(getConnection()),不断开的情况下,做完这些查询耗时大约在17~60秒,速度太慢了,而且很不稳定,不知道为什么。所以最后采用了WHERE ... IN ()的方式进行集合查询,耗时单位都改成毫秒了。得出结论,在数据库端做一条很复杂、数据很多的查询,也比反复做多条查询速度要快。由于对数据库的了解不深,背后具体的原理日后可能更新。

不足:

  1. 因为数据库比较小(跟游戏的相比),每次查出来的结果都不是很多,都输进去也就4000-6000分的样子,而且这游戏很鬼畜,一个名词,加s变复数后算一个新单词,而这个程序并没有选出复数、过去式等等(也不一定每局游戏都多个s),所以还是得手动+1s,以及考察对单词过去式的记忆~
  2. 项目结构可能不是特别好,稍显凌乱?不过也就一个小功能,也差不多?如果有大佬能指点一番,不胜感激!
  3. 自己太菜了,感觉还是写的比较慢

后记

最后实际效果还是蛮好的,胜率大幅提升23333

当然也不是无敌的,有时候还是感叹AI无法战胜人类啊~附一张对战截图(“我竟然输给了人类?!”)

其实是故意让的,总是赢的话,女票都不跟自己玩了(逃

英语字谜求解程序(JAVA):iMessage-GamePigeon的“字谜”相关推荐

  1. 英语不好学java好学吗_英语不好能学好java,做程序员吗?

    原标题:英语不好能学好java,做程序员吗? 很多想学java的朋友,都存在着这样一个疑惑:我的英语很差劲,对学习java没有影响吗?java编程用到英语的地方很多吧,我英语不好能学好java吗? 学 ...

  2. 零基础而且英语不好可以学java吗

    以前很多人都不知道有程序员这个岗位,现在随着互联网的发展,越来越多的人意识到当程序员是一个很好的选择.导致每年想学java的人越来越多,其中许多人都是零基础 零基础可以学java吗? 可以的.谁都是从 ...

  3. java 小程序 多线程_《多线程练习—买票小程序——Java第十四周》

    /* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2011, 烟台大学计算机学院学生 * All rights reserved. * 文件名称:    < ...

  4. java英文不好可以学吗_英语不好可以学好Java吗?

    英语不好可以学好Java吗?许多人都觉得英语好,学编程就一定学的好.实际上,并非如此,虽然计算机程序大都采用英语的语法,但这跟英语是两码事.会英语的人多了,英语八级的同学看到程序照样是一点不会.经实际 ...

  5. 思考并实现以下程序功能:实现一个抢红包的程序 java

    抢红包的程序 java 思考并实现以下程序功能:实现一个抢红包的程序. 可参考模拟微信抢红包的过程:假如当前红包是x元,参与抢红包的有y人,按时间先后顺序保证y人正好抢完x元红包,其中每人抢的红包数值 ...

  6. 在web前端调用后台java程序(java类)的方式

    在web前端调用后台java程序(java类)的方式: 首先静态html标签是无法直接调用java程序的,但是可以通过imput button按钮点击,onclick事件调用一个js函数,用这个js函 ...

  7. matlab怎么重新打开新的代码,方程求解程序代码求助-程序代码修改或新的代码...

    很简单的方程求解程序,调用mulDNewton函数求解,之前在Matlab 2011b版本上运行成功,现在在Matlab 2018a版本上总是出错,程序代码和出错的提示如下,mulDNewton函数代 ...

  8. 求解立方根 java

    求解立方根 java 题目描述 •计算一个数字的立方根,不使用库函数 详细描述: •接口说明 原型: public static double getCubeRoot(double input) 输入 ...

  9. 微信读书登陆界面java_(JAVA后端)微信小程序-毕设级项目搭建-微信阅读小程序(内含源码,微信小程序+java逻辑后台+vue管理系统)~不求完美,实现就好...

    转载地址:(JAVA后端)微信小程序-毕设级项目搭建-微信阅读小程序(内含源码,微信小程序+java逻辑后台+vue管理系统)~不求完美,实现就好 转载请注明出处 一.环境搭建 相关环境软件:JDK1 ...

最新文章

  1. HDU4756(次小生成树)
  2. 多激光雷达外参⾃动化标定算法及代码实例
  3. If using all scalar values, you must pass an index
  4. Java HashMap遍历的两种方式
  5. 纯 Win32 SDK程序为什么每次要获取设备描述表句柄
  6. 发送临时文件被服务器拒绝,临时会话说服务器拒绝了您发送离线文件的请求 - 卡饭网...
  7. SAP UI5 初学者教程之二十三 - 列表控件的排序 Sort 和分组 Group 试读版
  8. 迈向人工通用智能与混合天玑芯片架构
  9. ORACLE批量更新四种方法比较
  10. 华为鸿蒙os什么时候发布,鸿蒙OS将于今天发布
  11. 江湖人物之滴滴打车张博
  12. 浅谈IAST,DAST,SAST之区别
  13. unity中世界坐标与局部坐标
  14. 直接打印RAW文件到打印机
  15. matlab计算器设计流程图_matlab计算器的设计.doc
  16. 「需求广场」需求词更新明细(十二)
  17. 每日一犬 · 波尔多犬
  18. 白盒测试:语句覆盖、条件覆盖、判定覆盖、条件-判定覆盖、组合覆盖、路径覆盖
  19. r语言list 转换成 vector
  20. 在字节跳动干软件测试5年,4月无情被辞,想给划水的兄弟提个醒

热门文章

  1. 电商平台-团购模块设计与架构
  2. 自学java还是报班,哪个好?
  3. java short float_java – 将float转换为short,具有最小的精度损失
  4. Linux下fdisk格式化TF卡,创建分区
  5. 康有为的“真”与“伪”
  6. 新零售模式,数据管理更轻松
  7. windows 32位程序编译成64位
  8. Nexus 7 搞机教程
  9. Android传递对象方式Parcelable
  10. Spring事务管理——使用XML配置声明式事务