zoukankan      html  css  js  c++  java
  • 看图猜成语通关辅助程序(ruby)

          过年前的时候,看到同事HQJ在手机上玩猜成语,前两天,我也下载了一个《疯狂看图猜成语2》,其实最开始看到这个游戏时候,就习惯性的想作弊了。
          玩游戏我一直喜欢修改的,比如FPE啦,金山游侠啦,对我来说都是玩游戏必备的工具。
          这个看图猜成语,就是给一幅图,下面是24个汉字,从里面选4个字,作为符合图内容的成语答案。
          ok,现在让我们go。

    系统:Windows XP sp2
    ruby:1.9.2p180
    编辑器:SciTE 1.73

          工作环境,无法上网,所以系统旧,ruby旧,大家先承担些,后面没问题了,再转Ubuntu(Ubuntu在u盘上安装的系统,比windows下还慢)。

          1.开始的时候,很简单的想法,就是从里面随便抽汉字,组成4个字的词,看里面是否有成语,这个是最简单的。
          我喜欢使用ruby,纯属个人爱好,代码也许很烂,看的人多担待些。
          在Windows下有个问题,操作系统的编码是gbk,但是ruby1.9底层是utf-8,所以总是需要转码。

    #coding: UTF-8
    require 'iconv'  
    words_array = %w|无 黑 用 如 小 比 伦 材 脚 纸 四 表 两 得 一 字 天 大 朝 白 与 举 一 里|   #成语游戏的备选字库
    words = words_array.map {|x|  Iconv.conv 'gbk', 'utf-8', x} #utf-8转gbk
    idioms = words.permutation(4).to_a #每4个字分组
    idioms.each {|x|  puts x.join}  #分组合并,就是四字成语

          功能是有了,但是这个排列组合的数量巨大,人眼很难找到成语,24个字4字排列总共255024个,眼神好能找到符合的成语,不好就很难了。

          2.数量巨大的结果不实用,那么就减少。一个想法是从网上弄成语词库,从里面选就可以了。
          去网上找成语词库,真的不怎么好找,都是带解释什么的乱七八糟的,最后找到一个叫“成语词典.txt”的文件,里面的内容是类似“【束教管闻】谓学识浅陋,见闻不广。”这样的内容内容,就他了,很容易通过正则取出【】中间的内容为成语词典。

    #coding: UTF-8
    require 'iconv'
    s1 = Iconv.conv 'gbk','utf-8',"" #烦人的转码
    s2 = Iconv.conv 'gbk','utf-8',""
    File.open('成语.txt','w') do |wfile|
      File.open('成语词典.txt','r') do |rfile|
        rfile.each do |line|
          line =~ /#{s1}(.*)#{s2}/
          wfile << $1 << "
    "  #没有
    就会连一起了
        end
      end
    end

          输出为“成语.txt”,最后有几个错误的词,手工给删除了,最后是23594条成语。

          3.有字库排列,有成语词典,第一个想法当然是排列对照,简单的就是两个循环。其实我最开始就是这么做的,比较丢人啊,就不写了,速度很慢,你想想255024*23594的循环。后来就问了HQJ,程序员就明白的多,告诉我既然成语词典少,就从成语词典过滤,先比较第一个字,这样一次就只有几十上百个词语选择,接着再去字库中选择。

          按照这个思路,写了几版,最终的定型大概是这样的。

    #coding: UTF-8
    require 'iconv'  
    words = %w|无 黑 用 如 小 比 伦 材 脚 纸 四 表 两 得 一 字 天 大 朝 白 与 举 一 里|
    
    idioms_array = Array.new
    idioms_regexp  = Array.new
    
    File.open('成语.txt','r') do |file|
      file.each do |line|
        idioms_array << line.chomp   #把成语词典折腾出来,作为array数组     
      end
    end
    
    words_g = words.map {|x| Iconv.conv 'gbk', 'utf-8',x}.uniq #转码,另外把重复的字去除,后面用不到
    
    words_g.each {|word|
      idioms_array.map {|x| idioms_regexp << x if x =~ /^#{word}/} #循环,从成语词典中匹配第一个字相同的记录
      idioms_regexp.map  {|idiom|
        idioms_regexp = []   #这里坑了我很久,一直有重复的,后来发现因为里面有数据,清空就好了
        puts idiom if words_g.include?(idiom[1]) && words_g.include?(idiom[2]) && words_g.include?(idiom[3]) #检查成语的第2、3、4个字,是否在词库中,都在那就ok了
      }
    }


          4.上面的想法都太直白了,还是按照ruby的习惯,尽可能的少的代码,把循环等去除一下。

          重构code:

    #coding: UTF-8
    require 'iconv'
    require 'benchmark'
    
    words = %w|无 黑 用 如 小 比 伦 材 脚 纸 四 表 两 得 一 字 天 大 朝 白 与 举 一 里|
    
    idioms_array = Array.new
    
    File.open('成语.txt','r') do |file|
      file.each do |line|
        idioms_array << line.chomp   #把成语词典折腾出来,作为array数组     
      end
    end
    
    words_g = words.map {|x| Iconv.conv 'gbk', 'utf-8',x}.uniq #转码,另外把重复的字去除,后面用不到
    
    Benchmark.bm do |bm|
        bm.report {
        words_g.each do |word|
          idioms_array.map do |idiom|
            puts idiom if idiom =~ /^#{word}/ and words_g.include?(idiom[1]) and words_g.include?(idiom[2]) and words_g.include?(idiom[3])   
          end
        end
      }
    end


          我的烂机器上,大概6.8秒。重构与否其实速度没有变化。本来还序列化的了,但是和直接读txt一样,所以就没有用。

          5.Ubuntu下使用下面的代码。因为我的Ubuntu性能更烂,所以需要近10秒。而且Ubuntu下,需要把成语.txt转换为utf-8格式,所以我用了“成语u.txt”。

    Ubuntu下代码:

    #coding: UTF-8
    require 'iconv'
    require 'benchmark'
    
    words = %w|无 黑 用 如 小 比 伦 材 脚 纸 四 表 两 得 一 字 天 大 朝 白 与 举 一 里|
    idioms_array = Array.new
    
    File.open('成语u.txt','r') do |file|
      file.each do |line|
        idioms_array << line.chomp   #把成语词典折腾出来,作为array数组
      end
    end
    
    Benchmark.bm do |bm|
      bm.report {
        words.uniq.each do |word|
          idioms_array.map do |idiom|
            puts idiom if idiom =~ /^#{word}/ and words.include?(idiom[1]) and words.include?(idiom[2]) and words.include?(idiom[3])
          end
        end
      }
    end

         

          6.看到这里,大家发现了什么没有,其实上面说的都是在扯淡,不过恐怕没有几个人有耐心看到这里的吧。我的处理思想是有问题的,其实完全想多了。最简单的就是,从成语文件中读取,判断是否在字库中存在即可,下面的代码是秒速的,不到0.2秒结果就出来了,快2个数量级的差别。

    Windows版本:

    #coding: UTF-8
    require 'iconv'
    require 'benchmark'
    
    words = %w|无 黑 用 如 小 比 伦 材 脚 纸 四 表 两 得 一 字 天 大 朝 白 与 举 一 里|
    
    words_g = words.map {|x| Iconv.conv 'gbk', 'utf-8',x}.uniq #转码,另外把重复的字去除,后面用不到
    
    Benchmark.bm do |bm|
      bm.report {
        File.open('成语.txt','r') do |file|
          file.each do |line|
            puts line if words_g.include?(line[0]) and words_g.include?(line[1]) and words_g.include?(line[2]) and words_g.include?(line[3])
          end
        end
      }
    end


    Ubuntu版本:

    #coding: UTF-8
    require 'benchmark'
    
    words = %w|无 黑 用 如 小 比 伦 材 脚 纸 四 表 两 得 一 字 天 大 朝 白 与 举 一 里|
    
    Benchmark.bm do |bm|
      bm.report {
        File.open('成语u.txt','r') do |file|
          file.each do |line|
            puts line if words.include?(line[0]) and words.include?(line[1]) and words.include?(line[2]) and words.include?(line[3])
          end
        end
      }
    end


          7.大家使用的时候,可以把benchmark的部分屏蔽,反正就是要个结果而已。还有,因为我用的成语词典库不大,所以有很多查不到的,比如286关“胜友如云”,还有“置之脑后”"不可造次""巧用天时""寸土如金"“自始至终”“串通一气”等,遇上这些,大家还是用金币吧,不过应该不是很多。

          代码我放到下面的链接中了,只放最终的代码
          感谢能看到这里的朋友。

  • 相关阅读:
    更改eclipse(myeclipse) author的默认名字(注释的作者)
    Myecplise Tomcat 启动很慢
    Java Enum 比较用 == 还是 eques
    Spring JDBC查询返回对象代码跟踪
    Apache启动失败(Windows 无法在本地计算机启动Apache2.2)
    SQLServer2008 统计表占用空间
    SET IDENTITY_INSERT ON/OFF 权限
    字母出现频率
    统计单词数
    查找最大元素
  • 原文地址:https://www.cnblogs.com/qqrrm/p/3569839.html
Copyright © 2011-2022 走看看