MOE3: スタンドオフの解決
spec/models/main_phase_spec.rb
まずテストを書く。
マニュアルの Diagram4、German A Ber–Sil
と Russian A War–Sil
のスタンドオフ処理を実装する。
ちなみに Diagram2 は 1 と同じ単純移動(ただし海軍)なので省略。
Diagram3 は海軍にとっての非隣接地域への移動不可に関する事例ということで、MainPhase#resolve_orders
の守備範囲外(不可能命令は登録する段階で弾く予定)なので省略。
describe MainPhase do describe "#resolve_orders" do let(:phase) { MainPhase.create } let(:resolved_orders) { phase.resolve_orders } #(略) shared_context "Diagram4 スタンドオフ", diagram: 4 do let(:army_ber) { FactoryGirl.create(:army, :g, :ber, phase: phase) } let(:army_war) { FactoryGirl.create(:army, :r, :war, phase: phase) } let(:prov_sil) { Province.find_by(code: "sil") } let!(:move_ber_sil) { FactoryGirl.create(:move_order, unit: army_ber, destination: prov_sil) } let!(:move_war_sil) { FactoryGirl.create(:move_order, unit: army_war, destination: prov_sil) } end context "Diagram4", diagram: 4 do subject { resolved_orders } example { expect(subject.find(move_ber_sil).status).to eq OrderStatus::STANDOFF } example { expect(subject.find(move_war_sil).status).to eq OrderStatus::STANDOFF } end end end
MainPhase#resolve_standoff メソッド
ここでも戦力評価の実装は後回し。
- 未処理の
MoveOrder
オブジェクトを全て取得。- 移動先一つ一つについて競合する移動命令があるかチェック。
- 移動先が競合した場合は問答無用でスタンドオフにする。
なんやかんやでこの形。
class MainPhase < Phase def resolve_orders setup resolve_move resolve_standoff cleanup orders(true) end #(略) # スタンドオフ def resolve_standoff moves = @orders.select{|o| o.move?} moves.collect{|m| m.dst}.uniq.each do |dst| conflicts = moves.select{|m| m.dst == dst} next if conflicts.size == 1 conflicts.each do |m1| m1.standoff! end end end #(略) end
MoveOrder#move?
は成否を問わず処理済みなら false を返すようにしてみた。
class MoveOrder < Order #(略) def move? # 処理済の移動命令は移動命令として扱わない return true if unexecuted? false end def standoff! self.status = OrderStatus::STANDOFF end end