4 # :title: Hangman Plugin
6 # Author:: Raine Virta <rane@kapsi.fi>
7 # Copyright:: (C) 2009 Raine Virta
10 # Hangman game for rbot
13 SITE = "http://coyotecult.com/tools/randomwordgenerator.php"
16 res = Net::HTTP.post_form(URI.parse(SITE), {'numwords' => count})
17 words = res.body.scan(%r{<a.*?\?w=(.*?)\n}).flatten
19 count == 1 ? words.first : words
24 attr_reader :misses, :guesses, :word, :letters
26 STAGES = [' (x_x) ', ' (;_;) ', ' (>_<) ', ' (-_-) ', ' (o_~) ', ' (^_^) ', '\(^o^)/']
27 HEALTH = STAGES.size-1
30 def initialize(word, channel=nil)
39 # array of the letters in the word
40 @word.split(//).reject { |c| c !~ LETTER }
48 @word.split(//).map { |c|
49 @guesses.include?(c) || c !~ LETTER ? c : "_"
57 if str !~ /^#{LETTER}$/
58 word == str ? @solved = true : punish
59 else # single letter guess
60 return false if @guesses.include?(str) # letter has been guessed before
62 unless letters.include?(str)
76 (letters-@guesses).empty? || @solved
88 class HangmanPlugin < Plugin
94 def help(plugin, topic="")
97 #plugin.map "hangman [play] [on :channel] [with word :word] [with [:adj] length [:relation :size]]",
98 return "hangman game plugin - topics: play, stop"
100 return "hangman play [on <channel>] [with word <word>] | hangman play with [max|min] length [<|>|==] [<length>] => start a hangman game -- word will be randomed in case it's omitted"
102 return "hangman stop => quits the current game"
107 word = unless params[:word]
108 words = RandomWord::get(100)
110 if adj = params[:adj]
111 words = words.sort_by { |e| e.size }
118 elsif params[:relation] && params[:size]
119 words = words.select { |w| w.size.send(params[:relation], params[:size].to_i) }
124 m.reply "suitable word not found in the set"
136 if (params[:channel] || m.public?)
137 target = if m.public?
143 # is the bot on the channel?
144 unless @bot.server.channels.names.include?(target.to_s)
145 m.reply "i'm not on that channel"
149 if @games.has_key?(target)
150 m.reply "there's already a hangman game in progress on that channel"
154 @bot.say target, "#{m.source} has started a hangman -- join the fun!"
156 target = m.source.to_s
159 @games[target] = Hangman.new(word)
161 @bot.say target, game_status(@games[target])
165 source = if m.public?
171 if @games.has_key?(source.to_s)
172 @bot.say source, "oh well, the answer would've been #{Bold}#{@games[source.to_s].word}#{Bold}"
173 @games.delete(source.to_s)
178 source = if m.public?
184 if (game = @games[source])
185 if m.message =~ /^[^\W0-9_]$/u || m.message =~ prepare_guess_regex(game)
186 return unless game.guess(m.message)
188 m.reply game_status(game)
193 m.reply "game over - you win!"
195 m.reply "game over - you lose!"
198 @games.delete(source)
203 def prepare_guess_regex(game)
204 Regexp.new("^#{game.word.split(//).map { |c|
205 game.guesses.include?(c) || c !~ Hangman::LETTER ? c : '[^\W0-9_]'
209 def game_status(game)
210 "%{word} %{face} %{misses}" % {
211 :word => game.over? ? "#{Bold}#{game.word}#{Bold}" : game.to_s,
213 :misses => game.misses.map { |e| e.upcase }.join(" ")
218 plugin = HangmanPlugin.new
219 plugin.map "hangman [play] [on :channel] [with word :word] [with [:adj] length [:relation :size]]",
221 :requirements => { :adj => /min|max/, :relation => /<|<=|>=|>|==/, :size => /\d+/ }
223 plugin.map "hangman stop", :action => 'stop'