MOE3: 行軍解決処理のリファクタリング
行軍解決終了時の未処理命令の一律成功処理
そのうちなんとかすると言ったな。あれは嘘だ。
やはり行軍解決処理が終了する時点で未処理命令が残っているのは好ましくない。
気になるのでさっさと片付けてしまおう。
エラー状況の確認
まず MainPhase#cleanup
の一律成功処理を外してテストを実行してみる。
def cleanup @orders.each do |order| #order.success! if order.unexecuted? # 暫定コメントアウト order.save! end end
すると当然、French F Gol-Tyn
が UNEXECUTED のままなので、前回最後に追加したテストがエラーになる。
MainPhase#resolve_attack メソッドの修正
処理の順番的に resolve_conflicts
の次に来るのが resolve_attack
である。
現状、移動先に維持命令がない場合はその移動命令の成否判定をスキップする仕様だが、これを変更する。移動先に維持命令がなければその移動は成功でいいじゃないか。
というわけで Before。
# 維持ユニットへの攻撃 def resolve_attack moves = @orders.select{|o| o.move?} moves.each do |move| hold = @orders.select{|o| o.hold? && o.province == move.dst}[0] next unless hold 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
そして after。
# 維持ユニットへの攻撃 def resolve_attack moves = @orders.select{|o| o.move?} moves.each do |move| hold = @orders.select{|o| o.hold? && o.province == move.dst}[0] unless hold move.success! 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
おや、Diagram6 のテストがエラーになってしまった。
交換移動の 2 命令が SUCCESS
になっている。
MainPhase#resolve_attack メソッドの追加修正
成功確定条件が「移動先に維持命令がない」だけだと、resolve_rotation
の前に交換移動命令がそれぞれ SUCCESS
で確定してしまうのが問題。
条件に「移動先に未解決の移動命令がない」も追加する。
# 維持ユニットへの攻撃 def resolve_attack 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
テスト。はい OK。
ちょっと泥臭い書き方になったので気が向いたら綺麗にしておこう。
こっそり修正
MainPhase#resolve_move
と MainPhase#resolve_attack
のメソッド名を、それぞれ resolve_moves
、resolve_attacks
に修正。
主に気分の問題。
MainPhase#resolve_holds メソッド
孤独な維持命令の成功確定処理も忘れないうちに書くだけ書いてしまおう。実行タイミングは apply_supports の次でいいか。
本当はテストを先に書くべきなのだが時には勢いも大切だよね。
def resolve_orders setup apply_supports resolve_holds resolve_moves resolve_conflicts resolve_attacks resolve_pileup resolve_rotation cleanup orders(true) end #(略) # 干渉を受けない維持 def resolve_holds holds = @orders.select{|o| o.hold?} holds.each do |hold| moves = @orders.select{|o| o.move? && o.dst == hold.province} next if moves.size != 0 next unless hold.unexecuted? hold.success! end end
hold?
で true
を返すすべての未処理命令を SUCCESS
にしてしまうので、輸送成否判定を実装する時は resolve_holds の前に入れる必要があることだけ覚えておこう。
そしてテスト。もちろん問題なし。
後始末
お終いに MainPhase#cleanup
を綺麗にして完了。お疲れ。
def cleanup @orders.each do |order| order.save! end end