summaryrefslogtreecommitdiffstats
path: root/lib/colonial_twilight/board.rb
blob: b4add445f02914e843ff4e946a9817b09c01a78a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# frozen_string_literal: true

require_relative 'board/forces'
require_relative 'board/spaces'
require_relative 'board/setup'
require_relative 'board/scenario'

module ColonialTwilight
  class Board
    FRANCE_TRACK = %w[A B C D E F].freeze

    TRACKS = %i[support_commitment opposition_bases fln_resources
                gov_resources commitment france_track border_zone_track].freeze

    attr_reader :spaces

    %i[commitment gov_resources fln_resources france_track border_zone_track
       support_commitment opposition_bases].each do |sym|
      define_method(sym) { instance_variable_get("@#{sym}").v }
    end

    %i[gov_bases french_troops french_police algerian_troops algerian_police fln_bases fln_underground].each do |sym|
      define_method("available_#{sym}") { @available.send(sym) }
      # define_method "casualties_#{sym}" do @casualties.send(sym) end
      # define_method "out_of_play_#{sym}" do @out_of_play.send(sym) end
    end

    include Setup
    include Scenario

    def initialize
      @spaces = []
      @capabilities = []
      @available = Box.new :available
      @casualties = Box.new :casualties
      @out_of_play = Box.new :out_of_play
      @support_commitment = Track.new(50, 'Support & Commitment')
      @opposition_bases = Track.new(50, 'Opposition & Bases')
      @fln_resources = Track.new(50, 'FLN Resources')
      @gov_resources = Track.new(50, 'GOV Resources')
      @commitment = Track.new(50, 'Commitment')
      @france_track = Track.new(5, 'France track')
      @border_zone_track = Track.new(4, 'Border Zone track')
      setup
    end

    def inspect
      'Board'
    end

    def load(scenario)
      case scenario
      when :short then short_scenario
      when :medium then medium_scenario
      when :full then full_scenario
      else raise "unknown scenario : #{scenario}"
      end
    end

    def by_name(name)
      @spaces.find { |s| s.name == name }
    end

    def sector
      @spaces.select(&:sector?)
    end
    alias sectors sector

    def city
      @spaces.select(&:city?)
    end
    alias cities city

    def country
      @spaces.select(&:country?)
    end
    alias countries country

    def has(where = :spaces, &block)
      !send(where).select(&block).empty?
    end

    def search(where = :spaces, &block)
      send(where).select(&block)
    end

    def count(where = :spaces, &block)
      send(where).inject(0) { |i, s| i + block.call(s) }
    end

    def compute_opposition_bases
      count { |s| s.oppose? ? s.pop : 0 } + count(&:fln_bases)
    end

    def compute_support_commitment
      count { |s| s.support? ? s.pop : 0 } + @commitment.v
    end

    def shift(space, towards, num = 1)
      num.times { space.shift(towards) }
    end

    def shift_track(what, amount)
      raise "unknown track : #{what}" unless TRACKS.include?(what)

      instance_variable_get("@#{what}").shift(amount)
    end

    def apply(action)
      action.steps.each do |step|
        case step[:kind]
        when :transfer then transfer(step)
        else raise "unknow action step #{step}"
        end
      end
    end

    # def terror(where, num)
    #   where.terror += num
    # end

    # def data
    #   h = {}
    #   %i[gov_resources fln_resources commitment support_commitment opposition_bases
    #     france_track border_zone_track available casualties out_of_play].each do |sym|
    #     h[sym] = instance_variable_get("@#{sym}").data
    #   end
    #   h[:capabilities] = @capabilities
    #   h[:spaces] = @spaces.inject([]) { |a, s| a << s.data }
    #   h
    # end

    private

    def transfer(data)
      src = get_obj(data[:src])
      dst = get_obj(data[:dst])
      src.add data[:what], -data[:num]
      dst.add flip?(data), data[:num]
    end

    def flip?(data)
      !data[:flip] ? data[:what] : data[:flip]
    end

    def get_obj(obj)
      return obj if obj.is_a? ColonialTwilight::Sector

      case obj
      when :available then @available
      when :casualties then @casualties
      when :out_of_play then @out_of_play
      else
        raise "unknown Board variable named #{obj}"
      end
    end
  end
end