Skip to content

Instantly share code, notes, and snippets.

@gouf
Last active October 24, 2024 23:02
Show Gist options
  • Save gouf/140bd5c60f9ccd2616b08462be0cfb51 to your computer and use it in GitHub Desktop.
Save gouf/140bd5c60f9ccd2616b08462be0cfb51 to your computer and use it in GitHub Desktop.
5 10
8 2 24 40 25 42 26
59 48 13 21 13 56 2
5 59 7 57 5 25 24
99 28 6 32 5 23 2
62 24 19 11 19 7 21
2 1 3 2
2 1 3 2
5 1 3 1
5 3 1 2
1 1 2 2
4 2 3 1
5 3 3 2
2 3 3 2
4 1 5 3
2 3 3 2
# frozen_string_literal: true
# 戦士
# 体力があり、3つの攻撃スキルを持っている
class Fighter
attr_reader :id, :skills
attr_accessor :health
def initialize(id, health, skills)
@id = id
@health = health
@skills = skills
@current_skill = nil
end
def attack_skill(index)
@current_skill = skills_at(index)
end
def attack_power
@current_skill.attack_power
end
def attack_delay
@current_skill.attack_delay
end
def available_to_fight?
health.positive?
end
private
def skills_at(index)
special_attack! if special_attack?(index)
@skills.at(index - 1)
end
def special_attack?(index)
@skills.at(index - 1).then(&:special_attack?)
end
def special_attack!
@skills.each(&:obtain_buff!)
end
end
class Fighter
# 戦士が使う攻撃スキル
# 攻撃速度と攻撃力を持っている
# 攻撃速度と攻撃力がゼロの場合は、強化技を表す
class AttackSkill
ATTACK_SPEED_BUFF = -3
ATTACK_POWER_BUFF = 5
attr_reader :attack_delay, :attack_power
def initialize(attack_delay, attack_power)
@attack_delay = attack_delay
@attack_power = attack_power
end
def special_attack?
attack_delay.zero? && attack_power.zero?
end
# スキルを強化する
# 攻撃速度と攻撃力が上昇する
def obtain_buff!
return if special_attack? # 強化技自身の場合は何もしない
@attack_delay += ATTACK_SPEED_BUFF
@attack_power += ATTACK_POWER_BUFF
@attack_delay = 1 if @attack_delay <= 0 # 攻撃速度が速くなりすぎないように補正を入れる
end
end
end
# 戦闘ステージ
# 体力の続く限り、戦士同士を戦わせて、最後に生き残った戦士の数を返す
class FightStage
def initialize(fighters, attacks_rounds)
@fighters = fighters
@attack_rounds = attacks_rounds
end
def fight!
run_fight_loop!
@fighters.find_all(&:available_to_fight?).size
end
private
# 指定されたインデックスに対応する戦士とスキルを取得・設定する
def find_fighter_and_set_skill(fighter_id, skill_index)
fighter = @fighters.find { _1.id.eql?(fighter_id) }
fighter.attack_skill(skill_index)
fighter
end
# 戦闘に参加する2組の戦士を取得する
def find_fighters(attack_round)
attack_round.fighters.map do |fighter|
find_fighter_and_set_skill(*fighter)
end
end
def run_fight_loop!
@attack_rounds.each do |attack_round|
fighter1, fighter2 = find_fighters(attack_round)
# どちらかが戦闘不能の場合、なにもしない
next unless [fighter1, fighter2].any?(&available_to_fight?)
# 攻撃速度に応じて、どちらの戦士が攻撃できるかを判定する
# 攻撃速度が相手より優っている場合は、相手の体力を削る事が出来る
if fighter1.attack_delay.eql?(fighter2.attack_delay)
# なにもしない
elsif fighter1.attack_delay < fighter2.attack_delay
fighter2.health -= fighter1.attack_power
else
fighter1.health -= fighter2.attack_power
end
end
end
end
class FightStage
# 戦士が戦う相手とスキル、それぞれ1回戦分を保持する
class AttackRound
attr_reader :fighter1_id, :skill1_index, :fighter2_id, :skill2_index
def initialize(fighter1_id, skill1_index, fighter2_id, skill2_index)
@fighter1_id = fighter1_id
@skill1_index = skill1_index
@fighter2_id = fighter2_id
@skill2_index = skill2_index
end
def fighter1
[@fighter1_id, @skill1_index]
end
def fighter2
[@fighter2_id, @skill2_index]
end
def fighters
[fighter1, fighter2]
end
end
end
# メイン処理
# 戦士達のステータスやスキル情報・行動取得と戦闘ステージでの戦闘を実行する
class Solver
def solve!
input
fight_stage = FightStage.new(@fighters, @attack_rounds)
fight_stage.fight!
end
private
def input
@number_of_fighters, @number_of_rounds = gets.chomp.split.map(&:to_i)
input_fighters
input_attack_rounds
end
def input_fighters
@fighters =
@number_of_fighters.times.map do |index|
health, *attack_elements = splat_fighter_params
attack_skills =
attack_elements.map do |attack_delay, attack_power|
Fighter::AttackSkill.new(attack_delay, attack_power)
end
Fighter.new(index + 1, health, attack_skills)
end
end
# 戦士達が、誰に対してどのスキルを使い、戦いを進めていくかを取得する
# ここでは 2人の戦士のIDと、それぞれのスキルのインデックスを取得する
def input_attack_rounds
@attack_rounds =
@number_of_rounds.times.map do
fighter1, skill1, fighter2, skill2 = gets.split.map(&:to_i)
FightStage::AttackRound.new(fighter1, skill1, fighter2, skill2)
end
end
# 戦士の体力と3つのスキルを取得する
def splat_fighter_params
health, *params = gets.split.map(&:to_i)
attack_delay1, attack_power1, *params = params
attack_delay2, attack_power2, *params = params
attack_delay3, attack_power3 = params
[
health,
[attack_delay1, attack_power1],
[attack_delay2, attack_power2],
[attack_delay3, attack_power3]
]
end
end
solver = Solver.new
#
# ruby main.rb < input.txt
#
puts solver.solve! # => 3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment