note description: "[ Root class for all the game pieces in VITP. ]" author: "Jimmy J. Johnson" deferred class ATTACK_UNIT inherit VITP_ITEM redefine make end COMPARABLE undefine copy, is_equal end feature -- Initialization make (a_game: like game) -- Initialize with the values; these are initial values and cannot be changed -- `a_name' = name of the ship or unit -- `a_nationality' = country to which it belongs -- `a_arrival_turn' = turn 1 to 9 in which the unit enters the game -- `a_airstrike' = the unit's "airstrike factor" -- `a_guns' = the unit's "gunnery factor" -- `a_armor' = the unit's "armor factor" -- `a_speed' = the unit's "speed factor" -- `a_bonus' = true if the unit has an initial attack bonus local lin: LINEAR [PORT] do Precursor {VITP_ITEM} (a_game) create task_force.make (a_game) task_force.set_ordered -- arrival_location := game.still_in_box position := [0, 0] -- Initialize to never return (changed for air and amphibious units) returning_turn := 0 task_force.extend (Current) end feature -- Access arrival_turn: INTEGER -- Turn on which this unit enters the game. deferred end airstrike_factor: INTEGER -- The initial number of dice the unit rolls when attacking -- during a "day action". deferred end gunnery_factor: INTEGER -- The initial value for the number of dice the unit rolls -- when attacking during a "night action". deferred end defense_factor: INTEGER -- The number of damage points a unit can have without sinking. -- (This is doubled when the unit is in port.) deferred end speed_factor: INTEGER -- The initial "speed" of the unit. deferred end attack_bonus: BOOLEAN -- The initial setting saying if a unit can add one to each die roll. -- If the unit is a carrier this applies only to the airstrike factor. deferred end returning_turn: INTEGER -- The turn on which this unit can reenter the game. home_port: PORT -- The {PORT} from which Current is basing this turn. attribute Result := game.default_port end location: LOCATION -- The sea, base, or port at which Current is located. attribute -- Result := game.still_in_box if Current.is_japanese then Result := game.japanese_oa_chart else if Current.arrival_turn = 1 then Result := game.allied_starting_forces_chart else Result := game.allied_oa_chart end end end damage: INTEGER -- The amount of total damage Current has taken gunnery_count: INTEGER -- Number of dice the unit rolls when attacking during a "night action". -- It is the `Gunnery_factor' reduced by the amount of `damage'. do Result := (gunnery_factor - damage).max (1) end defense_count: INTEGER -- The amount of armor remaining, used to determine if a unit is "sunk". do Result := defense_factor - damage end speed_count: INTEGER -- The actual speed of Current calculated from other factors do Result := (speed_factor - damage).max (1) end airstrike_count: INTEGER -- Number of dice the unit rolls when attacking during a "day actions". do Result := airstrike_factor end task_force: TASK_FORCE -- The whole force including Current if others target: ATTACK_UNIT -- The target (if `is_targetting') do check attached target_imp as t then Result := t end end relative_value: INTEGER -- Relative value of current to other units, calculated from the -- current values of the gunnery, defense, and speed counts. local b_fac: INTEGER do if attack_bonus then if airstrike_factor > 0 then -- Apply bonus to airstrike only b_fac := Bonus_weight * airstrike_weight -- Result := (airstrike_count + Bonus_weight) * Airstrike_weight -- Result := Result + gunnery_count * Gunnery_weight else -- apply bonus to guns unless too much damage if defense_count > 0 then b_fac := Bonus_weight * Gunnery_weight -- Result := (gunnery_count + Bonus_weight) * Gunnery_weight -- Result := Result + airstrike_count * Airstrike_weight end end end Result := b_fac + airstrike_count + gunnery_count Result := Result + defense_count * Defense_weight + speed_factor * Speed_weight -- if Current = Tone then -- do_nothing -- end -- if Current = Mutsu then -- do_nothing -- end end patrol_distance: INTEGER -- How may sea areas can Current move through as patroller? -- Determined by the unit type and nationality do Result := 2 end raid_distance: INTEGER -- How many sea areas can Current move through as raider? -- Determined by the unit type and nationality local has_non_major: BOOLEAN do if is_task_force then from task_force.start until task_force.exhausted or has_non_major loop if not task_force.item.is_major_power then has_non_major := true end task_force.forth end end if not has_non_major then Result := patrol_distance + 1 end end feature -- Access sailing_distance: INTEGER -- The distance Current can patrol or raid (depending on `is_raiding'). -- This is the minimum of all contained units. local f: INTEGER u: ATTACK_UNIT do Result := {INTEGER}.Max_value from task_force.start until task_force.is_after loop u := task_force.item if u.sailing_distance < Result then Result := f end task_force.forth end end reinforceable_ports: LINKED_SET [PORT] -- A list containing each {PORT} to which Current -- can be moved during the reinforcement step. require is_reinforcing: game.sequence_of_play.is_reinforcement_step deferred end patrolable_sea_areas: LINKED_SET [SEA_AREA] -- A list containing each {SEA_AREA} to which Current -- can be moved during the moving patrollers step. local sop: VITP_SEQUENCE_OF_PLAY sd: INTEGER s: SEA_AREA dist: INTEGER do -- io.put_string ("ATTCK_UNIT.patrolable_sea_areas: fix using GRAPH_ITERATOR.shortest_paths %N") create Result.make sop := game.sequence_of_play if sop.is_patrolling_step and ((not game.is_allied_nationality (nationality) and then sop.is_japanese_player) or else (game.is_allied_nationality (nationality) and then sop.is_allied_player)) then if home_port = game.yokosuka_navy_yard or home_port = game.okinawa then Result.extend (game.japanese_islands) if not is_opposed (game.japanese_islands) then Result.extend (game.indonesia) Result.extend (game.marianas_islands) Result.extend (game.central_pacific_ocean) Result.extend (game.aleutian_islands) end elseif home_port = game.saigon or home_port = game.singapore then Result.extend (game.indonesia) if not is_opposed (game.indonesia) then Result.extend (game.bay_of_bengal) Result.extend (game.indian_ocean) Result.extend (game.south_pacific_ocean) Result.extend (game.marianas_islands) Result.extend (game.japanese_islands) end elseif home_port = game.ceylon or home_port = game.andaman_islands then Result.extend (game.bay_of_Bengal) if not is_opposed (game.bay_of_bengal) then Result.extend (game.indonesia) Result.extend (game.indian_ocean) end elseif home_port = game.philippines then Result.extend (game.indonesia) Result.extend (game.marianas_Islands) if not is_opposed (game.indonesia) then Result.extend (game.bay_of_bengal) Result.extend (game.indian_ocean) Result.extend (game.south_pacific_ocean) Result.extend (game.marianas_islands) Result.extend (game.japanese_islands) end if not is_opposed (game.marianas_islands) then Result.extend (game.south_pacific_ocean) Result.extend (game.marshall_islands) Result.extend (game.central_pacific_ocean) Result.extend (game.japanese_islands) end elseif home_port = game.lae then Result.extend (game.south_pacific_ocean) Result.extend (game.indonesia) if not is_opposed (game.indonesia) then Result.extend (game.japanese_islands) Result.extend (game.marianas_islands) end if not is_opposed (game.south_pacific_ocean) then Result.extend (game.marianas_islands) Result.extend (game.coral_sea) Result.extend (game.us_mandate) Result.extend (game.marshall_islands) end elseif home_port = game.australia or home_port = game.port_moresby then Result.extend (game.indian_ocean) Result.extend (game.coral_sea) if not is_opposed (game.indian_ocean) then Result.extend (game.bay_of_bengal) Result.extend (game.indonesia) end if not is_opposed (game.coral_sea) then Result.extend (game.south_pacific_ocean) Result.extend (game.us_mandate) end elseif home_port = game.guadalcanal then Result.extend (game.coral_sea) Result.extend (game.south_pacific_ocean) if not is_opposed (game.coral_sea) then Result.extend (game.indian_ocean) Result.extend (game.us_mandate) end if not is_opposed (game.south_pacific_ocean) then Result.extend (game.indonesia) Result.extend (game.marianas_islands) Result.extend (game.marshall_islands) Result.extend (game.us_mandate) end elseif home_port = game.new_hebrides then Result.extend (game.coral_sea) Result.extend (game.us_mandate) if not is_opposed (game.coral_sea) then Result.extend (game.indian_ocean) Result.extend (game.south_pacific_ocean) end if not is_opposed (game.us_mandate) then Result.extend (game.south_pacific_ocean) Result.extend (game.marshall_islands) Result.extend (game.hawaiian_islands) end elseif home_port = game.samoa then Result.extend (game.us_mandate) if not is_opposed (game.us_mandate) then Result.extend (game.coral_sea) Result.extend (game.south_pacific_ocean) Result.extend (game.marshall_islands) Result.extend (game.hawaiian_islands) end elseif home_port = game.johnston_island or home_port = game.pearl_harbor then Result.extend (game.hawaiian_islands) if not not is_opposed (game.hawaiian_Islands) then Result.extend (game.us_mandate) Result.extend (game.marshall_islands) Result.extend (game.central_pacific_ocean) Result.extend (game.north_pacific_ocean) end elseif home_port = game.kwajalein or home_port = game.maloelap then Result.extend (game.marshall_islands) if not is_opposed (game.marshall_islands) then Result.extend (game.south_pacific_ocean) Result.extend (game.us_mandate) Result.extend (game.hawaiian_islands) Result.extend (game.central_pacific_ocean) Result.extend (game.marianas_islands) end elseif home_port = game.truk then Result.extend (game.south_pacific_ocean) Result.extend (game.marshall_islands) Result.extend (game.marianas_islands) if not is_opposed (game.south_pacific_ocean) then Result.extend (game.indonesia) Result.extend (game.coral_sea) Result.extend (game.us_mandate) end if not is_opposed (game.marshall_islands) then Result.extend (game.us_mandate) Result.extend (game.hawaiian_islands) Result.extend (game.central_pacific_ocean) end if not is_opposed (game.marianas_islands) then Result.extend (game.indonesia) Result.extend (game.japanese_islands) Result.extend (game.central_pacific_ocean) end elseif home_port = game.saipan then Result.extend (game.marianas_islands) if not is_opposed (game.marianas_islands) then Result.extend (game.japanese_Islands) Result.extend (game.indonesia) Result.extend (game.south_pacific_ocean) Result.extend (game.marshall_islands) Result.extend (game.central_pacific_ocean) end elseif home_port = game.midway then Result.extend (game.central_pacific_ocean) if not is_opposed (game.central_pacific_ocean) then Result.extend (game.japanese_islands) Result.extend (game.marianas_islands) Result.extend (game.marshall_islands) Result.extend (game.hawaiian_islands) Result.extend (game.north_pacific_ocean) Result.extend (game.aleutian_islands) end elseif home_port = game.dutch_harbor then Result.extend (game.north_pacific_ocean) Result.extend (game.aleutian_islands) if not is_opposed (game.north_pacific_ocean) then Result.extend (game.central_pacific_ocean) Result.extend (game.hawaiian_islands) end if not is_opposed (game.aleutian_islands) then Result.extend (game.japanese_islands) Result.extend (game.central_pacific_ocean) end elseif home_port = game.attu then Result.extend (game.aleutian_islands) if not is_opposed (game.aleutian_islands) then Result.extend (game.japanese_islands) Result.extend (game.central_pacific_ocean) Result.extend (game.north_pacific_ocean) end else end end end landable_ports: LINKED_SET [PORT] -- A list containing each {PORT} at which Current can make -- a landing if at the appropriate point in the game local lin: LINEAR [PORT] do create Result.make if attached {SEA_AREA} location as s then lin := s.adjoining_ports from lin.start until lin.exhausted loop if not lin.item.is_enemy_controlled (nationality) then Result.extend (lin.item) end lin.forth end end -- Add all major ports to the set from game.major_ports.start until game.major_ports.after loop if not game.major_ports.item_for_iteration.is_enemy_controlled (nationality) then Result.extend (game.major_ports.item_for_iteration) end game.major_ports.forth end end arrivable_locations: LINKED_LIST [LOCATION] -- The possible locations to which Current can move when -- coming into [or back into] the game local sop: VITP_SEQUENCE_OF_PLAY do create Result.make sop := game.sequence_of_play if arrival_turn = sop.turn or returning_turn = sop.turn then if nationality = sop.nationality then if nationality = game.japanese then end end end end arrival_location: LOCATION -- The port or sea area at which this unit may enter the game do if nationality = game.japanese and game.yokosuka_navy_yard.nationality = game.japanese then Result := game.yokosuka_navy_yard elseif nationality = game.us then if game.pearl_harbor.nationality = game.us then Result := game.pearl_harbor elseif game.samoa.nationality = game.us then Result := game.samoa else io.put_string ("ATTACK_UNIT.arrival_location -- put it on US_chart. %N") Result := game.still_in_box end elseif nationality = game.british and game.ceylon.nationality = game.us then Result := game.ceylon elseif nationality = game.australian then Result := game.australia else Result := game.still_in_box check should_not_happpen: False -- because all nationalities have been checked end end end arrival_port: like home_port -- The port to which Current is assigned when it comes into -- the game during a reinforcement action. do Result := game.default_port if nationality = game.japanese and game.yokosuka_navy_yard.nationality = game.japanese then Result := game.yokosuka_navy_yard elseif nationality = game.us then if game.pearl_harbor.nationality = game.us then Result := game.pearl_harbor else Result := game.samoa end elseif nationality = game.british then if Current = game.victorious and game.pearl_harbor.nationality = game.us then Result := game.pearl_harbor elseif game.ceylon.nationality = game.us then Result := game.ceylon end elseif nationality = game.australian then Result := game.australia else check should_not_happpen: False -- because all nationalities have been checked end end end arrival_position: like position -- The location (latitude/longitude-like coordinates) where Current will enter the game do -- The following measurements in millimeters were taken from the game board if arrival_location = game.Yokosuka_navy_yard then Result := [300, 140] elseif arrival_location = game.Pearl_Harbor then Result := [700, 330] elseif arrival_location = game.Samoa then Result := [570, 480] elseif arrival_location = game.Ceylon then Result := [185, 15] elseif arrival_location = game.Bay_of_Bengal then Result := [10, 370] elseif arrival_location = game.Indonesia then Result := [130, 350] elseif arrival_location = game.Philippines then Result := [210, 270] elseif arrival_location = game.Australia then Result := [240, 470] elseif arrival_location = game.Singapore then Result := [90, 280] elseif arrival_location = game.Coral_sea then Result := [370, 520] elseif arrival_location = game.US_mandate then Result := [500, 500] elseif arrival_location = game.Hawaiian_islands then Result := [570, 380] else -- Return its Current position Result := [position.longitude, position.latitude] end end feature -- Element change set_location (a_location: LOCATION) -- Move all ships in `task_force' to `a_location' require is_valid_move: is_valid_move (a_location) local u: ATTACK_UNIT do io.put_string ("ATTACK_UNIT.set_location: " + name.out + " to " + a_location.name + "%N") from task_force.start until task_force.is_after loop u := task_force.item u.set_location_internal (a_location) task_force.forth end ensure location_set: location = a_location location_set_for_all: end set_home_port (a_port: PORT) -- Change the unit's `home_port' require is_valid_base: is_valid_unit_move (a_port) do home_port := a_port end set_returning_turn (a_turn: INTEGER) -- Set the turn on which Current can reenter the game require valid_turn: a_turn >= 3 and a_turn <= 9 do returning_turn := a_turn end set_location_internal (a_location: LOCATION) -- Used internally to bypass referential invariant checking do if location /= a_location then is_stable := False location.prune (Current) location := a_location if not a_location.has (Current) then a_location.put (Current) end is_stable := True end end set_target (a_target: ATTACK_UNIT) -- Get ready to attack `a_target' require same_locations: location = a_target.location do target_imp := a_target end remove_target -- Remove any target from Current sights do target_imp := Void end feature -- Query is_valid_move (a_location: LOCATION): BOOLEAN -- Can this {TASK_FORCE} (all units) move to `a_location'? do Result := True from task_force.start until task_force.is_after or not Result loop Result := task_force.item.is_valid_unit_move (a_location) task_force.forth end end is_valid_unit_move (a_location: LOCATION): BOOLEAN -- Can Current (regardless of any other units that -- may be in the `task_force') move to `a_location'? do io.put_string ("{ATTACK_UNIT}.is_valid_unit_move: fix to for restricted port %N") Result := True end feature -- Access position: VITP_POSITION -- The position in millimeters (east/west and up/down) from the -- top-left of the [logical] VITP world. That is, the position -- of an attack unit is relative to the top-left corner of the -- game board which is at point (0, 0). unit_size: INTEGER -- The size of Current (square). -- Assume it is `Ship_size' and redefine for {AIR_UNIT} and -- for {AMPHIBIOUS_UNIT}. once Result := game.initial_ship_size end corners: ARRAY [VITP_POSITION] -- The four corner points of Current (square ships) calculated -- from Current's location and `unit_size', starting at the top/ -- left and going clockwise. local p: VITP_POSITION h: INTEGER do h := unit_size // 2 create Result.make_filled (create {VITP_POSITION}, 1, 4) create p.set_xy (position.longitude - h, position.latitude - h) Result.put (p, 1) create p.set_xy (position.longitude + h, position.latitude - h) Result.put (p, 2) create p.set_xy (position.longitude + unit_size, position.latitude + h) Result.put (p, 3) create p.set_xy (position.longitude - unit_size, position.latitude + unit_size) Result.put (p, 4) end feature -- Element change set_position (a_position: like position) -- Change the `position' of Current [and all units in `task_force'] require position_exists: a_position /= Void is_valid_position: not is_incompatible_position (a_position) local u: ATTACK_UNIT do from task_force.start until task_force.is_after loop u := task_force.item u.internal_set_position (a_position) task_force.forth end ensure position_set: position ~ a_position end feature -- Query -- is_valid_position (a_position: VITP_POSITION): BOOLEAN -- -- Is `a_position' valid? Yes if the position is on the board/table, -- -- (garanteed by invariant of {VITP_POSITION}), not on an enemy unit, -- -- and not on a unit of the wrong type (i.e. a submarine cannot join -- -- a task force.) -- do -- Result := not is_on_incompatible_unit (a_position) -- end is_incompatible_position (a_position: VITP_POSITION): BOOLEAN -- Yes if repositioning Current to `a_position' would cause Current -- to overlap a unit that is incompatible for a `join_force' (e.g. -- on a submarine or on an enemy)? deferred end contains_position (a_position: VITP_POSITION): BOOLEAN -- Is `a_position' on or in Current? -- This feature uses a ray-casting algorithm which determines if the -- number of edge crossings made by a ray to the right is odd (inside) -- or even (outside). local pts: like corners i, j: INTEGER do pts := corners from i := 1 j := 4 until i > 4 loop -- Get integer values so algorithm can work. -- if ( ((pts[i] >= a_position) /= (pts[j] >= a_position)) and -- (a_position <= (pts[j] - pts[i]) * -- (a_position - pts[i]) // -- (pts[j] - pts[i]) + pts[i]) ) then -- -- Invert Result every time an edge is crossed. -- Result := not Result -- end j := i i := i + 1 end end overlaps (a_other: ATTACK_UNIT): BOOLEAN -- Does Current occupy any space occupied by a_other local pts: like corners i: INTEGER do if Current /= a_other then pts := corners from i := 1 until i > pts.count or Result loop Result := a_other.contains_position (pts[i]) i := i + 1 end -- Check the other way around if not Result then pts := a_other.corners from i := 1 until i > pts.count or Result loop Result := contains_position (pts[i]) i := i + 1 end end end end -- is_same_power (a_nationality: NATIONALITY): BOOLEAN -- -- Is Current the same power (Axis or Allied) as `a_natinality'? -- do -- Result := (nationality.is_allied and a_nationality.is_allied) or else -- (not nationality.is_allied and not a_nationality.is_allied) -- end feature -- Basic operations join_force (a_other: ATTACK_UNIT) -- Join forces with `a_other' as a single `task_force' require not_submarine: not attached {SUBMARINE} a_other and not attached {SUBMARINE} Current lba_implication: attached {AIR_UNIT} task_force.first implies attached {AIR_UNIT} a_other other_lba_implication: attached {AIR_UNIT} a_other implies attached {AIR_UNIT} task_force.first not_lba_implication: not attached {AIR_UNIT} task_force.first implies not attached {AIR_UNIT} a_other not_other_lba_implication: not attached {AIR_UNIT} a_other implies not attached {AIR_UNIT} task_force.first not_same_units: not (a_other = Current) not_same_task_forces: (is_task_force and a_other.is_task_force) implies not (task_force = a_other.task_force) not_opposing_sides: not is_opposed (a_other) same_location: location = a_other.location local u: ATTACK_UNIT pos: VITP_POSITION do is_stable := False -- Put all units into `a_other's `task_force' pos := a_other.position from task_force.start until task_force.is_after loop u := task_force.item -- u.position.set_xy (pos.longitude, pos.latitude) a_other.task_force.extend (u) task_force.forth end -- Remove all the units from Current's `task_force' task_force.wipe_out -- Make to two tasks forces the same one set_task_force (a_other.task_force) is_stable := True ensure same_task_forces: task_force = a_other.task_force has_multiple_units: task_force.count >= 2 end leave_force -- Remove Current from the `task_force' to which it belongs, but only -- if there are other ships in the force, and put it in its own. require is_in_task_force: is_task_force local u: ATTACK_UNIT do task_force.prune (Current) create task_force.make (game) task_force.extend (Current) ensure not_in_force: not is_task_force end feature -- Status report is_task_force: BOOLEAN -- Is this unit part of a task force? do Result := task_force.count > 1 ensure result_implies_in_force: task_force.has (Current) result_implies_others: Result implies task_force.count >= 2 end is_in_game: BOOLEAN -- Is this unit in the game? (I.e. not sunk, not still to enter) do Result := is_at_sea or is_in_port or location = game.uncommitted_japanese_location or location = game.uncommitted_allied_location end is_at_sea: BOOLEAN -- Is this unit at sea? do Result := attached {SEA_AREA} location end is_in_port: BOOLEAN -- Is this unit in port? do Result := attached {PORT} location end is_movable: BOOLEAN -- Can Current move (to sea or back to port) at -- this time in the game? local u: ATTACK_UNIT do Result := true from task_force.start until task_force.is_after or not Result loop u := task_force.item Result := u.internal_is_movable task_force.forth end end internal_is_movable: BOOLEAN -- Can Current move (not the whole `task_force') move at this time? local sop: VITP_SEQUENCE_OF_PLAY do sop := game.sequence_of_play print ("ATTACK_UNIT.internal_is_movable: %N") print (" sop.is_allied_player = " + sop.is_allied_player.out + "%N") print (" " + name + ".is_allied = " + is_allied.out + "%N") print (" sop.is_japaneses_player = " + sop.is_japanese_player.out + "%N") print (" " + name + ".is_japanese = " + is_japanese.out + "%N") print (" sop.is_patrolling_step = " + sop.is_patrolling_step.out + "%N") print (" " + name + ".is_patrolling = " + is_patrolling.out + "%N") Result := ( (sop.is_allied_player and is_allied) or (sop.is_japanese_player and is_japanese)) and then ( (sop.is_reinforcement_step and is_returning_unit) or -- (sop.is_removing_sunk_units_phase and is_sunk) or -- (sop.is_returning_disabled_units_stage and is_disabled) or -- (sop.is_removing_sunk_units_phase and is_sunk) or -- (sop.is_returning_to_port_stage and is_at_sea and not is_sunk) or (sop.is_patrolling_step and is_patrolling) or (sop.is_raiding_step and is_raiding)) print (" Result = " + Result.out + "%N") end is_stable: BOOLEAN -- Set to false when pruning and adding for invariant checking -- of referential integrity between units and locations is_major_power: BOOLEAN -- Is Current's `nationality' one of Japanese or US? do Result := nationality = game.japanese or nationality = game.us end is_sunk: BOOLEAN -- Has this unit been sunk? deferred end is_bottomed: BOOLEAN -- Is unit in port with too much damage to sail? -- Default is Fasle, so redefine for {SHIP} do Result := False ensure implication: Result implies is_in_port end is_disabled: BOOLEAN -- Is the unit disabled? is_returning_unit: BOOLEAN -- Is the unit returning on this turn? do Result := returning_turn = game.sequence_of_play.turn end is_patrollable: BOOLEAN -- Can this unit be a patroller for area control purposes? deferred end is_raidable: BOOLEAN -- Can this unit be a raider? deferred end is_patrolling: BOOLEAN -- Is this unit a patroller (as opposed to a raider)? deferred end is_raiding: BOOLEAN -- Is this unit a raider? deferred end feature -- Status setting set_disabled -- Mark Current as `is_disabled' do is_disabled := True end set_not_disabled -- Mark Current as not `is_disabled' do is_disabled := False end feature {ATTACK_UNIT} -- Implementation internal_set_position (a_position: VITP_POSITION) -- Change the `position' of [only] Current require position_exists: a_position /= Void do position.set_xy (a_position.longitude, a_position.latitude) end feature {ATTACK_UNIT} -- Implementation feature -- Comparison is_less alias "<" (other: like Current): BOOLEAN -- Is current object less than `other'? do -- Weight the attack, defense, speed factors and compare result Result := (relative_value > other.relative_value) or else (relative_value = other.relative_value and then name < other.name) -- Result := name < other.name end feature {NONE} -- Implementation (weighting factors for `relative_value') gunnery_weight: INTEGER = 10 defense_weight: INTEGER = 1 speed_weight: INTEGER = 1 airstrike_weight: INTEGER = 10 bonus_weight: INTEGER = 2 feature {ATTACK_UNIT} -- Implementation set_task_force (a_force: like task_force) -- Set `task_force' to `a_force' require has_current: a_force.has (Current) do task_force.prune (Current) task_force := a_force ensure task_force_assigned: task_force = a_force in_task_force: task_force.has (Current) end remove_task_force -- Remove Current from `task_force' and put it in its own `task_force' do task_force.prune (Current) create task_force.make (game) end feature {NONE} -- Implementation (invariant routines) same_location_for_all: BOOLEAN -- Do all the unit have the same `location'? local c: CURSOR do c := task_force.cursor Result := true if is_task_force then from task_force.start until task_force.is_after loop Result := task_force.item.location = location task_force.forth end end task_force.go_to (c) end same_position_for_all: BOOLEAN -- Do all the units have the same `location'? local c: CURSOR do c := task_force.cursor Result := true if is_task_force then from task_force.start until task_force.is_after loop Result := task_force.item.position ~ position task_force.forth end end task_force.go_to (c) end feature {NONE} -- Implementation target_imp: detachable ATTACK_UNIT -- The unit if any that Current is set to attack invariant location_exists: location /= Void task_force_exists: task_force /= Void -- longitude_big_enough: position.longitude >= {POSITION_CONSTANTS}.Minimum_longitude -- longitude_small_enough: position.longitude <= {POSITION_CONSTANTS}.Maximum_longitude -- latitude_big_enough: position.latitude >= {POSITION_CONSTANTS}.Minimum_latitude -- latitude_small_enough: position.latitude <= {POSITION_CONSTANTS}.Maximum_latitude contains_itself: task_force.has (Current) valid_arrival_turn: arrival_turn >= 1 and arrival_turn <= 9 valid_gunnery_factor: gunnery_factor >= 0 and gunnery_factor <= 9 valid_defense_factor: defense_factor >= 0 and defense_factor <= 9 valid_speed_factor: speed_factor >= 3 and speed_factor <= 9 -- contains_current: task_force.first = Current -- contains_only_current: task_force.count = 1 location_integrity: is_stable implies location.has (Current) task_force_integrity: (is_stable and then is_task_force and then task_force.is_stable) implies task_force.has (Current) -- task_force_location_implication: is_stable implies (is_task_force implies same_location_for_all) -- task_force_position_implication: is_stable implies (is_task_force implies same_position_for_all) end