MOE3: 移動失敗後の維持への移動支援の無効
spec/models/main_phase_spec.rb
マニュアルの Diagram12、同等戦力のスタンドオフで移動に失敗した German A Mun-Sil
が支援付きの Austrian A Boh-Mun
に撃退される処理を実装する*1。
これは、移動支援は移動に失敗したユニットの維持には効果がないことの例示である。
describe MainPhase do describe "#resolve_orders" do let(:phase) { MainPhase.create } let(:resolved_orders) { phase.resolve_orders } #(略) shared_context "Diagram12 移動失敗後の維持には移動支援は適用されない", diagram: 12 do let(:army_boh) { FactoryGirl.create(:army, :a, :boh, phase: phase) } let(:army_tyr) { FactoryGirl.create(:army, :a, :tyr, phase: phase) } let(:army_mun) { FactoryGirl.create(:army, :g, :mun, phase: phase) } let(:army_ber) { FactoryGirl.create(:army, :g, :ber, phase: phase) } let(:army_war) { FactoryGirl.create(:army, :r, :war, phase: phase) } let(:army_pru) { FactoryGirl.create(:army, :r, :pru, phase: phase) } let(:prov_mun) { army_mun.province } let(:prov_sil) { Province.find_by(code: "sil") } let!(:move_boh_mun) { FactoryGirl.create(:move_order, unit: army_boh, destination: prov_mun) } let!(:supp_tyr_boh) { FactoryGirl.create(:support_order, unit: army_tyr, target: move_boh_mun) } let!(:move_mun_sil) { FactoryGirl.create(:move_order, unit: army_mun, destination: prov_sil) } let!(:supp_ber_mun) { FactoryGirl.create(:support_order, unit: army_ber, target: move_mun_sil) } let!(:move_war_sil) { FactoryGirl.create(:move_order, unit: army_war, destination: prov_sil) } let!(:supp_pru_war) { FactoryGirl.create(:support_order, unit: army_pru, target: move_war_sil) } end context "Diagram12", diagram: 12 do subject { resolved_orders } example { expect(subject.find(move_boh_mun).status).to eq OrderStatus::SUCCESS} example { expect(subject.find(supp_tyr_boh).status).to eq OrderStatus::SATISFIED } example { expect(subject.find(move_mun_sil).status).to eq OrderStatus::DISLODGED} example { expect(subject.find(supp_ber_mun).status).to eq OrderStatus::SATISFIED } example { expect(subject.find(move_war_sil).status).to eq OrderStatus::STANDOFF} example { expect(subject.find(supp_pru_war).status).to eq OrderStatus::SATISFIED } end end end
実行すると、German A Mun-Sil
が STANDOFF で Austrian A Boh-Mun
が FAILURE。
さて。失敗した移動命令に支援が効いているのか、失敗した移動命令への攻撃処理が抜けているのか。
MainPhase#resolve_attacks メソッド
スタンドオフを処理する MainPhase#resolve_conflicts
の次に実行されるのがこちら。
ざっと見た感じ、処理そのものに問題はなさそうだが。
# 維持ユニットへの攻撃 def resolve_attacks moves = @orders.select{|o| o.move?} moves.each do |move| hold = @orders.select{|o| o.hold? && o.province == move.dst}[0] unless hold unexecuted_move = @orders.select{|o| o.move? && o.src == move.dst}[0] move.success! unless unexecuted_move next end move_supports = @orders.select{|o| o.support? && o.target?(move)}.size hold_supports = @orders.select{|o| o.support? && o.target?(hold)}.size if move_supports > hold_supports move.success! hold.dislodged! else move.failure! hold.success! if hold.unexecuted? end end end
これはあれだ、SupportOrder#target?
で、支援対象の移動命令が失敗済みなら false
を返すようにすれば良いはずだ。きっと。
SupportOrder#target? メソッド
before。
def target?(order) return false if self.target.unit != order.unit return false if self.target.dst != order.dst true end
after。
def target?(order) return false if self.target.unit != order.unit return false if self.target.dst != order.dst return false if self.target.move? != order.move? true end
MoveOrder#move?
は UNEXECUTED の時だけ true
を返すことを思い出して欲しい。
一方で支援命令が保有する標本命令のステータスは UNEXECUTED のまま。
つまり標本命令が MoveOrder
なら move?
は常に true
を返すから、これで move?
が false
を返す失敗済みの移動命令は支援対象として認識されなくなるわけだ。
……うーむ、直観的ではないな。
とにかくテスト
実行。オールグリーン。完了。
MoveOrder#move?
と SupportOrder#target?
の複合技はちょっとトリッキーなので、どこかで見直ししないと未来の自分が理解できなくなりそうな不安がある。注意。
*1:ユニット数が多くて全部書くのめんどい。