note description: "[ Root class for all the locations (ports, sea-areas, bases) in VITP. ]" author: "Jimmy J. Johnson" deferred class LOCATION inherit VITP_ITEM redefine make end feature {NONE} -- Initialization make (a_game: like game) -- Initialize Current do Precursor (a_game) -- create defining_position create units_imp.make is_stable := True -- defining_cell := game. end feature -- Access defining_position: TUPLE [x, y: INTEGER_32] -- The x- and y-coordinate (in millimeters) of Current's -- position relative to the top-left corner of the board. deferred end defining_cell: VITP_CELL -- The "central" cell for Current, around which its -- positioning `grid' is built. local x, y: INTEGER_32 once x := ((defining_position.x + game.board_left) / game.cell_size).truncated_to_integer + 1 y := ((defining_position.y + game.board_top) / game.cell_size).truncated_to_integer + 1 Result := game.cell (x, y) end units: LINKED_SET [like unit_anchor] -- Copy of the list of units in current. -- Why do I have this feature? do print ("LOCATION.units: why have this feature? %N"); Result := units_imp.twin end japanese_units: LINKED_SET [like unit_anchor] -- All the japanese units in Current do create Result.make from units_imp.start until units_imp.exhausted loop if units_imp.item.nationality = game.Japanese then Result.extend (units_imp.item) end units_imp.forth end end allied_units: LINKED_SET [like unit_anchor] -- All the allied units in Current do create Result.make from units_imp.start until units_imp.exhausted loop if units_imp.item.nationality /= game.Japanese then Result.extend (units_imp.item) end units_imp.forth end end adjacent_sea_areas: LINEAR [SEA_AREA] -- A list of all sea areas that touch this location deferred end feature -- Status report is_port: BOOLEAN -- Is the location a {PORT}? do Result := Current.conforms_to ({PORT}) end is_sea_area: BOOLEAN -- Is the location a {SEA_AREA}? do Result := Current.conforms_to ({SEA_AREA}) end feature -- Basic operations put (a_unit: like unit_anchor) -- Ensure `a_unit' is in Current require unit_exists: a_unit /= Void -- valid_move: a_unit.is_valid_move (Current) do is_stable := False units_imp.put (a_unit) if a_unit.location /= Current then a_unit.set_location (Current) end is_stable := True ensure has_unit: has (a_unit) location_integrity: a_unit.location = Current end prune (a_unit: like unit_anchor) -- Ensure `a_unit' is NOT in Current require unit_exists: a_unit /= Void do is_stable := False if has (a_unit) then units_imp.prune (a_unit) end is_stable := True ensure not_has_unit: not has (a_unit) end feature -- Query -- friendly_ports (a_nationality: NATIONALITY): LINKED_SET [PORT] -- -- Of the `adjoining_ports' the ones that are friendly to `a_nationality' -- local -- p: like adjoining_ports -- do -- create Result.make -- from ports.start -- until ports.exhausted -- loop -- if not ports.item.is_enemy_controlled (a_nationality) then -- Result.extend (ports.item) -- end -- ports.forth -- end -- end distance_to (other: LOCATION): INTEGER -- The distance between Current and `other' do io.put_string ("LOCATION.distance_to: Fix me - move functionality to VITP_GAME? %N") Result := {INTEGER_32}.max_value end is_enemy_controlled (a_nationality: like game.japanese): BOOLEAN -- Is the location controlled by the other side? do Result := (game.is_allied_nationality (a_nationality) and not game.is_allied_nationality (nationality)) or (not game.is_allied_nationality (a_nationality) and game.is_allied_nationality (nationality)) end has (a_unit: like unit_anchor): BOOLEAN -- Does Current contain `a_unit'? require unit_exists: a_unit /= Void do Result := units_imp.has (a_unit) end has_allied: BOOLEAN -- Does this location have any allied game piece here? local u: like unit_anchor do from units_imp.start until Result or else units_imp.after loop u := units_imp.item Result := game.is_allied_nationality (u.nationality) units_imp.forth end end has_japanese: BOOLEAN -- Does this location have any japanese game piece here? local u: like unit_anchor do from units_imp.start until Result or else units_imp.after loop u := units_imp.item Result := not game.is_allied_nationality (u.nationality) units_imp.forth end end has_japanese_patroller: BOOLEAN -- Does this location contain at least one Japanese patroller? local u: like unit_anchor do from units_imp.start until Result or else units_imp.after loop u := units_imp.item Result := u.is_patrolling and then not game.is_allied_nationality (u.nationality) units_imp.forth end end has_allied_patroller: BOOLEAN -- Does this location contain at least one Japanese patroller? local u: like unit_anchor do from units_imp.start until Result or else units_imp.after loop u := units_imp.item Result := u.is_patrolling and then game.is_allied_nationality (u.nationality) units_imp.forth end end has_japanese_air_raiders: BOOLEAN -- Does Current contain any Japanese carriers? -- (Carriers are the only units that can air raid.) local set: like japanese_units do set := japanese_units from set.start until set.exhausted or Result loop Result := attached {SHIP} set.item as s and then s.airstrike_factor > 0 set.forth end end has_allied_air_raiders: BOOLEAN -- Does Current contain any Japanese carriers? -- (Carriers are the only units that can air raid.) local set: like allied_units do set := allied_units from set.start until set.exhausted or Result loop Result := attached {SHIP} set.item as s and then s.airstrike_factor > 0 set.forth end end has_allied_amphibious: BOOLEAN -- Does Current contain any Allied amphibious units? local set: like allied_units do set := allied_units from set.start until set.exhausted or Result loop Result := attached {AMPHIBIOUS_UNIT} set.item set.forth end end has_japanese_amphibious: BOOLEAN -- Does Current contain any Japanese amphibious units? local set: like japanese_units do set := japanese_units from set.start until set.exhausted or Result loop Result := attached {AMPHIBIOUS_UNIT} set.item set.forth end end feature {NONE} -- Implementation units_imp: LINKED_SET [like unit_anchor] -- The units that are in this location has_invalid_unit: BOOLEAN -- Does Current contain a unit that does not refer back to Current? -- For invariant checking -- Should always be false require call_only_when_stable: is_stable do from units_imp.start until Result or units_imp.exhausted loop Result := units_imp.item.location /= Current units_imp.forth end end is_stable: BOOLEAN -- Set to false when pruning and adding units for invariant checking -- of referential integrity between units and locations feature {NONE} -- Anchors (for covariant redefinitions) unit_anchor: ATTACK_UNIT -- Anchor for features using units. -- Not to be called; just used to anchor types. -- Declared as a feature to avoid adding an attribute. require not_callable: False do check do_not_call: False then -- Because give no info; simply used as anchor. end end invariant valid_controller: nationality = game.japanese or nationality = game.us or nationality = game.nobody all_units_imp_refer_to_current: is_stable implies not has_invalid_unit end