MOE3: 単純移動命令の解決
MainPhase#resolve_move メソッド
先にテストを書く。
resolve_move
自体は private メソッドの位置付けで*1、実装が進むと名前や扱いが変わる可能性がある、というかその余地を縛りたくないので、テストはあくまで MainPhase#resolve_orders
を対象としたものになる。
spec/main_phase_spec.rb
マニュアルの Diagram1 から French A Par-Bur
を実装する。
describe MainPhase do describe "#resolve_orders" do let(:phase) { MainPhase.create } let(:resolved_orders) { phase.resolve_orders } shared_context "単純移動 Diagram1", diagram: 1 do let(:army_par) { FactoryGirl.create(:army, :f, :par, phase: phase) } let(:prov_bur) { Province.where(code: "bur").first } let!(:move_par_bur) { FactoryGirl.create(:move_order, unit: army_par, destination: prov_bur) } end context "Diagram1", diagram: 1 do subject { resolved_orders } example { expect(subject.find(move_par_bur).status).to eq OrderStatus::SUCCESS } end end end
MainPhase#resolve_orders
実行後、命令ステータスが OrderStatus::SUCCESS
になれば良い。
MainPhase#resolve_orders
では実装しよう。
事前に実験したところ ActiveRecord の遅延評価とキャッシュが邪魔になりそうだったので*2、予めクエリ結果を配列として取得しておき、全てをオンメモリで処理した後に一括で save!
することにした。
class MainPhase < Phase def resolve_orders setup resolve_move cleanup orders(true) end def setup @orders = orders.where(sample: false).to_a end def resolve_move moves = @orders.select{|o| o.move? && o.unexecuted?} moves.collect{|m| m.dst}.uniq.each do |dst| holds = @orders.select{|o| o.hold? && o.province == dst} return if holds.size != 0 move, *conflicts = moves.select{|m| m.dst == dst} return if conflicts.size != 0 move.success! end end def cleanup @orders.each do |order| order.save! end end end
setup
事前準備として、orders
のクエリに対して「標本命令以外」を指定して取得した結果を配列化している。
いずれ「仮想命令以外」も条件として追加するが、こちらはクエリ条件ではなく、配列化後に Array#select
で絞り込むのが楽なはずだ。
そのためには、命令者の担当国とユニットの所属国が異なる場合に true
を返してくれる Order#assumed?
メソッドが欲しいので Player
モデルの実装までお預け。
resolve_move
戦力の実装はもう少し先なので、ここでは戦力評価抜きで確定する移動命令を確定させてしまう。
MainPhase#resolve_move の仕様
- 移動先に維持命令を受けた軍があったら処理保留。
- 移動先が競合する移動命令があったら処理保留。
- 残りは移動成功。
Order#hold?
、Order#move?
、Order#unexecuted?
、Order#success!
は楽をするために導入。hold?
と move?
は派生クラスで適宜オーバーライドする。
MoveOrder#hold?
は基本的に false
を返すが、移動失敗が確定していたら true
を返すと便利になるような気がしないでもない。
cleanup
この時点ですべての命令に対する処理が完了しているので一つずつ DB に保存する。