#!/usr/bin/env ruby require 'cgi' require 'cgi/session' require 'zlib' require "xmlrpc/client" CHOICE = [ 'アリス', 'ボブ', 'チャーリー', 'ドンキー', '降参', 'パス' ] HUMAN = [ 'アリス', 'ボブ', 'チャーリー', 'ドンキー' ] class HeadFoot def initialize File.open('hateww.html') do |ifile| cont = ifile.read i = cont.index('
') @head = cont[0...i] i = cont.index('
', i) @foot = cont[i+6..-1] end end def print_head print @head @head = '' end def print_foot print @foot @foot = '' end end def random_keyword File.open('keywords') do |ifile| ifile.seek(0, IO::SEEK_END) size = ifile.tell ifile.seek(rand(size-10), IO::SEEK_SET) ifile.readline w = ifile.readline while false ifile.seek(rand(size-10), IO::SEEK_SET) ifile.readline w = ifile.readline end w.chomp end end def relational_keywords(s) server = XMLRPC::Client.new("d.hatena.ne.jp", "/xmlrpc") res = server.call("hatena.getSimilarWord", { "wordlist" => s }) res['wordlist'].map {|v| v['word']} end def init_game while true root = random_keyword @s['root'] = root rels = relational_keywords(root) next if rels.size < 4 second = rels.delete_at(rand(rels.size)) # easier # reswords = nil # tmp_rels = relational_keywords(second) # while true # third = tmp_rels[rand(tmp_rels.size)] # next if third == root # @s['second'] = third # reswords = [ second, third ] # second = third # break # end @s['second'] = second reswords = [ second ] second_rels = relational_keywords(second) next if second_rels.empty? p2 = 14 p3 = 8 if second_rels.size < 3 p2 -= 1 if second_rels.size == 1 p3 -= 2 else p3 -= 1 end second_rels2 = relational_keywords(second_rels) next if second_rels.size + second_rels2.size < 4 while second_rels.size < 3 second_rels.push(second_rels2.delete_at(rand(second_rels2.size))) end else while second_rels.size > 3 second_rels.delete_at(rand(second_rels.size)) end end # @s['second_rels'] = second_rels.dup reswords += second_rels rels.delete_if {|i| reswords.include?(i) } if rels.size < 9 add = 9 - rels.size p3 += add if add > 3 p2 += add - 3 end rels2 = relational_keywords(rels) rels2.delete_if {|i| reswords.include?(i) } next if rels.size + rels2.size < 9 while rels.size < 9 rels.push(rels2.delete_at(rand(rels2.size))) end else while rels.size > 9 rels.delete_at(rand(rels.size)) end end # @s['rels'] = rels.dup wolf = rand(4) @s['wolf'] = wolf.to_s words = [] for i in 0...3 for j in 0...4 if j == wolf words.push(second_rels.shift) else words.push(rels.shift) end end end @s['words'] = words.join('|') @s['points'] = [ '20', p2.to_s, p3.to_s ].join('|') break end end def print_truth human = HUMAN.dup print %Q(

真相は以下の通り。

) wolf = human.delete_at(@s['wolf'].to_i) print %Q(

ワードウルフ: #{wolf} (#{@s['second']})

) print %Q(

その他: #{human.join(',')} (#{@s['root']})

) print_saying(2) end def print_saying(state) print %Q(

) end @q = CGI.new @s = CGI::Session.new(@q) @nojs = @q['nojs'] == '1' ? HeadFoot.new : nil print @q.header({ 'type' => 'text/html; charset=UTF-8', 'Cache-Control' => 'no-cache', 'Pragma' => 'no-cache', }) if @nojs @nojs.print_head end begin if @q.has_key?('highscore') hf = HeadFoot.new hf.print_head print "

ハイスコア

" print %Q(

トップへ

) hf.print_foot exit(0) elsif @q.has_key?('init') @s['state'] = '' elsif @q.has_key?('start') @s['state'] = '0' @s['score'] = '0' if @s['score'] == '' init_game elsif @q.has_key?('score') if @q.has_key?('name') @s['highscore'] = @s['record'] @s['name'] = @q['name'].to_s require 'pstore' db = PStore.new('score.db') db.transaction do name = @q['name'].to_s score = @s['record'].to_i prev = db[name].to_i if score > prev db[name] = score else print "

既に#{prev}点という記録があったので登録されない

" end end end @s['state'] = '' elsif @q.has_key?('choice') if @s['state'] !~ /^\d$/ @s['state'] = '' elsif @q.has_key?('q') now = Time.now prev = Time.at(@s['time'].to_i) state = @s['state'].to_i choice = @q['q'].to_i point = @s['points'].split('|')[state].to_i if now-prev > 60 @s['state'] = 'timeover' @s['record'] = @s['score'].to_i - (20 - point) @s['score'] = '0' elsif choice == 4 @s['state'] = 'giveup' @s['record'] = @s['score'].to_i - (20 - point) @s['score'] = '0' elsif choice == @s['wolf'].to_i @s['state'] = 'right' @s['score'] = @s['score'].to_i + point @s['curpt'] = point elsif choice != 5 || state >= 2 @s['state'] = 'wrong' @s['record'] = @s['score'].to_i - (40 - point) @s['score'] = '0' else @s['state'] = (state+1).to_s end else print '

どれか選んで下さい。

' end end state = @s['state'].to_s # async = (state == '' || state == 'right').to_s async = 'true' print %Q(
) if @nojs print %Q() end case state when '' print %Q(

4人のうち、3人は同じ単語から連想される単語をあげている。
ただ、残る1人、ワードウルフは、別の単語を元にしている。

さて、誰がワードウルフだろうか?

詳しい説明 / ハイスコア

) when 'right' print %Q(

正解!#{@s['curpt']}点獲得。

) print_truth print %Q( ) when 'wrong', 'timeover', 'giveup' case @s['state'] when 'wrong' print %Q(

はずれ

) when 'giveup' print %Q(

降参した

) when 'timeover' print %Q(

時間切れ

) else assert false end score = @s['record'].to_i print %Q(

#{score}点だった。

) print_truth if score > @s['highscore'].to_i print %Q(

ハイスコアですおめでとう。

(カラにしておくと登録されない) ) else print %Q( ) end else state = @s['state'].to_i point = @s['points'].split('|')[state].to_i print %Q(

今の得点は#{(@s['score'].to_i-20+point).to_i}点。 1分以内に回答すること。

) print_saying(state) print %Q(

ワードウルフは誰……?

) for i in 0 ... 5 + ((state < 2) ? 1 : 0) print %Q( #{CHOICE[i]}) end print %Q() end print '
' if @nojs @nojs.print_foot end @s['time'] = Time.now.to_i.to_s rescue print "

なんかエラー起きた

" print "

#{$!}

" print %Q(
#{$!.backtrace.join("\n")}
) print "

リロードするとか戻るとかして下さい。

" end