<commit_before>require 'cinch'
require 'cinch/plugins/game_bot'
require 'rebellion_g54/game'
require 'rebellion_g54/role'

module Cinch; module Plugins; class RebellionG54 < GameBot
  include Cinch::Plugin

  xmatch(/choices/i, method: :choices, group: :rebellion_g54)
  xmatch(/me\s*$/i, method: :whoami, group: :rebellion_g54)
  xmatch(/whoami/i, method: :whoami, group: :rebellion_g54)
  xmatch(/table(?:\s+(##?\w+))?/i, method: :table, group: :rebellion_g54)
  xmatch(/status/i, method: :status, group: :rebellion_g54)

  xmatch(/help(?: (.+))?/i, method: :help, group: :rebellion_g54)
  xmatch(/rules/i, method: :rules, group: :rebellion_g54)

  xmatch(/settings(?:\s+(##?\w+))?$/i, method: :get_settings, group: :rebellion_g54)
  xmatch(/settings(?:\s+(##?\w+))? (.+)$/i, method: :set_settings, group: :rebellion_g54)

  xmatch(/roles\s+list/i, method: :list_possible_roles, group: :rebellion_g54)
  xmatch(/roles(?:\s+(##?\w+))?$/i, method: :get_roles, group: :rebellion_g54)
  xmatch(/roles(?:\s+(##?\w+))?\s+random(?:\s+(.+))?/i, method: :random_roles, group: :rebellion_g54)
  xmatch(/roles(?:\s+(##?\w+))? (.+)$/i, method: :set_roles, group: :rebellion_g54)

  xmatch(/peek(?:\s+(##?\w+))?/i, method: :peek, group: :rebellion_g54)

  xmatch(/(\S+)(?:\s+(.*))?/, method: :rebellion_g54, group: :rebellion_g54)

  common_commands

  class ChannelOutputter
    def initialize(bot, game, c)
      @bot = bot
      @game = game
      @chan = c
    end

    def player_died(user)
      @bot.player_died(user, @chan)
    end

    def new_cards(user)
      @bot.tell_cards(@game, user: user)
    end

    def puts(msg)
      @chan.send(msg)
    end
  end

  #--------------------------------------------------------------------------------
  # Implementing classes should override these
  #--------------------------------------------------------------------------------

  def game_class
    ::RebellionG54::Game
  end

  def do_start_game(m, game, options)
    success, error = game.start_game
    unless success
      m.reply(error, true)
      return
    end

    Channel(game.channel_name).send("Welcome to game #{game.id}, with roles #{game.roles}")
    order = game.users.map { |u| dehighlight_nick(u.nick) }.join(' ')
    Channel(game.channel_name).send("Player order is #{order}")

    # Tell everyone of their initial stuff
    game.each_player.each { |player| tell_cards(game, player: player, game_start: true) }

    game.output_streams << ChannelOutputter.new(self, game, Channel(game.channel_name))
    announce_decision(game)
  end

  def do_reset_game(game)
    chan = Channel(game.channel_name)
    info = table_info(game, show_secrets: true)
    chan.send(info)
  end

  def do_replace_user(game, replaced_user, replacing_user)
    tell_cards(game, replacing_user) if game.started?
  end

  def bg3po_invite_command(channel_name)
    # Nah, I don't want to do bg3po
  end

  #--------------------------------------------------------------------------------
  # Other player management
  #--------------------------------------------------------------------------------

  def player_died(user, channel)
    # Can't use remove_user_from_game because remove would throw an exception.
    # Instead, just do the same thing it does...
    channel.devoice(user)
    # I'm astounded that I can access my parent's @variable
    @user_games.delete(user)
  end

  def tell_cards(game, user: nil, player: nil, game_start: false)
    player ||= game.find_player(user)
    user ||= player.user
    turn = game_start ? 'starting hand' : "Turn #{game.turn_number}"
    user.send("Game #{game.id} #{turn}: #{player_info(player, show_secrets: true)}")
  end

  #--------------------------------------------------------------------------------
  # Game
  #--------------------------------------------------------------------------------

  def announce_decision(game)
    Channel(game.channel_name).send(decision_info(game, show_choices: true))
    game.choice_names.keys.each { |p|
      explanations = format_choice_explanations(game, p)
      User(p).send(explanations.map { |e| "[#{e}]" }.join(' '))
    }
  end

  def rebellion_g54(m, command, args = '')
    game = self.game_of(m)
    return unless game && game.started? && game.has_player?(m.user)

    success, error = game.take_choice(m.user, command, args || '')
<commit_msg>Split args and splat them into take_choice<commit_after>require 'cinch'
require 'cinch/plugins/game_bot'
require 'rebellion_g54/game'
require 'rebellion_g54/role'

module Cinch; module Plugins; class RebellionG54 < GameBot
  include Cinch::Plugin

  xmatch(/choices/i, method: :choices, group: :rebellion_g54)
  xmatch(/me\s*$/i, method: :whoami, group: :rebellion_g54)
  xmatch(/whoami/i, method: :whoami, group: :rebellion_g54)
  xmatch(/table(?:\s+(##?\w+))?/i, method: :table, group: :rebellion_g54)
  xmatch(/status/i, method: :status, group: :rebellion_g54)

  xmatch(/help(?: (.+))?/i, method: :help, group: :rebellion_g54)
  xmatch(/rules/i, method: :rules, group: :rebellion_g54)

  xmatch(/settings(?:\s+(##?\w+))?$/i, method: :get_settings, group: :rebellion_g54)
  xmatch(/settings(?:\s+(##?\w+))? (.+)$/i, method: :set_settings, group: :rebellion_g54)

  xmatch(/roles\s+list/i, method: :list_possible_roles, group: :rebellion_g54)
  xmatch(/roles(?:\s+(##?\w+))?$/i, method: :get_roles, group: :rebellion_g54)
  xmatch(/roles(?:\s+(##?\w+))?\s+random(?:\s+(.+))?/i, method: :random_roles, group: :rebellion_g54)
  xmatch(/roles(?:\s+(##?\w+))? (.+)$/i, method: :set_roles, group: :rebellion_g54)

  xmatch(/peek(?:\s+(##?\w+))?/i, method: :peek, group: :rebellion_g54)

  xmatch(/(\S+)(?:\s+(.*))?/, method: :rebellion_g54, group: :rebellion_g54)

  common_commands

  class ChannelOutputter
    def initialize(bot, game, c)
      @bot = bot
      @game = game
      @chan = c
    end

    def player_died(user)
      @bot.player_died(user, @chan)
    end

    def new_cards(user)
      @bot.tell_cards(@game, user: user)
    end

    def puts(msg)
      @chan.send(msg)
    end
  end

  #--------------------------------------------------------------------------------
  # Implementing classes should override these
  #--------------------------------------------------------------------------------

  def game_class
    ::RebellionG54::Game
  end

  def do_start_game(m, game, options)
    success, error = game.start_game
    unless success
      m.reply(error, true)
      return
    end

    Channel(game.channel_name).send("Welcome to game #{game.id}, with roles #{game.roles}")
    order = game.users.map { |u| dehighlight_nick(u.nick) }.join(' ')
    Channel(game.channel_name).send("Player order is #{order}")

    # Tell everyone of their initial stuff
    game.each_player.each { |player| tell_cards(game, player: player, game_start: true) }

    game.output_streams << ChannelOutputter.new(self, game, Channel(game.channel_name))
    announce_decision(game)
  end

  def do_reset_game(game)
    chan = Channel(game.channel_name)
    info = table_info(game, show_secrets: true)
    chan.send(info)
  end

  def do_replace_user(game, replaced_user, replacing_user)
    tell_cards(game, replacing_user) if game.started?
  end

  def bg3po_invite_command(channel_name)
    # Nah, I don't want to do bg3po
  end

  #--------------------------------------------------------------------------------
  # Other player management
  #--------------------------------------------------------------------------------

  def player_died(user, channel)
    # Can't use remove_user_from_game because remove would throw an exception.
    # Instead, just do the same thing it does...
    channel.devoice(user)
    # I'm astounded that I can access my parent's @variable
    @user_games.delete(user)
  end

  def tell_cards(game, user: nil, player: nil, game_start: false)
    player ||= game.find_player(user)
    user ||= player.user
    turn = game_start ? 'starting hand' : "Turn #{game.turn_number}"
    user.send("Game #{game.id} #{turn}: #{player_info(player, show_secrets: true)}")
  end

  #--------------------------------------------------------------------------------
  # Game
  #--------------------------------------------------------------------------------

  def announce_decision(game)
    Channel(game.channel_name).send(decision_info(game, show_choices: true))
    game.choice_names.keys.each { |p|
      explanations = format_choice_explanations(game, p)
      User(p).send(explanations.map { |e| "[#{e}]" }.join(' '))
    }
  end

  def rebellion_g54(m, command, args = '')
    game = self.game_of(m)
    return unless game && game.started? && game.has_player?(m.user)

    args = args ? args.split : []
    success, error = game.take_choice(m.user, command, *args)

{'fraction_non_alphanumeric': 0.2535485347985348, 'fraction_numerical': 0.010073260073260074, 'mean_word_length': 2.419569471624266, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1766243', 'n_tokens_mistral': 3045, 'n_tokens_neox': 2886, 'n_words': 615}