summaryrefslogtreecommitdiffstats
path: root/lib/colonial_twilight
diff options
context:
space:
mode:
Diffstat (limited to 'lib/colonial_twilight')
-rw-r--r--lib/colonial_twilight/turn.rb239
1 files changed, 239 insertions, 0 deletions
diff --git a/lib/colonial_twilight/turn.rb b/lib/colonial_twilight/turn.rb
new file mode 100644
index 0000000..34690e7
--- /dev/null
+++ b/lib/colonial_twilight/turn.rb
@@ -0,0 +1,239 @@
+#! /usr/bin/env ruby
+# frozen_string_literal: true
+
+module ColonialTwilight
+ OPERATIONS = {
+ pass: 'Pass',
+ rally: 'Rally',
+ march: 'March',
+ attack: 'Attack',
+ terror: 'Terror'
+ }.freeze
+
+ SPECIAL_ACTIVITIES = {
+ extort: 'Extort',
+ subvert: 'Subvert',
+ ambush: 'Ambush',
+ oas: 'OAS'
+ }.freeze
+
+ class Action
+ attr_reader :type, :space, :cost, :steps, :to_agitate_in
+ attr_accessor :resources
+
+ def initialize(type, space, cost, to_agitate_in: nil)
+ @type = type
+ @space = space
+ @cost = cost
+ @steps = []
+ @resources = 0
+ @to_agitate_in = to_agitate_in
+ end
+
+ def sanitize!
+ map = { src_control: :src, dst_control: :dst }
+ control = _collect_indexes(map)
+ control.each do |k, v|
+ v.pop
+ v.each do |i|
+ step = steps[i]
+ step.delete(step[:src] == k ? :src_control : :dst_control)
+ end
+ end
+ end
+
+ def _collect_indexes(map)
+ hash = {}
+ steps.each_with_index do |step, i|
+ map.each do |k, v|
+ if step.key?(k)
+ hash[step[v]] ||= []
+ hash[step[v]] << i
+ end
+ end
+ end
+ hash
+ end
+
+ def name
+ return 'Agitate' if @type == :agitate
+
+ operation? ? OPERATIONS[@type] : SPECIAL_ACTIVITIES[@type]
+ end
+
+ def operation?
+ OPERATIONS.keys.include? @type
+ end
+
+ def special_activity?
+ SPECIAL_ACTIVITIES.keys.include? @type
+ end
+
+ def transfer_steps(steps)
+ steps.each do |k, v|
+ transfer_from(k, :fln_underground, v)
+ end
+ self
+ end
+
+ def pass
+ @steps << { kind: :pass }
+ self
+ end
+
+ def activate(num = 1)
+ @steps << { kind: :activate, src: @space, num: num } if num.positive?
+ self
+ end
+
+ def transfer_to(dst, what, num = 1, flip: false)
+ @steps << { kind: :transfer, src: @space, dst: dst, what: what, num: num, flip: flip } if num.positive?
+ self
+ end
+
+ def transfer_from(src, what, num = 1, flip: false)
+ @steps << { kind: :transfer, src: src, dst: @space, what: what, num: num, flip: flip } if num.positive?
+ self
+ end
+
+ def shift(num)
+ @steps << { kind: :shift, dst: @space, num: num } unless num.zero?
+ self
+ end
+
+ def extort
+ @steps << { kind: :extort, src: @space, what: :fln_underground, flip: true }
+ self
+ end
+
+ def terror
+ @steps << { kind: :set, src: @space, what: :terror, terror: 1 }
+ @steps << { kind: :set, src: @space, what: :alignment, alignment: :neutral }
+ self
+ end
+
+ def agitate(terror, oppose)
+ @steps << { kind: :agitate, src: @space, terror: terror, shift: oppose }
+ self
+ end
+
+ def inspect
+ "action #{@type} in '#{@space}' cost: #{@cost} #{_to_agitate} : #{_steps}"
+ end
+
+ def _to_agitate
+ @to_agitate_in.nil? ? '' : " - to agitate in #{@to_agitate_in}"
+ end
+
+ def _steps
+ @steps.inject('') { |r, s| r + "\n #{s.inspect}" }
+ end
+ end
+
+ class Turn
+ attr_reader :actions, :operation, :special_activity
+
+ def initialize
+ reset(false)
+ end
+
+ def reset(limited_op_only)
+ @operation = nil
+ @special_activity = nil
+ @actions = []
+ @limited_op_only = limited_op_only
+ end
+
+ def operation_done?
+ !@operation.nil?
+ end
+
+ def special_activity_done?
+ !@special_activity.nil?
+ end
+
+ def may_special_activity?(special_activity)
+ @special_activity.nil? || @special_activity == special_activity
+ end
+
+ def operation_spaces
+ @actions.select(&:operation?).size
+ end
+ alias selected_spaces operation_spaces
+
+ def special_activity_spaces
+ @actions.select(&:special_activity?).size
+ end
+
+ def operation_selected?(space)
+ !@actions.select(&:operation?).find { |a| a.space == space }.nil?
+ end
+
+ def special_activity_selected?(space)
+ !@actions.select(&:special_activity?).find { |a| a.space == space }.nil?
+ end
+
+ def cost
+ @actions.inject(0) { |s, a| s + a.cost }
+ end
+
+ def operation_cost
+ @actions.select(&:operation?).inject(0) { |s, a| s + a.cost }
+ end
+
+ def special_activity_cost
+ @actions.select(&:special_activity?).inject(0) { |s, a| s + a.cost }
+ end
+
+ def pass(cost)
+ operation_in(:pass, nil, -cost).pass
+ end
+
+ def agitate_in(space, terror, oppose)
+ raise "illegal Agitate in #{@operation}" if @operation != :rally
+ raise "not already selected : #{space.name}" unless operation_selected?(space)
+
+ add Action.new(:agitate, space, terror + oppose).agitate(terror, oppose)
+ end
+
+ def operation_in(operation, space, cost, to_agitate_in: nil)
+ raise "unknown operation : #{operation}" unless OPERATIONS.keys.include? operation
+
+ unless @operation.nil?
+ raise "illegal #{operation} in #{@operation}" if @operation != operation
+ raise "illegal #{operation} in limited operation #{@operation}" if @limited_op_only
+ end
+ raise "already selected : #{space.name}" if operation_selected?(space)
+
+ @operation = operation
+ add Action.new(operation, space, cost, to_agitate_in: to_agitate_in)
+ end
+
+ def special_activity_in(special_activity, space, cost, to_agitate_in: nil)
+ raise "unknown special activity : #{special_activity}" unless SPECIAL_ACTIVITIES.keys.include? special_activity
+ raise "illegal #{special_activity} in #{@special_activity}" if !@special_activity.nil? && @special_activity != special_activity
+ raise "illegal #{special_activity} in limited operation #{@operation}" if @limited_op_only
+ raise "already selected : #{space.name}" if special_activity_selected?(space)
+
+ @special_activity = special_activity
+ @operation = :attack if special_activity == :ambush
+ add Action.new(special_activity, space, cost, to_agitate_in: to_agitate_in)
+ end
+
+ def add(action)
+ @actions << action
+ action
+ end
+
+ def inspect
+ "Operation : #{@operation} - in #{selected_spaces} spaces => #{operation_cost} Resources\
+ \nSpecial Activity : #{@special_activity} - in #{special_activity_spaces}\
+ spaces => #{special_activity_cost} Resources\
+ \nactions : #{_actions_to_s}"
+ end
+
+ def _actions_to_s
+ @actions.inject('') { |s, a| s + "\n - #{a.inspect}" }
+ end
+ end
+end