module BomPoker
Constants
- DEFAULT_BET
- PAYOUT_MULTIPLIER
- PLUGIN
- STYLE_LOSE
- STYLE_TITLE
- STYLE_WIN
Public Instance Methods
Source
# File lib/bom_poker.rb, line 67 def observed_max_celsius(forecast) days = forecast[:days] || [] yesterday = days.reject { |day| day[:period].to_s.match?(/rest of/i) }[1] return nil unless yesterday parse_max_celsius(yesterday[:max]) || parse_max_celsius(yesterday[:min]) end
Source
# File lib/bom_poker.rb, line 54 def parse_max_celsius(text) match = text.to_s.match(/(\d+(?:\.\d+)?)\s*°?\s*C/i) match ? match[1].to_f : nil end
Source
# File lib/bom_poker.rb, line 22 def parse_poker_args(parts) tokens = Array(parts).map(&:to_s) return { error: usage_message } if tokens.empty? case tokens[0].downcase when "start" location = tokens[1..].reject { |t| t.match?(/\A\d+\z/) }.join(" ").strip amount = DEFAULT_BET amount = tokens.find { |t| t.match?(/\A\d+\z/) }.to_i if tokens.any? { |t| t.match?(/\A\d+\z/) } return { error: "Usage: !bom poker start <location> [amount]" } if location.empty? unless Game.valid_amount?(amount) return { error: "Bet amount must be between #{Game::MIN_BET} and #{Game::MAX_BET} credits." } end { action: :start, location: location, amount: amount } when "over", "under" pick = tokens[0].downcase.to_sym amount = DEFAULT_BET amount = tokens[1].to_i if tokens[1]&.match?(/\A\d+\z/) unless Game.valid_amount?(amount) return { error: "Bet amount must be between #{Game::MIN_BET} and #{Game::MAX_BET} credits." } end { action: :bet, pick: pick, amount: amount } when "settle" { action: :settle } else { error: usage_message } end end
Source
# File lib/bom_poker.rb, line 97 def place_bet(network:, channel:, user:, pick:, amount:, store: RabbotDb) round = GameStore.load(plugin: PLUGIN, network: network, channel: channel, store: store) return { error: "No Forecast Poker round — !bom poker start <location>" } unless round balance = Game.balance_for(user, store: Game.default_store) if balance < amount return { error: "#{user}, you need #{amount} credits (balance: #{balance})." } end key = GameStore.norm_nick(user) return { error: "#{user}, you already placed a bet." } if round["bets"][key] Game.deduct_bet(user, amount, store: Game.default_store) round = round.dup round["bets"] = round["bets"].dup round["bets"][key] = { "pick" => pick.to_s, "amount" => amount } GameStore.save(plugin: PLUGIN, network: network, channel: channel, game: round, store: store) { message: "#{user} bet #{pick} #{amount} on #{round['place']} max #{round['target_max'].round} °C" } end
Source
# File lib/bom_poker.rb, line 120 def settle_round(network:, channel:, forecast:, store: RabbotDb) round = GameStore.load(plugin: PLUGIN, network: network, channel: channel, store: store) return { error: "No Forecast Poker round to settle." } unless round actual = observed_max_celsius(forecast) || tomorrow_forecast_max(forecast) return { error: "Could not determine actual max temperature." } unless actual target = round["target_max"].to_f lines = [ IrcFormat.report_header(tag: "BOM", title: "Forecast Poker settled", style: STYLE_TITLE), "#{round['place']} — forecast #{target.round} °C, actual #{actual.round} °C" ] (round["bets"] || {}).each do |nick, bet| pick = bet["pick"].to_sym amount = bet["amount"].to_i won = (pick == :over && actual > target) || (pick == :under && actual < target) winnings = won ? amount * PAYOUT_MULTIPLIER : 0 Game.credit_winnings(nick, winnings, store: Game.default_store) if winnings.positive? balance = Game.balance_for(nick, store: Game.default_store) style = won ? STYLE_WIN : STYLE_LOSE word = won ? "WIN" : "LOSS" lines << "#{nick} #{pick} #{amount} — #{IrcFormat.decorate(word, style)} (balance #{balance})" end GameStore.clear(plugin: PLUGIN, network: network, channel: channel, store: store) lines << IrcFormat.report_footer("Bureau of Meteorology") { message: lines.join("\n") } end
Source
# File lib/bom_poker.rb, line 75 def start_round(network:, channel:, location:, amount:, forecast:, store: RabbotDb) max = tomorrow_forecast_max(forecast) return { error: "Could not read tomorrow's max temperature from BOM forecast." } unless max round = { "location" => location, "place" => forecast[:place], "target_max" => max, "default_amount" => amount, "bets" => {} } GameStore.save(plugin: PLUGIN, network: network, channel: channel, game: round, store: store) { message: [ IrcFormat.report_header(tag: "BOM", title: "Forecast Poker · #{forecast[:place]}", style: STYLE_TITLE), "BOM forecasts tomorrow's max at #{max.round} °C", "Bet over or under with !bom poker over|under [amount] (default #{amount} credits)", IrcFormat.report_footer("settle with !bom poker settle", "Bureau of Meteorology") ].join("\n") } end
Source
# File lib/bom_poker.rb, line 59 def tomorrow_forecast_max(forecast) days = forecast[:days] || [] tomorrow = days.reject { |day| day[:period].to_s.match?(/rest of/i) }.first return nil unless tomorrow parse_max_celsius(tomorrow[:max]) end
Source
# File lib/bom_poker.rb, line 18 def usage_message "Usage: !bom poker start <location> [amount] | over|under [amount] | settle" end