From 40f6759106bc429ff49cdaefdf8901ebb68688c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Zurcher?= Date: Mon, 23 Oct 2023 21:44:50 +0200 Subject: FLNBotRules : major rewrite + specs --- lib/colonial_twilight/fln_bot_rules.rb | 181 +++++++----- spec/fln_bot_rules_spec.rb | 495 +++++++++++++++++++++++---------- 2 files changed, 460 insertions(+), 216 deletions(-) diff --git a/lib/colonial_twilight/fln_bot_rules.rb b/lib/colonial_twilight/fln_bot_rules.rb index e9b9e79..cbe2145 100644 --- a/lib/colonial_twilight/fln_bot_rules.rb +++ b/lib/colonial_twilight/fln_bot_rules.rb @@ -12,44 +12,40 @@ module ColonialTwilight end end - def pass? + def pass?(board = @board) # if resources = 0 && Op Limited as only choice - r = @board.fln_resources.zero? && limited_op_only? + r = board.fln_resources.zero? && limited_op_only? dbg 'PASS', r r end - def terror1? - # unless any FLN base is (pop 0 && 0 FLN underground or pop 1+ && 1- FLN underground) - r = !@board.has do |s| - s.fln_bases.positive? && - ((s.pop.zero? && s.fln_underground.zero?) || (!s.pop.zero? && s.fln_underground < 2)) + def terror1?(board = @board) + # if no FLN base is (pop 0 && 0 FLN underground or pop 1+ && 1- FLN underground) + r = !board.has do |s| + s.fln_bases.positive? && ((s.pop.zero? && s.fln_underground.zero?) || (!s.pop.zero? && s.fln_underground < 2)) end dbg 'TERROR 1', r r end - def terror2? + def terror2?(_board = nil) # if GOV is first eligible && will be second eligible r = !first_eligible? && will_be_next_first_eligible? dbg 'TERROR 2', r r end - def rally1? - # rally would place bases (first 2 bullets) - # 4+ or (3+ FLN and no GOV (unless limited_op_only)) - r = @board.available_fln_bases.positive? && @board.has do |s| - may_add_base_in?(s) && (rally_2_in?(s) || rally_1_in?(s)) - end + def rally1?(board = @board) + # rally would place a base (rally 1 or 2) + r = board.available_fln_bases.positive? && board.has { |s| (may_rally_1_in?(s) || may_rally_2_in?(s)) } dbg 'RALLY 1', r r end - def rally2? + def rally2?(board = @board) # if #FLN bases * 2 > #FLN at FLN bases + 1d6/2 - a = @board.count(&:fln_bases) * 2 - b = @board.count { |s| s.fln_bases.zero? ? 0 : s.fln_cubes } + a = board.count(&:fln_bases) * 2 + b = board.count { |s| s.fln_bases.zero? ? 0 : s.guerrillas } r = a > (b + d6 / 2) dbg 'RALLY 2', r r @@ -57,87 +53,148 @@ module ColonialTwilight # Rally - def may_add_base_in?(space) - r = space.fln_cubes > 2 && (space.fln_bases < (space.country? ? space.max_bases : 1)) - dbg " may_add_base : #{space.name}", r - r - end - - def rally_1_in?(space) + def may_rally_1_in?(space) # 3+ FLN and no GOV (unless limited_op_only)) - r = space.fln_cubes >= 3 && (limited_op_only? ? true : space.gov_cubes.zero?) - dbg " rally_1_in : #{space.name}", r + r = may_rally_in?(space) && may_add_base_in?(space) && space.guerrillas >= 3 && + (limited_op_only? ? true : space.gov_cubes.zero?) + dbg " may_rally_1_in : #{space.name}", r r end - def rally_2_in?(space) + def may_rally_2_in?(space) # 4+ FLN - r = space.fln_cubes >= 4 - dbg " rally_2_in : #{space.name}", r + r = may_rally_in?(space) && may_add_base_in?(space) && space.guerrillas >= 4 + dbg " may_rally_2_in : #{space.name}", r r end - def rally_3_in?(space) + def may_rally_3_in?(space) # at FLN bases, with 2- FLN underground or 0 fln_undergroud in country or 0 pop - r = !space.fln_bases.zero? && + r = may_rally_in?(space) && !space.fln_bases.zero? && (space.country? || space.pop.zero? ? space.fln_underground.zero? : space.fln_underground < 2) - dbg " rally_3_in : #{space.name}", r + dbg " may_rally_3_in : #{space.name}", r r end def rally_3_priority(spaces) # Algeria -> with cubes -> pop 1+ -> least FLN underground - l0 = (l0 = spaces.reject(&:country?)).empty? ? spaces : l0 - l1 = (l1 = l0.select { |s| s.gov_cubes.positive? }).empty? ? l0 : l1 - l2 = (l2 = l1.select { |s| s.pop.positive? }).empty? ? l1 : l2 - l2.min { |a, b| a.fln_underground <=> b.fln_underground } + f = _filter(spaces) { |s| !s.country? } + f = _filter(f) { |s| s.gov_cubes.positive? } + f = _filter(f) { |s| s.pop.positive? } + _min(f, :fln_underground).shuffle end - def rally_5_in?(space) + def may_rally_5_in?(space) # non-city at support with 0 FLN underground - r = !space.city? && space.support? && space.fln_underground.zero? - dbg " rally_5_in : #{space.name}", r + r = may_rally_in?(space) && !space.city? && space.support? && space.fln_underground.zero? + dbg " may_rally_5_in : #{space.name}", r r end - def rally_6_in?(space) - # 2+ pop to agitate - r = space.pop > 1 && may_agitate_in?(space) - dbg " rally_6_in : #{space.name}", r + def rally_5_priority(spaces) + # highest population + _max(spaces, :pop).shuffle + end + + def may_rally_6_in?(space, already_rallied) + # 2+ pop to agitate after rally + r = (already_rallied || may_rally_in?(space)) && space.pop > 1 + dbg " may_rally_6_in : #{space.name}", r r end - def rally_8_in?(space) - r = !space.fln_cubes.zero? && space.fln_bases.zero? - dbg " rally_8_in : #{space.name}", r + def rally_6_priority(spaces) + # max pop, min terror, support : reference ? + f = _max(spaces, :pop) + f = _min(f, :terror) + f = _filter(f, &:support?) + # FIXME: maybe already selected first, or not + f.shuffle + end + + def may_rally_7_in?(space) + r = may_rally_in?(space) + dbg " may_rally_7_in : #{space.name}", r r end + def rally_7_priority(spaces) + # highest population + _max(spaces, :pop).shuffle + end + + def rally_7_priority_after(spaces) + # in city, least terror + f = _filter(spaces, &:city?) + _min(f, :terror).shuffle + end + + def may_rally_8_in?(space) + r = may_rally_in?(space) && !space.guerrillas.zero? && space.fln_bases.zero? + dbg " may_rally_8_in : #{space.name}", r + r + end + + def rally_8_priority(spaces) + # Algeria -> most Guerrillas -> no gov cubes + f = _filter(spaces) { |s| !s.country? } + f = _max(f, :guerrillas) + _filter(f) { |s| s.gov_cubes.zero? }.shuffle + end + # 8.1.2 - Procedure Guidelines - def fln_to_place? - @board.available_fln_underground.positive? || !place_from(@board.spaces).nil? + + def _filter(spaces, &block) + (f = spaces.select(&block)).empty? ? spaces : f + end + + def _max(spaces, sym) + v = spaces.max { |a, b| a.send(sym) <=> b.send(sym) }.send(sym) + spaces.select { |s| s.send(sym) == v } + end + + def _min(spaces, sym) + v = spaces.min { |a, b| a.send(sym) <=> b.send(sym) }.send(sym) + spaces.select { |s| s.send(sym) == v } + end + + def may_add_base_in?(space) + space.guerrillas > 2 && (space.fln_bases < (space.country? ? space.max_bases : 1)) + end + + def max_placable_guerrillas_in?(space) + n = max_placable_guerrillas(space) + n = n.clamp(0, space.pop + 1 - space.guerrillas) if space.fln_bases.positive? + n end - # 1) place: outofplay -> available | bases -> cubes if choice - # 2) place: underground first unless from map then place active first flipped as underground - # 3) march: underground -> active, unless march would activate then move active first + # 1) place: outofplay -> available | bases -> guerrillas if choice + # 2) place: underground first unless from map then place active first flipped as underground + # 3) march: underground -> active, unless march would activate then move active first - def place_in(spaces) + def place_guerrillas(spaces) # 4) support -> with friendly pieces -> random l0 = (l0 = spaces.select(&:support?)).empty? ? spaces : l0 - l1 = (l1 = l0.select { |s| s.fln_cubes.positive? }).empty? ? l0 : l1 - (l1.empty? ? @board.spaces : l1).sample + l1 = (l1 = l0.select { |s| s.guerrillas.positive? }).empty? ? l0 : l1 + l1.shuffle end - def place_from(spaces) - # 5) active only, leave 2 cubes at base or support, most cubes first - l = spaces.select do |s| - s.fln_active.positive? && (s.support? || s.fln_bases.positive? ? s.fln_cubes > 2 : true) - end - return nil if l.empty? + def removable_guerrillas(space) + # 5) active only, leave 2 guerrillas at base or support + a = (a = space.fln_underground) > 2 ? 2 : a + n = space.fln_active - (space.support? || space.fln_bases.positive? ? (2 - a) : 0) + n.positive? ? n : 0 + end + + def not_selected(spaces, steps) + spaces.reject { |s| steps.key?(s) } + end + + def remove_guerrillas_priority(spaces, steps) + # 5) #removable_guerrillas then most guerrillas first + return [] if (l = not_selected(spaces, steps).select { |s| removable_guerrillas(s).positive? }).empty? - v = l.max { |a, b| a.fln_cubes <=> b.fln_cubes }.fln_cubes - l.select { |s| s.fln_cubes == v }.sample + _max(l, :guerrillas).shuffle end def remove_from(space, num = 1) diff --git a/spec/fln_bot_rules_spec.rb b/spec/fln_bot_rules_spec.rb index 2330ac1..547e2ea 100644 --- a/spec/fln_bot_rules_spec.rb +++ b/spec/fln_bot_rules_spec.rb @@ -1,279 +1,466 @@ # frozen_string_literal: true require './lib/colonial_twilight/fln_bot_rules' -require './lib/colonial_twilight/game' +require './spec/mock_board' class FLNRulesImpl include ColonialTwilight::FLNBotRules + attr_reader :board + attr_writer :limited_op_only, :first_eligible, :will_be_next_first_eligible + def initialize @debug = 0 - @board = nil + @board = Board.new + @limited_op_only = true + @first_eligible = true + @will_be_next_first_eligible = true + end + + def set(hash = {}) + board.sector.data = hash + board.sector end - attr_writer :board def limited_op_only? - true + @limited_op_only end def d6 - 5 + 3 end - # def first_eligible? - # true - # end - # - # def will_be_next_first_eligible? - # true - # end + def first_eligible? + @first_eligible + end + + def will_be_next_first_eligible? + @will_be_next_first_eligible + end end describe ColonialTwilight::FLNBotRules do - - rules = FLNRulesImpl.new before do - @board = ColonialTwilight::Board.new - @board.load :short - rules.board = @board + @rules = FLNRulesImpl.new + @board = @rules.board end describe 'Pass' do - it 'pass? no' do - expect(rules.pass?).to be false + it 'pass? no resources' do + expect(@rules.pass?).to be true end - it 'pass? no resources' do - @board.shift_track :fln_resources, -15 - expect(rules.pass?).to be true + it 'pass? no resources but not op only' do + @rules.limited_op_only = false + expect(@rules.pass?).to be false + end + + it 'pass? has resources' do + @rules.board.fln_resources = 15 + expect(@rules.pass?).to be false end end describe 'Terror' do - it 'terror1? no' do - expect(rules.terror1?).to be false + it 'terror1? 1 pop 2 underground' do + @rules.set({ pop: 1, fln_bases: 1, fln_underground: 2 }) + expect(@rules.terror1?).to be true end - it 'terror1? all bases are protected' do - @board.by_name('Souk Ahras').add :fln_underground - @board.by_name('Tizi Ouzou').add :fln_underground - @board.by_name('Bougie').add :fln_underground - @board.by_name('Orleansville').add :fln_underground - expect(rules.terror1?).to be true + it 'terror1? 1 pop 1 underground' do + @rules.set({ pop: 1, fln_bases: 1, fln_underground: 1 }) + expect(@rules.terror1?).to be false end - # it 'terror2? true' do - # expect(rules.terror2?).to be false - # end + it 'terror1? 0 pop 1 underground' do + @rules.set({ pop: 0, fln_bases: 1, fln_underground: 1 }) + expect(@rules.terror1?).to be true + end + + it 'terror1? 0 pop 0 underground' do + @rules.set({ pop: 0, fln_bases: 1, fln_underground: 0 }) + expect(@rules.terror1?).to be false + end + + it 'terror2?' do + expect(@rules.terror2?).to be false + end + + it 'terror2? true' do + @rules.first_eligible = false + expect(@rules.terror2?).to be true + end + + it 'terror2? true' do + @rules.first_eligible = false + @rules.will_be_next_first_eligible = false + expect(@rules.terror2?).to be false + end end describe 'Rally' do - it 'rally1? false' do - expect(rules.rally1?).to be false + expect(@rules.rally1?).to be false end it 'rally1? may rally_1' do - space = @board.by_name('Barika') - space.add :fln_active, 2 - expect(rules.rally1?).to be true + @rules.set({ fln_active: 1, fln_underground: 2 }) + expect(@rules.rally1?).to be true end it 'rally1? may rally_2' do - space = @board.by_name('Barika') - space.add :fln_active, 3 - expect(rules.rally1?).to be true + @rules.set({ fln_active: 2, fln_underground: 2 }) + expect(@rules.rally1?).to be true + end + + it 'rally1? may rally_1 but no bases' do + @rules.set({ fln_active: 1, fln_underground: 2 }) + @board.available_fln_bases = 0 + expect(@rules.rally1?).to be false + end + + it 'rally1? may rally_2 but no bases' do + @rules.set({ fln_active: 2, fln_underground: 2 }) + @board.available_fln_bases = 0 + expect(@rules.rally1?).to be false end it 'rally2? enough fln at bases' do - expect(rules.rally2?).to be true + @rules.set({ fln_bases: 2, fln_underground: 3 }) + expect(@rules.rally2?).to be false end it 'rally2? false' do - @board.by_name('Bougie').add :fln_active, 1 - expect(rules.rally2?).to be false + @rules.set({ fln_bases: 2, fln_underground: 2 }) + expect(@rules.rally2?).to be true end + end - it 'may_add_base_in?' do - expect(@board.spaces.select(&rules.method(:may_add_base_in?)).size).to eq(0) + describe 'Rally Specific' do + it 'may_rally_1_in? not enough fln guerrillas' do + a = Sector.new({ fln_active: 1, fln_underground: 1 }) + expect(@rules.may_rally_1_in?(a)).to be false end - it 'may_add_base_in?' do - @board.by_name('Batna').add :fln_active, 3 - expect(@board.spaces.select(&rules.method(:may_add_base_in?))[0].name).to eq('Batna') + it 'may_rally_1_in? 3+ guerrillas' do + a = Sector.new({ fln_active: 1, fln_underground: 2 }) + expect(@rules.may_rally_1_in?(a)).to be true end - it 'may_add_base_in?' do - space = @board.by_name('Batna') - space.add :fln_active, 6 - space.add :fln_base, 1 - expect(@board.spaces.select(&rules.method(:may_add_base_in?)).size).to eq(0) + it 'may_rally_1_in? 3+ guerrillas no limited op' do + a = Sector.new({ fln_active: 1, fln_underground: 2 }) + @rules.limited_op_only = false + expect(@rules.may_rally_1_in?(a)).to be true end - it 'rally_1_in? not enough fln cubes' do - space = @board.by_name('Barika') - expect(rules.rally_1_in?(space)).to be false + it 'may_rally_1_in? 3+ guerrillas but gov cubes' do + a = Sector.new({ fln_active: 1, fln_underground: 2, gov_cubes: 1 }) + @rules.limited_op_only = false + expect(@rules.may_rally_1_in?(a)).to be false end - it 'rally_1_in? enough fln cubes' do - space = @board.by_name('Barika') - space.add :fln_active, 2 - expect(rules.rally_1_in?(space)).to be true + it 'may_rally_2_in? not enough fln guerrillas' do + a = Sector.new({ fln_active: 2, fln_underground: 1 }) + expect(@rules.may_rally_2_in?(a)).to be false end - it 'rally_2_in? not enough fln cubes' do - space = @board.by_name('Barika') - expect(rules.rally_2_in?(space)).to be false + it 'may_rally_2_in? 4+ guerrillas' do + a = Sector.new({ fln_active: 2, fln_underground: 2 }) + expect(@rules.may_rally_2_in?(a)).to be true end - it 'rally_2_in? enough fln cubes' do - space = @board.by_name('Barika') - space.add :fln_active, 3 - expect(rules.rally_2_in?(space)).to be true + it 'may_rally_3_in? no base' do + a = Sector.new + expect(@rules.may_rally_3_in?(a)).to be false end - it 'rally_3_in? no base' do - space = @board.by_name('Batna') - expect(rules.rally_3_in?(space)).to be false + it 'may_rally_3_in? base and pop 0' do + a = Sector.new({ fln_bases: 1 }) + expect(@rules.may_rally_3_in?(a)).to be true end - it 'rally_3_in? base and 0 pop and 0 fln underground' do - space = @board.by_name('Batna') - space.add :fln_base, 1 - expect(rules.rally_3_in?(space)).to be true + it 'may_rally_3_in? base and pop 0 but has fln underground' do + a = Sector.new({ fln_bases: 1, fln_underground: 1 }) + expect(@rules.may_rally_3_in?(a)).to be false end - it 'rally_3_in? base and 0 pop but fln underground' do - space = @board.by_name('Batna') - space.add :fln_base, 1 - space.add :fln_underground, 1 - expect(rules.rally_3_in?(space)).to be false + it 'may_rally_3_in? base and country but not independent' do + a = Sector.new({ fln_bases: 1, pop: 1, name: 'country', independent: false }) + expect(@rules.may_rally_3_in?(a)).to be false end - it 'rally_3_in? base and not enough fln underground' do - space = @board.by_name('Bougie') - expect(rules.rally_3_in?(space)).to be true + it 'may_rally_3_in? base and country' do + a = Sector.new({ fln_bases: 1, pop: 1, name: 'country', independent: true }) + expect(@rules.may_rally_3_in?(a)).to be true end - it 'rally_3_in? base but not enough fln underground' do - space = @board.by_name('Bougie') - space.add :fln_underground, 1 - expect(rules.rally_3_in?(space)).to be false + it 'may_rally_3_in? base and country but has fln underground' do + a = Sector.new({ fln_bases: 1, pop: 1, name: 'country', independent: true, fln_underground: 1 }) + expect(@rules.may_rally_3_in?(a)).to be false + end + + it 'may_rally_3_in? base and pop' do + a = Sector.new({ fln_bases: 1, pop: 1, fln_underground: 1 }) + expect(@rules.may_rally_3_in?(a)).to be true + end + + it 'may_rally_3_in? base and pop but too many fln underground ' do + a = Sector.new({ fln_bases: 1, pop: 1, fln_underground: 2 }) + expect(@rules.may_rally_3_in?(a)).to be false end it 'rally_3_priority Algeria' do - a = @board.by_name('Ain Oussera') - b = @board.by_name('Morocco') - b.add :fln_base, -2 - b.add :fln_underground, -4 - expect(rules.rally_3_priority([a, b]).name).to eq('Ain Oussera') + a = Sector.new + b = Sector.new({ name: 'country' }) + expect(@rules.rally_3_priority([a, b])[0]).to be a end it 'rally_3_priority with GOV cubes' do - a = @board.by_name('Mecheria') - b = @board.by_name('Saida') - expect(rules.rally_3_priority([a, b]).name).to eq('Mecheria') + a = Sector.new + b = Sector.new({ gov_cubes: 1 }) + expect(@rules.rally_3_priority([a, b])[0]).to be b end it 'rally_3_priority pop 1+' do - a = @board.by_name('Ain Oussera') - b = @board.by_name('Sidi Aissa') - expect(rules.rally_3_priority([a, b]).name).to eq('Ain Oussera') + a = Sector.new({ pop: 1 }) + b = Sector.new({ gov_cubes: 1, pop: 1 }) + c = Sector.new({ gov_cubes: 1 }) + expect(@rules.rally_3_priority([a, b, c])[0]).to be b end it 'rally_3_priority least fln_underground' do - a = @board.by_name('Tebessa') - a.add :fln_underground, 1 - b = @board.by_name('Barika') - expect(rules.rally_3_priority([a, b]).name).to eq('Barika') + a = Sector.new({ pop: 1 }) + b = Sector.new({ gov_cubes: 1, pop: 1 }) + c = Sector.new({ gov_cubes: 1, pop: 1, fln_underground: 1 }) + expect(@rules.rally_3_priority([a, b, c])[0]).to be b + end + + it 'may_rally_5_in? city' do + a = Sector.new({ name: 'city', support: true }) + expect(@rules.may_rally_5_in?(a)).to be false + end + + it 'may_rally_5_in? fln underground' do + a = Sector.new({ support: true, fln_underground: 1 }) + expect(@rules.may_rally_5_in?(a)).to be false + end + + it 'may_rally_5_in? no support' do + a = Sector.new({ support: false }) + expect(@rules.may_rally_5_in?(a)).to be false + end + + it 'may_rally_5_in? good' do + a = Sector.new({ support: true }) + expect(@rules.may_rally_5_in?(a)).to be true + end + + it 'rally_5_priority most pop' do + a = Sector.new({ pop: 1 }) + b = Sector.new({ pop: 2 }) + expect(@rules.rally_5_priority([a, b])[0]).to be b + end + + it 'may_rally_6_in? pop 1' do + a = Sector.new({ pop: 1 }) + expect(@rules.may_rally_6_in?(a, false)).to be false + end + + it 'may_rally_6_in? pop 1+' do + a = Sector.new({ pop: 2 }) + expect(@rules.may_rally_6_in?(a, false)).to be true + end + + it 'rally_6_priority population' do + a = Sector.new({ pop: 2 }) + b = Sector.new({ pop: 1 }) + expect(@rules.rally_6_priority([a, b])[0]).to be a + end + + it 'rally_6_priority min terror' do + a = Sector.new({ pop: 1, terror: 2 }) + b = Sector.new({ pop: 2, terror: 1 }) + c = Sector.new({ pop: 2, terror: 2 }) + expect(@rules.rally_6_priority([a, b, c])[0]).to be b + end + + it 'rally_6_priority support' do + a = Sector.new({ pop: 2, terror: 1, support: false }) + b = Sector.new({ pop: 2, terror: 1, support: true }) + c = Sector.new({ pop: 2, terror: 2, support: true }) + expect(@rules.rally_6_priority([a, b, c])[0]).to be b + end + + it 'may_rally_7_in?' do + a = Sector.new + expect(@rules.may_rally_7_in?(a)).to be true + end + + it 'may_rally_7_in? not in city at support' do + a = Sector.new({ name: 'city', support: true }) + expect(@rules.may_rally_7_in?(a)).to be false + end + + it 'may_rally_7_in? not in not independent country' do + a = Sector.new({ name: 'country', independent: false }) + expect(@rules.may_rally_7_in?(a)).to be false + end + + it 'rally_7_priority_after city?' do + a = Sector.new({ name: 'city' }) + b = Sector.new + expect(@rules.rally_7_priority_after([a, b])[0]).to be a + end + + it 'rally_7_priority_after least terror' do + a = Sector.new + b = Sector.new({ name: 'city', terror: 1 }) + c = Sector.new({ name: 'city', terror: 2 }) + expect(@rules.rally_7_priority_after([a, b, c])[0]).to be b end - it 'rally_5_in? city' do - space = @board.by_name('Oran') - expect(rules.rally_5_in?(space)).to be false + it 'rally_7_priority population' do + a = Sector.new({ pop: 2 }) + b = Sector.new({ pop: 1 }) + expect(@rules.rally_7_priority([a, b])[0]).to be a end - it 'rally_5_in? support but fln underground' do - space = @board.by_name('Barika') - space.shift :support - expect(rules.rally_5_in?(space)).to be false + it 'rally_7_priority population' do + a = Sector.new({ pop: 2 }) + b = Sector.new({ pop: 1 }) + expect(@rules.rally_7_priority([a, b])[0]).to be a end - it 'rally_5_in? support and fln underground' do - space = @board.by_name('Barika') - space.shift :support - space.add :fln_underground, -1 - expect(rules.rally_5_in?(space)).to be false + it 'may_rally_8_in? no fln guerrillas' do + a = Sector.new + expect(@rules.may_rally_8_in?(a)).to be false end - it 'rally_6_in? 2+ pop but no fln control' do - space = @board.by_name('Medea') - expect(rules.rally_6_in?(space)).to be false + it 'may_rally_8_in? fln guerrillas but base' do + a = Sector.new({ fln_active: 1, fln_bases: 1 }) + expect(@rules.may_rally_8_in?(a)).to be false end - it 'rally_6_in? 2+ pop and fln' do - space = @board.by_name('Medea') - space.add :fln_active, 3 - expect(rules.rally_6_in?(space)).to be true + it 'may_rally_8_in? fln guerrillas and 0 base' do + a = Sector.new({ fln_underground: 1 }) + expect(@rules.may_rally_8_in?(a)).to be true end - it 'rally_8_in? no fln cubes' do - space = @board.by_name('Tiaret') - expect(rules.rally_8_in?(space)).to be false + it 'rally_8_priority Algeria' do + a = Sector.new + b = Sector.new({ name: 'country' }) + expect(@rules.rally_8_priority([a, b])[0]).to be a end - it 'rally_8_in? fln cubes but base' do - space = @board.by_name('Bougie') - expect(rules.rally_8_in?(space)).to be false + it 'rally_8_priority most guerrillas' do + a = Sector.new + b = Sector.new({ fln_active: 2, fln_underground: 1 }) + c = Sector.new({ fln_active: 1, fln_underground: 1 }) + expect(@rules.rally_8_priority([a, b, c])[0]).to be b end - it 'rally_8_in? fln cubes and 0 base' do - space = @board.by_name('Barika') - expect(rules.rally_8_in?(space)).to be true + it 'rally_8_priority no cubes' do + a = Sector.new + b = Sector.new({ fln_active: 1, fln_underground: 1 }) + c = Sector.new({ fln_active: 1, fln_underground: 1, gov_cubes: 1 }) + expect(@rules.rally_8_priority([a, b, c])[0]).to be b end end describe '8.1.2 Procedure Guidelines' do - it 'place_in' do - expect(rules.place_in(@board.spaces).city?).to be true + it 'may_add_base_in?' do + a = Sector.new({ fln_active: 3 }) + expect(@rules.may_add_base_in?(a)).to be true + end + + it 'may_add_base_in? not enough fln' do + a = Sector.new({ fln_active: 2 }) + expect(@rules.may_add_base_in?(a)).to be false + end + + it 'may_add_base_in? but has base' do + a = Sector.new({ fln_bases: 1, fln_active: 3 }) + expect(@rules.may_add_base_in?(a)).to be false + end + + it 'may_add_base_in? country ' do + a = Sector.new({ name: 'country', fln_bases: 2, fln_active: 3 }) + expect(@rules.may_add_base_in?(a)).to be true + end + + it 'may_add_base_in? country but limit' do + a = Sector.new({ name: 'country', fln_bases: 3, fln_active: 3 }) + expect(@rules.may_add_base_in?(a)).to be false + end + + it 'max_placable_guerrillas_in? 1' do + a = Sector.new({ pop: 2 }) + expect(@rules.max_placable_guerrillas_in?(a)).to eq(1) + end + + it 'max_placable_guerrillas_in? pop + base' do + a = Sector.new({ pop: 2, fln_bases: 1 }) + expect(@rules.max_placable_guerrillas_in?(a)).to eq(3) + end + + it 'max_placable_guerrillas_in? max pop + 1' do + a = Sector.new({ pop: 2, fln_bases: 1, fln_active: 1, fln_underground: 1 }) + expect(@rules.max_placable_guerrillas_in?(a)).to eq(1) + end + + it 'removable_guerrillas active' do + a = Sector.new({ fln_active: 2, fln_underground: 3 }) + expect(@rules.removable_guerrillas(a)).to eq(2) + end + + it 'removable_guerrillas leave 2 at support' do + a = Sector.new({ support: true, fln_active: 3 }) + expect(@rules.removable_guerrillas(a)).to eq(1) + end + + it 'removable guerrillas leave 2 at bases' do + a = Sector.new({ fln_bases: 1, fln_active: 3, fln_underground: 1 }) + expect(@rules.removable_guerrillas(a)).to eq(2) end - it 'place_in support' do - space = @board.by_name('Mostaganem') - space.add :fln_active, 3 - expect(rules.place_in(@board.spaces).city?).to be true + it 'place_guerrillas support' do + a = Sector.new({ support: false }) + b = Sector.new({ support: true }) + c = Sector.new({ support: false }) + expect(@rules.place_guerrillas([a, b, c])[0]).to be b end - it 'place_in support and fln_active' do - space = @board.by_name('Mostaganem') - space.shift :support - space.add :fln_active, 3 - expect(rules.place_in(@board.spaces).name).to be 'Mostaganem' + it 'place_guerrillas support and fln_active' do + a = Sector.new({ support: false }) + b = Sector.new({ support: true, fln_active: 1 }) + c = Sector.new({ support: true }) + expect(@rules.place_guerrillas([a, b, c])[0]).to be b end - it 'place_from none' do - expect(rules.place_from(@board.spaces).nil?).to be true + it 'remove_guerrillas_priority none' do + a = Sector.new + b = Sector.new + expect(@rules.remove_guerrillas_priority([a, b], {}).empty?).to be true end - it 'place_from most active' do - @board.by_name('Oran').add :fln_active, 1 - @board.by_name('Batna').add :fln_active, 3 - @board.by_name('Negrine').add :fln_active, 2 - expect(rules.place_from(@board.spaces).name).to be 'Batna' + it 'remove_guerrillas_priority most guerrillas' do + a = Sector.new({ fln_active: 2, fln_underground: 1 }) + b = Sector.new({ fln_active: 2, fln_underground: 2 }) + c = Sector.new({ fln_active: 1, fln_underground: 2 }) + d = Sector.new({ fln_active: 3, fln_underground: 2 }) + expect(@rules.remove_guerrillas_priority([a, b, c, d], { d => true })[0]).to be b end it 'remove_from all' do - space = @board.by_name('Bougie') - space.add :fln_active, 2 - h = rules.remove_from(space, 6) + a = Sector.new({ fln_active: 2, fln_underground: 1, fln_bases: 1 }) + h = @rules.remove_from(a, 6) expect(h[:fln_underground]).to be 1 expect(h[:fln_active]).to be 2 expect(h[:fln_bases]).to be 1 end it 'remove_from a few' do - space = @board.by_name('Bougie') - space.add :fln_active, 1 - h = rules.remove_from(space, 2) + a = Sector.new({ fln_active: 1, fln_underground: 1 }) + h = @rules.remove_from(a, 2) expect(h[:fln_underground]).to be 1 expect(h[:fln_active]).to be 1 expect(h[:fln_bases]).to be 0 -- cgit v1.1-2-g2b99