jalyna/oakdex-battle

View on GitHub
lib/oakdex/battle.rb

Summary

Maintainability
A
0 mins
Test Coverage
require 'oakdex/pokemon'

require 'oakdex/battle/in_battle_pokemon'
require 'oakdex/battle/trainer'
require 'oakdex/battle/move_execution'
require 'oakdex/battle/action'
require 'oakdex/battle/damage'
require 'oakdex/battle/turn'
require 'oakdex/battle/valid_action_service'
require 'oakdex/battle/side'
require 'oakdex/battle/active_in_battle_pokemon'

module Oakdex
  # Represents battle, with has n turns and m sides
  class Battle
    attr_reader :log, :actions, :team1, :team2,
                :sides, :current_log

    def initialize(team1, team2, options = {})
      @team1 = team1.is_a?(Array) ? team1 : [team1]
      @team2 = team2.is_a?(Array) ? team2 : [team2]
      @options = options
      @sides = []
      @log = []
      @current_log = []
      @actions = []
      @turns = []
      @sides = [@team1, @team2].map do |team|
        Side.new(self, team)
      end
    end

    def pokemon_per_side
      @options[:pokemon_per_side] || @team1.size
    end

    def valid_actions_for(trainer)
      valid_action_service.valid_actions_for(trainer)
    end

    def add_action(trainer, action)
      return false unless valid_actions_for(trainer).include?(action)
      @actions << Action.new(trainer, action)
      true
    end

    def simulate_action(trainer)
      valid_actions = valid_actions_for(trainer)
      return false if valid_actions.empty?
      add_action(trainer, valid_actions.sample)
    end

    def continue
      return start if @log.empty?
      return false unless trainers.all? { |t| valid_actions_for(t).empty? }
      execute_actions
      true
    end

    def finished?
      !fainted_sides.empty?
    end

    def winner
      return if fainted_sides.empty?
      (sides - fainted_sides).flat_map(&:trainers)
    end

    def add_to_log(*args)
      @current_log << args.to_a
    end

    def remove_fainted
      sides.each(&:remove_fainted)
    end

    def side_by_id(id)
      sides.find { |s| s.id == id }
    end

    def trainers
      sides.flat_map(&:trainers)
    end

    def pokemon_by_id(id)
      trainers.each do |trainer|
        trainer.team.each do |p|
          return p if p.id == id
        end
      end

      nil
    end

    def to_h
      {
        finished: finished?,
        pokemon_per_side: pokemon_per_side,
        sides: sides.map(&:to_h)
      }
    end

    private

    def valid_action_service
      @valid_action_service ||= ValidActionService.new(self)
    end

    def fainted_sides
      sides.select(&:fainted?)
    end

    def start
      sides.each(&:send_to_battle)
      finish_turn
      true
    end

    def execute_actions
      @turns << Turn.new(self, @actions).tap(&:execute)
      finish_turn
    end

    def finish_turn
      @log << @current_log
      @current_log = []
      @actions = []
    end
  end
end