From ec088078fbc0646f3d9b25804b35b232e9e9c81b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Zurcher?= Date: Tue, 1 Sep 2020 15:26:31 +0200 Subject: Board : is in good shape so far --- lib/colonial_twilight/board.rb | 302 ++++++++++++++++++++++++++++------------- 1 file changed, 209 insertions(+), 93 deletions(-) diff --git a/lib/colonial_twilight/board.rb b/lib/colonial_twilight/board.rb index 3a1679a..473d0c1 100644 --- a/lib/colonial_twilight/board.rb +++ b/lib/colonial_twilight/board.rb @@ -23,7 +23,7 @@ module ColonialTwilight attr_accessor :french_troops, :french_police attr_accessor :fln_underground, :fln_active attr_accessor :fln_bases, :gov_bases - attr_reader :control + attr_reader :max_bases, :control def initialize k @algerian_troops = 0 @@ -34,8 +34,8 @@ module ColonialTwilight @fln_underground = 0 @fln_active = 0 @fln_bases = 0 - @max_bases = 2 - @control = :none + @max_bases = nil + @control = :uncontrolled rm = nil case k when :available @@ -45,12 +45,13 @@ module ColonialTwilight when :out_of_play rm = [:@control, :@algerian_troops, :@algerian_police, :@fln_active, :@fln_bases] when :Country - @max_bases = 3 + @max_bases = 2 rm = [:@control, :@algerian_troops, :@algerian_police, :@french_troops, :@french_police, :@gov_bases] + when :Sector + @max_bases = 2 end rm.each do |sym| - # maybe remove :sym= instead or set @sym to nil - remove_instance_variable sym + instance_variable_set(sym, nil) end unless rm.nil? end @@ -76,7 +77,39 @@ module ColonialTwilight end def bases - @gov_bases||0 + @fln_bases||0 + (@gov_bases||0) + (@fln_bases||0) + end + + def fln + guerrillas + (@fln_bases||0) + end + + def guerrillas + (@fln_underground||0) + (@fln_active||0) + end + + def gov + gov_cubes + (@gov_bases||0) + end + + def gov_cubes + french_cubes + algerian_cubes + end + + def french_cubes + (@french_troops||0) + (@french_police||0) + end + + def algerian_cubes + (@algerian_troops||0) + (@algerian_police||0) + end + + def troops + (@french_troops||0) + (@algerian_troops||0) + end + + def police + (@french_police||0) + (@algerian_police||0) end def add t, n=1 @@ -87,29 +120,31 @@ module ColonialTwilight when :algerian_police; @algerian_police += n when :fln_underground; @fln_underground += n when :fln_active; @fln_active += n + when :gov_base; add_base :gov_base, n + when :fln_base; add_base :fln_base, n else raise "unknown force type : #{t}" end update_control end + private + def add_base t, n=1 - raise "too much bases in #@name (#{bases} + #{n}) > #@max_bases" if (bases + n) > @max_bases - @gov_bases += n if t == :gov - @fln_bases += n if t == :fln - update_control + raise "too much bases in #@name (#{bases} + #{n}) > #@max_bases" if not @max_bases.nil? and (bases + n) > @max_bases + @gov_bases += n if t == :gov_base + @fln_bases += n if t == :fln_base end - private - def update_control return if @control.nil? - gov = @algerian_troops + @algerian_police + @french_troops + @french_police + @gov_bases - fln = @fln_underground + @fln_active + @fln_bases - if gov == fln; @control = :none - elsif gov > fln; @control = :GOV - else @control = :FLN - end + @control = ( + case gov <=> fln + when 0; :uncontrolled + when 1; :GOV + when -1; :FLN + end + ) end end @@ -121,7 +156,7 @@ module ColonialTwilight BORDER=4 attr_reader :wilaya, :sector, :name, :resettled - attr_accessor :pop, :adjacents + attr_accessor :pop, :terror, :adjacents attr_accessor :alignment def initialize n, w, s, p, attrs=0 @@ -129,6 +164,7 @@ module ColonialTwilight @wilaya = w @sector = s @pop = p + @terror = 0 @attributes = attrs @descr = "#{self.class.name} #@name #{@wilaya == 0 ? '' : @wilaya}" + (@sector == 0 ? '' : "-#{@sector}") @terrain = [mountain? ? 'mountain' : nil ,coastal? ? 'coastal' : nil, border? ? 'border' : nil].reject(&:nil?).join '/' @@ -141,13 +177,20 @@ module ColonialTwilight "#@descr #@terrain control : #{@forces.control} alignment : #@alignment + terror : #@terror population : #{@pop}#{@resettled ? ' resettled' : ''} forces : #{@forces} adjs : #{@adjacents}" end def data - { :name=>@name, :alignment=>@alignment, :pop=>@pop, :resettled=>@resettled }.merge(@forces.data) + { :name=>@name, :alignment=>@alignment, :terror=>@terror, :pop=>@pop, :resettled=>@resettled }.merge(@forces.data) + end + + [:gov, :gov_cubes, :french_cubes, :algerian_cubes, :troops, :police, :gov_bases, :french_troops, :french_police, :algerian_troops, :algerian_police, + :fln, :guerrillas, :fln_bases, :fln_underground, :fln_active, + :max_bases].each do |sym| + define_method sym do @forces.send(sym) end end def city?; false; end @@ -155,23 +198,28 @@ module ColonialTwilight def border?; (@attributes & BORDER) == BORDER end def coastal?; (@attributes & COASTAL) == COASTAL end def mountain?; (@attributes & MOUNTAIN) == MOUNTAIN end - def control; @forces.control; end - def add_gov_base n=1; @forces.add_base :gov, n; end - def add_fln_base n=1; @forces.add_base :fln, n; end - def add_french_troops n=1; @forces.add :french_troops, n; end - def add_french_police n=1; @forces.add :french_police, n; end - def add_algerian_troops n=1; @forces.add :algerian_troops, n; end - def add_algerian_police n=1; @forces.add :algerian_police, n; end - def add_fln_underground n=1; @forces.add :fln_underground, n; end - def add_fln_active n=1; @forces.add :fln_active, n; end - def french_troops; @forces.french_troops end - def french_police; @forces.french_police end - def algerian_troops; @forces.algerian_troops end - def algerian_police; @forces.algerian_police end - def fln_underground; @forces.fln_underground end - def fln_active; @forces.fln_active end - def gov_bases; @forces.gov_bases end - def fln_bases; @forces.fln_bases end + def support?; @alignment == :support end + def oppose?; @alignment == :oppose end + def neutral?; @alignment == :neutral end + def control; @forces.control end + def uncontrolled?; @forces.control == :uncontrolled end + def fln_control?; @forces.control == :FLN end + def gov_control?; @forces.control == :GOV end + def has_terror?; terror > 0 end + def has_gov?; not gov_bases_0? or not gov_cubes_0? end + def has_fln?; not fln_bases_0? or fln > 0 end + def gov_bases_0?; gov_bases == 0 end + def fln_bases_0?; fln_bases == 0 end + def gov_bases_1m?; gov_bases > 0 end + def fln_bases_1m?; fln_bases > 0 end + def pop0?; pop == 0 end + def gov_cubes_0?; gov_cubes == 0 end + def add t, n=1; @forces.add t, n end + def fln_u_1l?; fln_underground < 2 end + def fln_u_0?; fln_underground == 0 end + def fln_u_1m?; fln_underground > 0 end + def fln_u_2m?; fln_underground > 1 end + def fln_u_3m?; fln_underground > 2 end def resettle! raise "can't resettle a country " if country? raise "can't resettle a sector with a population > 1" if @pop != 1 @@ -179,6 +227,17 @@ module ColonialTwilight @resettled = true end + def shift towards + if towards == :oppose + raise "can't shift towards oppose" if oppose? + @alignment = (support? ? :neutral : :oppose) + end + if towards == :support + raise "can't shift towards support" if support? + @alignment = (oppose? ? :neutral : :support) + end + end + end class City < Sector @@ -192,8 +251,8 @@ module ColonialTwilight attr_reader :independant - def initialize n - super n, 0, 0, 1, MOUNTAIN|BORDER|COASTAL + def initialize n, w + super n, w, 0, 1, MOUNTAIN|BORDER|COASTAL @descr += " #{@independant ? 'Independant' : 'French'}" end def add_gov_base n=1; raise "no gov bases allowed in #@name" end @@ -203,37 +262,90 @@ module ColonialTwilight class Board - FRANCE_TRACK=['A','B','C','D','E'].freeze + FRANCE_TRACK=['A','B','C','D','E','F'].freeze attr_accessor :commitment attr_accessor :gov_resources, :fln_resources - attr_accessor :support_commitment, :opposition_bases + attr_accessor :support_commitment,:opposition_bases attr_accessor :resettled_sectors attr_accessor :france_track, :border_zone_track - attr_reader :spaces, :names + attr_reader :spaces, :sectors, :cities, :countries + attr_reader :spaces_h def initialize @names = [] - @spaces = {} + @spaces_h = {} @capabilities = [] @available = Forces.new :available @casualties = Forces.new :casualties @out_of_play = Forces.new :out_of_play feed + @spaces = @spaces_h.values + @sectors = @spaces.select { |s| not s.country? } + @cities = @spaces.select { |s| s.city? } + @countries = @spaces.select { |s| s.country? } end - def load scenario - case scenario - when :short; short - when :medium; medium - when :full; full - else raise "unknown scenario : #{scenario}" + [:gov_bases, :french_troops, :french_police, :algerian_troops, :algerian_police, + :fln_bases, :fln_underground].each do |sym| + define_method "available_#{sym}" do @available.send(sym) end + # define_method "casualties_#{sym}" do @casualties.send(sym) end + # define_method "out_of_play_#{sym}" do @out_of_play.send(sym) end + end + + def transfer n, what, from, to, towhat=nil + from = (from.is_a?(Sector) ? from : get_local(from) ) + to = (to.is_a?(Sector) ? to : get_local(to) ) + from.add what, -n + to.add towhat, n + end + + def terror where, n + where.terror += n + end + + def shift where, towards, n=1 + n.times do + where.shift towards end end - def sectors - @spaces.select{ |k,s| not s.country? } + def shift_france_track dt + ft = @france_track + dt + return false if (ft < 0 or ft > 5) + @france_track = ft + true + end + + def has where=:spaces, &block + r = search &block + r.length > 0 + 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 resettle sector + @spaces_h[sector].resettle! + @resettled_sectors += 1 + end + + def compute_victory_points + values = [@support_commitment, @opposition_bases] + @opposition_bases = 0 + @support_commitment = @commitment + @spaces_h.each do |n,s| + @opposition_bases += s.fln_bases + @opposition_bases += s.pop if s.alignment == :oppose + @support_commitment += s.pop if s.alignment == :support + end + values << @support_commitment << @opposition_bases end def data @@ -245,7 +357,7 @@ module ColonialTwilight h[:available] = @available.data h[:casualties] = @casualties.data h[:out_of_play] = @out_of_play.data - h[:spaces] = @spaces.inject([])do |a,(k,s)| a << s.data end + h[:spaces] = @spaces_h.inject([])do |a,(k,s)| a << s.data end h end @@ -260,34 +372,38 @@ module ColonialTwilight end end - def resettle sector - @spaces[sector].resettle! - @resettled_sectors += 1 - end - - def compute_victory - @opposition_bases = 0 - @support_commitment = @commitment - @spaces.each do |n,s| - @opposition_bases += s.fln_bases - @opposition_bases += s.pop if s.alignment == :oppose - @support_commitment += s.pop if s.alignment == :support + def load scenario + case scenario + when :short; short + when :medium; medium + when :full; full + else raise "unknown scenario : #{scenario}" end end private + def get_local sym + case sym + when :available; return @available + when :casualties; return @casualties + when :out_of_play; return @out_of_play + else + raise "unknown Board variable named #{sym}" + end + end + def add k, *args s = k.new *args # puts s @names << s.name - @spaces[s.name] = s + @spaces_h[s.name] = s end def adjacents i, *args - @spaces[@names[i]].adjacents = args - # @spaces[@names[i]].adjacents = args.map { |i| @names[i] } - # puts @spaces[@names[i]] + @spaces_h[@names[i]].adjacents = args + # @spaces_h[@names[i]].adjacents = args.map { |i| @names[i] } + # puts @spaces_h[@names[i]] end def feed @@ -322,8 +438,8 @@ module ColonialTwilight add Sector, 'Laghouat', 'V', 9, 0 # 25 add Sector, 'Sidi Aissa', 'VI', 1, 0, mountain # 26 add Sector, 'Ain Oussera', 'VI', 2, 1, mountain # 27 - add Country, 'Moroco' # 28 - add Country, 'Tunisia' # 29 + add Country, 'Moroco', 0 # 28 + add Country, 'Tunisia', 1 # 29 adjacents 0, 1, 2, 3, 7, 8, 11, 19 adjacents 1, 0, 2, 3, 5 adjacents 2, 0, 1, 5, 25, 26, 29 @@ -357,15 +473,15 @@ module ColonialTwilight end def set_sector i, h, align=nil - s = @spaces[@names[i]] + s = @spaces_h[@names[i]] s.alignment = align unless align.nil? - s.add_gov_base h[:govb] if h.has_key? :govb - s.add_fln_base h[:flnb] if h.has_key? :flnb - s.add_french_troops h[:ft] if h.has_key? :ft - s.add_french_police h[:fp] if h.has_key? :fp - s.add_algerian_troops h[:at] if h.has_key? :at - s.add_algerian_police h[:ap] if h.has_key? :ap - s.add_fln_underground h[:fln] if h.has_key? :fln + s.add :gov_base, h[:govb] if h.has_key? :govb + s.add :fln_base, h[:flnb] if h.has_key? :flnb + s.add :french_troops, h[:ft] if h.has_key? :ft + s.add :french_police, h[:fp] if h.has_key? :fp + s.add :algerian_troops, h[:at] if h.has_key? :at + s.add :algerian_police, h[:ap] if h.has_key? :ap + s.add :fln_underground, h[:fln] if h.has_key? :fln # puts s end @@ -410,9 +526,9 @@ module ColonialTwilight set_sector 27, {}, :oppose set_sector 28, {:fln=>4, :flnb=>2} set_sector 29, {:fln=>5, :flnb=>2} - compute_victory - raise "wrong opposition bases" if @opposition_bases != 19 - raise "wrong support_commitment" if @support_commitment != 22 + compute_victory_points + raise "wrong opposition + bases" if @opposition_bases != 19 + raise "wrong support + commitment" if @support_commitment != 22 end def medium @@ -434,21 +550,21 @@ end if $PROGRAM_NAME == __FILE__ def check b # puts '--- Coastal' - # b.spaces.select{ |k,s| s.coastal? }.each { |k,s| puts s.name } - raise "coastal sectors error" if b.spaces.select{ |k,s| s.coastal? }.size != 14 + # b.spaces.select{ |s| s.coastal? }.each { |s| puts s.name } + raise "coastal sectors error" if b.spaces.select{ |s| s.coastal? }.size != 14 # puts '--- not Mountain' - # b.spaces.select{ |k,s| not s.mountain? }.each { |k,s| puts s.name } - raise "not moauntain sectors error" if b.spaces.select{ |k,s| not s.mountain? }.size != 9 + # b.spaces.select{ |s| not s.mountain? }.each { |s| puts s.name } + raise "not moauntain sectors error" if b.spaces.select{ |s| not s.mountain? }.size != 9 # puts '--- Border' - # b.spaces.select{ |k,s| s.border? }.each { |k,s| puts s.name } - raise "border sectors error" if b.spaces.select{ |k,s| s.border? }.size != 9 + # b.spaces.select{ |s| s.border? }.each { |s| puts s.name } + raise "border sectors error" if b.spaces.select{ |s| s.border? }.size != 9 # puts '--- City' - # b.spaces.select{ |k,s| s.city? }.each { |k,s| puts s.name } - raise "city sectors error" if b.spaces.select{ |k,s| s.city? }.size != 3 + # b.spaces.select{ |s| s.city? }.each { |s| puts s.name } + raise "city sectors error" if b.spaces.select{ |s| s.city? }.size != 3 [[0,11],[1,9],[2,9],[3,1]].each do |p,n| # puts "--- Population #{p}" - # b.spaces.select{ |k,s| s.pop==p }.each { |k,s| puts s.name } - raise "population #{p} error" if b.spaces.select{ |k,s| s.pop==p}.size != n + # b.spaces.select{ |s| s.pop==p }.each { |s| puts s.name } + raise "population #{p} error" if b.spaces.select{ |s| s.pop==p}.size != n end raise "sectors count wrong" if b.sectors.size != 28 end @@ -457,7 +573,7 @@ if $PROGRAM_NAME == __FILE__ sup, opp, gov, fln = 0, 0, 0, 0 ft, fp, at, ap, g = 0, 0, 0, 0, 0 gb, fb = 0, 0 - b.spaces.each do |n,s| + b.spaces.each do |s| sup += 1 if s.alignment == :support opp += 1 if s.alignment == :oppose gov += 1 if s.control == :GOV -- cgit v1.1-2-g2b99