Files
kondiplo_front/app/services/turn_processing_service.rb
kontei f25fd6f802
Some checks failed
CI / scan_ruby (push) Has been cancelled
CI / scan_js (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled
CI / system-test (push) Has been cancelled
フロントエンドプレイアブル
2026-02-15 14:57:17 +09:00

136 lines
5.1 KiB
Ruby
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
class TurnProcessingService
def initialize(turn, client: GameApiClient.new)
@turn = turn
@game = turn.game
@client = client
end
def process(force: false)
# Check for unsubmitted orders in multiplayer
if !@game.solo_mode? && !@game.all_orders_submitted?
unless force == "true"
return { success: false, message: "全プレイヤーの命令入力が完了していません。強制ターン終了ボタンを使用してください。" }
end
end
current_orders = @turn.orders || {}
# 非人間プレイヤーのランダム命令を事前に生成(ターン処理の前に)
if @game.auto_order_mode == "random" && !@game.solo_mode?
# ゲーム状態から全国のリストを取得(参加者だけでなく全国にランダム命令を生成)
all_powers = @turn.game_state&.dig("units")&.keys || []
submitted_powers = current_orders.keys.map(&:upcase)
all_powers.each do |power|
# 既に命令が提出済みならスキップ
next if submitted_powers.include?(power.upcase)
auto_orders_response = @client.api_calculate_auto_orders(@turn.game_state, power)
if auto_orders_response && auto_orders_response["orders"]
current_orders[power] = auto_orders_response["orders"]
end
end
# 自動生成した命令を現在のターンに保存
@turn.update_columns(orders: current_orders) if current_orders.present?
end
# 現在のターンにALL SVG全プレイヤーの命令を含む画像を保存
# 履歴モードで「このターンでどんな命令が出されたか」を表示するため
if current_orders.present?
current_svg_orders = @turn.svg_orders || {}
all_svg_current = @client.api_render(@turn.game_state, orders: current_orders)
if all_svg_current
current_svg_orders["ALL"] = all_svg_current
@turn.update_columns(svg_orders: current_svg_orders)
end
end
# Calculate next state
process_response = @client.api_calculate_process(@turn.game_state, current_orders)
unless process_response
return { success: false, message: "ターン処理に失敗しました。" }
end
new_game_state = process_response["game_state"]
# Transaction to ensure data consistency
Game.transaction do
# Create next turn foundation
possible_orders = @client.api_calculate_possible_orders(new_game_state, by_power: true)
svg = @client.api_render(new_game_state, orders: nil)
new_turn = @game.turns.build(
number: @turn.number + 1,
game_state: new_game_state,
orders: {},
phase: new_game_state&.dig("name"),
possible_orders: possible_orders,
svg_date: svg,
svg_orders: { "NONE" => svg }
)
# Save new turn
if new_turn.save
# Reset orders_submitted flag
@game.participants.update_all(orders_submitted: false) unless @game.solo_mode?
# ハウスルール: 勝利条件判定
result = check_victory_conditions(new_turn, new_game_state)
return result if result
{ success: true, message: "ターンを終了し、次のフェーズへ進みました。" }
else
{ success: false, message: "次のターンの作成に失敗しました: #{new_turn.errors.full_messages.join(', ')}" }
end
end
rescue StandardError => e
Rails.logger.error("Turn processing failed: #{e.message}")
Rails.logger.error(e.backtrace.join("\n"))
{ success: false, message: "予期せぬエラーが発生しました。" }
end
private
def check_victory_conditions(new_turn, new_game_state)
centers = new_game_state&.dig("centers") || {}
# 1. ソロ勝利判定
if @game.solo_victory?(new_game_state)
winner = @game.solo_victory_power(new_game_state)
finish_game(new_turn, "solo", [ winner ])
return { success: true, message: "#{winner}#{@game.victory_sc_count} SC を獲得し、ソロ勝利しました!" }
end
# 2. 年数制限判定
if @game.year_limit_reached?(new_turn.phase)
# SC数最多の国が勝者、同数なら引き分け
max_sc = centers.values.map(&:size).max
winners = centers.select { |_power, scs| scs.size == max_sc }.keys
finish_game(new_turn, winners.size == 1 ? "year_limit_solo" : "year_limit_draw", winners)
result_type = winners.size == 1 ? "#{winners.first} の勝利" : "#{winners.join(', ')} の引き分け"
return { success: true, message: "年数制限(#{@game.year_limit}年)に達しました。#{result_type}です。" }
end
nil
end
def finish_game(last_turn, result_type, winners)
# 完了ターンを作成
Turn.create!(
game: @game,
number: last_turn.number + 1,
game_state: last_turn.game_state,
orders: {},
possible_orders: {},
phase: "COMPLETED",
svg_date: last_turn.svg_date,
svg_orders: last_turn.svg_orders
)
@game.update!(status: "finished")
Rails.logger.info("Game #{@game.id} finished: #{result_type}, winners: #{winners.join(', ')}")
end
end