diff options
| -rw-r--r-- | lib/colonial_twilight/actions/action.rb | 79 | ||||
| -rw-r--r-- | lib/colonial_twilight/actions/fln/agitate.rb | 51 | ||||
| -rw-r--r-- | lib/colonial_twilight/actions/fln/fln_action.rb | 13 | ||||
| -rw-r--r-- | lib/colonial_twilight/actions/fln/rally.rb | 66 | ||||
| -rw-r--r-- | spec/mock_board.rb | 20 |
5 files changed, 229 insertions, 0 deletions
diff --git a/lib/colonial_twilight/actions/action.rb b/lib/colonial_twilight/actions/action.rb new file mode 100644 index 0000000..3be8483 --- /dev/null +++ b/lib/colonial_twilight/actions/action.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +module ColonialTwilight + module Actions + class GameAction + def initialize(faction:, space:, cost: 0, mode: nil) + @data = { + faction: faction, + space: space, + cost: cost, + mode: mode + } + validate! + end + + def faction + @data[:faction] + end + + def space + @data[:space] + end + + def cost + @data[:cost] + end + + def mode + @data[:mode] + end + + def to_h + @data.merge(type: self.class.name.split('::')[-1]) + end + + def validate! + raise "not applicable to #{@data[:space]}" unless self.class.applicable?(@data[:space]) + + available = self.class.available_modes(@data[:space]) + @data[:mode].each do |key, value| + raise "mode: #{key} is not available" unless available.key?(key) + + max_allowed = available[key] + raise "value: #{key} set to #{value}, max is #{max_allowed}" if value > max_allowed + end + end + + def apply! + raise NotImplementedError + end + + def revert! + raise NotImplementedError + end + + class << self + def op? + false + end + + def special? + false + end + + def applicable?(space) + raise NotImplementedError + end + + def available_modes(_space) + nil + end + + def possible_spaces(board) + board.search(&method(:applicable?)) + end + end + end + end +end diff --git a/lib/colonial_twilight/actions/fln/agitate.rb b/lib/colonial_twilight/actions/fln/agitate.rb new file mode 100644 index 0000000..fd0e287 --- /dev/null +++ b/lib/colonial_twilight/actions/fln/agitate.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require_relative 'fln_action' +require_relative 'rally' + +module ColonialTwilight + module Actions + module FLN + # Agitate 3.3.1 + class Agitate < FlnAction + # 1 resources per Terror marker, then 1 resource for the level shift + def initialize(space, mode) + super(space, mode, cost: (mode[:remove_terror] || 0) + (mode[:shift_oppose] || 0)) + end + + def validate! + super + raise 'select at least 1 mode' unless mode.keys.size.positive? + + return if space.terror.zero? || (mode.key?(:remove_terror) && mode[:remove_terror] == space.terror) + + raise 'remove Terror marker first' if mode.key?(:shift_oppose) + end + + # remove Terror first, then shift 1 level toward Oppose + def apply!(board) + raise NotImplementedError + end + + class << self + def op? + true + end + + # with Base and or Control && terror or shift to oppose possible + def applicable?(space) + Rally.applicable?(space) && + (space.fln_bases.positive? || space.fln_control?) && (space.terror.positive? || !space.oppose?) + end + + def available_modes(space) + modes = {} + modes[:remove_terror] = space.terror if space.terror.positive? + modes[:shift_oppose] = 1 unless space.oppose? + modes + end + end + end + end + end +end diff --git a/lib/colonial_twilight/actions/fln/fln_action.rb b/lib/colonial_twilight/actions/fln/fln_action.rb new file mode 100644 index 0000000..3a571aa --- /dev/null +++ b/lib/colonial_twilight/actions/fln/fln_action.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require_relative '../action' + +module ColonialTwilight + module Actions + class FlnAction < GameAction + def initialize(space, mode, cost: 1) + super(faction: :FLN, space: space, mode: mode, cost: cost) + end + end + end +end diff --git a/lib/colonial_twilight/actions/fln/rally.rb b/lib/colonial_twilight/actions/fln/rally.rb new file mode 100644 index 0000000..c9ed489 --- /dev/null +++ b/lib/colonial_twilight/actions/fln/rally.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require_relative 'fln_action' +require_relative 'agitate' + +module ColonialTwilight + module Actions + module FLN + # Rally 3.3.1 + class Rally < FlnAction + def initialize(space, mode) + super(space, mode) + @agitate = nil + end + + def cost + super + (@agitate.nil? ? 0 : @agitate.cost) + end + + def validate! + super + raise 'select 1 mode' if mode.keys.size != 1 + raise 'flip all Guerrillas' if mode.key?(:underground) && mode[:underground] != space.fln_active + end + + # France track: shift 1 level toward "F" + # in space place 1 underground Guerrilla, or replace 2 Guerrillas with 1 Base + # or in space with FLN Base: add underground Guerrillas equal to population + Bases, + # or flip all Guerrillas underground + def apply!(board) + raise NotImplementedError + end + + def agitate!(mode) + raise 'agitate! called twice' unless @agitate.nil? + + @agitate = Agitate.new(@data[:space], mode) + self + end + + class << self + def op? + true + end + + # Sectors, Cities not at Support, Independent Countries, France track + def applicable?(space) + return space.name == 'France track' && !space.max? if space.track? + + space.sector? || (space.city? && !space.support?) || (space.country? && space.independent?) + end + + def available_modes(space) + modes = { place_guerilla: 1 } + modes[:place_base] = 1 if space.guerrillas > 1 && space.bases < space.max_bases + unless space.fln_bases.zero? + modes[:place_guerilla] = space.fln_bases + space.pop + modes[:underground] = space.fln_active if space.fln_active.positive? + end + modes + end + end + end + end + end +end diff --git a/spec/mock_board.rb b/spec/mock_board.rb index 133c09e..7afbd6f 100644 --- a/spec/mock_board.rb +++ b/spec/mock_board.rb @@ -1,5 +1,21 @@ # frozen_string_literal: true +class Track + attr_reader :value, :name + def initialize(value, name) + @value = value + @name = name + end + + def track? + true + end + + def max? + false + end +end + class Sector attr_reader :name attr_writer :data @@ -9,6 +25,10 @@ class Sector @data = data end + def track? + false + end + def sector? @name == 'sector' end |
