Skip to content

Commit

Permalink
Merge pull request #11394 from michaeljb/1822-local-mail
Browse files Browse the repository at this point in the history
[1822 family] fix Mail Contract interactions with permanent L-trains
  • Loading branch information
ollybh authored Dec 15, 2024
2 parents 78bb15f + 8afaea4 commit 8fe9584
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 47 deletions.
31 changes: 21 additions & 10 deletions lib/engine/game/g_1822/game.rb
Original file line number Diff line number Diff line change
Expand Up @@ -882,14 +882,17 @@ def train_help(_entity, runnable_trains, _routes)
'the value of its destination station. This only applies to one train per operating turn.'
end

if mail_contracts
help << 'Mail contract(s) gives a subsidy equal to one half of the base value of the start and end '\
'stations from one of the trains operated. Doubled values (for E trains or destination tokens) '\
'do not count.'
end
help << train_help_mail_contracts if mail_contracts

help
end

def train_help_mail_contracts
'Mail contract(s) gives a subsidy equal to one half of the base value of the start and end '\
'stations from one of the trains operated. Doubled values (for E trains or destination tokens) '\
'do not count. L-trains cannot use mail contracts.'
end

def init_companies(players)
game_companies.map do |company|
next if players.size < (company[:min_players] || 0)
Expand Down Expand Up @@ -1741,13 +1744,21 @@ def mail_contract_bonus(entity, routes)
mail_bonuses = routes.map do |r|
stops = r.visited_stops
next if stops.size.zero?
next if stops.size < 2 && !self.class::LOCAL_TRAIN_CAN_CARRY_MAIL

first = stops.first.route_base_revenue(r.phase, r.train) / 2
last = stops.size < 2 ? 0 : stops.last.route_base_revenue(r.phase, r.train) / 2
{ route: r, subsidy: first + last }
# LP does not work with Mail Contract, even if it stops at a
# town. An exception for 1822PNW is made via
# `LOCAL_TRAIN_CAN_CARRY_MAIL`
#
# https://boardgamegeek.com/thread/2640241/article/40423428#40423428
# https://boardgamegeek.com/thread/2640241/article/43680986#43680986
# https://docs.google.com/document/d/1puHQJV4eLeunOtu_RyqAT-_mBCI93u8dqSBNwWMsAiE/
next if !self.class::LOCAL_TRAIN_CAN_CARRY_MAIL && (r.train.name[0] == 'L' || stops.size < 2)

first = stops.first.route_base_revenue(r.phase, r.train)
last = stops.size < 2 ? 0 : stops.last.route_base_revenue(r.phase, r.train)
{ route: r, subsidy: (first + last) / 2 }
end.compact
mail_bonuses.sort_by { |v| v[:subsidy] }.reverse.take(mail_contracts)
mail_bonuses.sort_by { |v| -v[:subsidy] }.take(mail_contracts)
end

def move_exchange_token(entity)
Expand Down
45 changes: 18 additions & 27 deletions lib/engine/game/g_1822_ca/game.rb
Original file line number Diff line number Diff line change
Expand Up @@ -393,53 +393,38 @@ def upgrades_to_correct_label?(from, to)
end

def mail_contract_bonus(entity, routes)
mail_contracts = entity.companies.count { |c| self.class::PRIVATE_MAIL_CONTRACTS.include?(c.id) }
# "Large Mail Contract" is the same as the standard 1822 family "Mail Contract"
large_bonuses = super

large_contracts = large_bonuses.size
small_contracts = entity.companies.count { |c| self.class::PRIVATE_SMALL_MAIL_CONTRACTS.include?(c.id) }
all_contracts = mail_contracts + small_contracts
all_contracts = large_contracts + small_contracts
return [] unless all_contracts.positive?

mail_bonuses =
if mail_contracts.positive?
bonuses = routes.map do |r|
stops = r.visited_stops
next if stops.size < 2

first = stops.first.route_base_revenue(r.phase, r.train)
last = stops.last.route_base_revenue(r.phase, r.train)
{ route: r, subsidy: (first + last) / 2 }
end
bonuses.compact.sort_by { |v| -v[:subsidy] }.take(mail_contracts)
else
[]
end

small_bonuses =
if small_contracts.positive?
subsidy = small_mail_subsidy

routes.map do |r|
next if r.visited_stops.size < 2

{ route: r, subsidy: subsidy }
end.compact.take(small_contracts)
else
[]
end

if routes.size >= all_contracts || mail_bonuses.empty? || small_bonuses.empty?
mail_bonuses + small_bonuses
if routes.size >= all_contracts || large_bonuses.empty? || small_bonuses.empty?
large_bonuses + small_bonuses
else
mail_index = 0
large_index = 0
small_index = 0
routes.map do
mail = mail_bonuses[mail_index] || { subsidy: 0 }
large = large_bonuses[large_index] || { subsidy: 0 }
small = small_bonuses[small_index] || { subsidy: 0 }
if small[:subsidy] > mail[:subsidy]
if small[:subsidy] > large[:subsidy]
small_index += 1
small
else
mail_index += 1
mail
large_index += 1
large
end
end
end
Expand Down Expand Up @@ -470,6 +455,12 @@ def train_help(entity, runnable_trains, _routes)
help
end

def train_help_mail_contracts
'Large mail contract(s) gives a subsidy equal to one half of the base value of the start and end '\
'stations from one of the trains operated. Doubled values (for E trains or destination tokens) '\
'do not count. L-trains cannot use large mail contracts.'
end

def revenue_for(route, stops)
revenue = super

Expand Down
14 changes: 6 additions & 8 deletions lib/engine/game/g_1822_mx/entities.rb
Original file line number Diff line number Diff line change
Expand Up @@ -273,12 +273,11 @@ module Entities
desc: 'MAJOR, Phase 3. Mail Contract. After running trains, the owning company receives income '\
'into its treasury equal to one half of the base value of the start and end '\
'stations from one of the trains operated. Modifications to values (for '\
'E-trains, a 3/2-train, or destination tokens) do not apply. An L-train may '\
'deliver mail within a single city. The company is not required to maximize '\
'the dividend from its run if it wishes to maximize its revenue from the mail '\
'E-trains, a 3/2-train, or destination tokens) do not apply. The company is not required to '\
'maximize the dividend from its run if it wishes to maximize its revenue from the mail '\
'contract by stopping at a large city and not running beyond it to include '\
'towns. A company that owns more than one Mail Contract may not use '\
'more than one on any train.',
'more than one on any train. Cannot be used with an L-train.',
abilities: [],
},
{
Expand All @@ -289,12 +288,11 @@ module Entities
desc: 'MAJOR, Phase 3. Mail Contract. After running trains, the owning company receives income '\
'into its treasury equal to one half of the base value of the start and end '\
'stations from one of the trains operated. Modifications to values (for '\
'E-trains, a 3/2-train, or destination tokens) do not apply. An L-train may '\
'deliver mail within a single city. The company is not required to maximize '\
'the dividend from its run if it wishes to maximize its revenue from the mail '\
'E-trains, a 3/2-train, or destination tokens) do not apply. The company is not required to '\
'maximize the dividend from its run if it wishes to maximize its revenue from the mail '\
'contract by stopping at a large city and not running beyond it to include '\
'towns. A company that owns more than one Mail Contract may not use '\
'more than one on any train.',
'more than one on any train. Cannot be used with an L-train.',
abilities: [],
},
{
Expand Down
2 changes: 0 additions & 2 deletions lib/engine/game/g_1822_mx/game.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ class Game < G1822::Game
PRIVATE_PHASE_REVENUE = %w[].freeze # Stub for 1822 specific code
P7_REVENUE = [0, 0, 0, 20, 20, 40, 40, 60].freeze

LOCAL_TRAIN_CAN_CARRY_MAIL = true

# Don't run 1822 specific code for certain private companies
COMPANY_LCDR = nil
COMPANY_OSTH = nil
Expand Down
6 changes: 6 additions & 0 deletions lib/engine/game/g_1822_pnw/game.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,12 @@ def game_end_check
[:bank, @round.is_a?(Engine::Round::Operating) ? :full_or : :current_or]
end
end

def train_help_mail_contracts
'Mail contract(s) gives a subsidy equal to one half of the base value of the start and end '\
'stations from one of the trains operated. Doubled values (for E trains or destination tokens) '\
'do not count. L-trains can use mail contracts, even if they visit one city and no towns.'
end
end
end
end
Expand Down

0 comments on commit 8fe9584

Please sign in to comment.