Finished testing and docs for now. Time for new features!

This commit is contained in:
2025-10-02 23:58:24 -06:00
parent 279658f3e5
commit b8f54b44a3
16 changed files with 316 additions and 66 deletions
+1
View File
@@ -4,3 +4,4 @@
**/logs **/logs
**/*tmp* **/*tmp*
**/coverage **/coverage
game/spec/examples.txt
+2 -1
View File
@@ -24,7 +24,8 @@ end
namespace :doc do namespace :doc do
desc 'Create the YARD documentation for the project' desc 'Create the YARD documentation for the project'
task :yard do task :yard do
res = sh 'yard doc *.rb' res = sh 'yard doc *.rb --list-undoc'
sh 'yard stats *.rb --list-undoc'
end end
desc 'Create code coverage' desc 'Create code coverage'
+17 -17
View File
@@ -1,17 +1,17 @@
# Nathan Hinton 2 Oct 2025 # BROKEN :( # Nathan Hinton 2 Oct 2025
# Does not work sadly... # BROKEN :( # Does not work sadly...
# BROKEN :(
require 'logger' # BROKEN :( require 'logger'
# BROKEN :(
module Log # BROKEN :( module Log
@log = Logger.new('game.log') # BROKEN :( @log = Logger.new('game.log')
@log.level = Logger::INFO # BROKEN :( @log.level = Logger::INFO
# BROKEN :(
def self.logger # BROKEN :( def self.logger
@logger # BROKEN :( @logger
end # BROKEN :( end
# BROKEN :(
def logger # BROKEN :( def logger
Log.logger # BROKEN :( Log.logger
end # BROKEN :( end
end # BROKEN :( end
+1 -1
View File
@@ -12,7 +12,7 @@ class Planet
def initialize(random) def initialize(random)
@random = random @random = random
@prod_rate = @random.rand @prod_rate = @random.rand
@resource = PLANET_PRODUCTION_RESOURCES[(@random.rand * PLANET_PRODUCTION_RESOURCES.length).floor] @resource = PLANET_PRODUCTION_RESOURCES.sample(random: @random)
@owner = nil @owner = nil
end end
+5
View File
@@ -41,6 +41,11 @@ class Position
return "(#{@x_pos}, #{y_pos})" return "(#{@x_pos}, #{y_pos})"
end end
# Custom comparison. We need to check the the point is the same, not the
# identity.
#
# @param other [Positon] The position to compare with
# @return [Boolean] If they are in the same position as each other.
def ==(other) def ==(other)
return other.x_pos == @x_pos && other.y_pos == @y_pos return other.x_pos == @x_pos && other.y_pos == @y_pos
end end
+4 -1
View File
@@ -3,9 +3,12 @@
# This class will be the container for ships. For now they are all the same # This class will be the container for ships. For now they are all the same
class Ship class Ship
def initialize(x_pos, y_pos) attr_reader :owner
def initialize(x_pos, y_pos, owner)
@position = [x_pos, y_pos] @position = [x_pos, y_pos]
@speed = 0.1 @speed = 0.1
@owner = owner
end end
# Called every game tick # Called every game tick
+157
View File
@@ -1,2 +1,159 @@
# frozen_string_literal: true # frozen_string_literal: true
# Nathan Hinton 2 Oct 2025 # Nathan Hinton 2 Oct 2025
# This is for testing the API that the clients can use.
# Most of the api is here as it relates to interacting with the universe
require './universe'
require './player'
require './position'
require './ship'
RSpec.describe 'API' do
# Universe setup
let(:name) { 'Test Universe' }
let(:universe_size) { 3 }
let(:seed) { 12345 }
subject(:universe) do
Universe.new(
name,
universe_size: universe_size,
seed: seed,
create_chances: { planet: 1 } # force a planet at every valid spot
)
end
before(:each) do
universe.create_universe
end
# Player setup
let(:player_1) { Player.new('test player 01') }
let(:player_2) { Player.new('test player 02') }
# Positions setup
let(:center_position) { Position.new(5, 3) }
describe 'UNIVERSE API' do
describe '#get_position' do
it 'returns a position in the universe' do
expect(universe.get_position(player_1, Position.new(0, 0))).to be nil
expect(universe.get_position(player_1, Position.new(3, 5))).to be_a(Planet)
expect(universe.get_position(player_1, center_position)).to be_a(Star)
end
end # describe Universe#get_position
end # describe 'UNIVERSE API'
describe 'SHIPS API' do
describe '@create_ship' do
it 'returns false when the player is invalid' do
expect(universe.create_ship(player_1, Position.new(3, 5))).to eq false
end
end # describe '@create_ship'
describe '@move_ship' do
it 'returns false when the player is invalid' do
expect(universe.move_ship(player_1, Ship.new(2, 4, player_1), Position.new(3, 5))).to eq false
end
end # describe '@move_ship'
describe '@remove_ship' do
it 'returns false when the player is invalid' do
expect(universe.remove_ship(player_1, Position.new(3, 5))).to eq false
end
end # describe '@remove_ship'
end # describe 'SHIPS API'
describe 'PLANETS API' do
describe '@remove_planet' do
end # describe '@remove_planet'
end # describe 'PLANETS API'
describe 'PLAYER API' do
describe '#add_player' do
it 'adds with free planets' do
expect(universe.add_player(player_1)).to be(true)
expect(universe.instance_variable_get(:@player_list)).to eq [player_1]
end
it 'fails to add when all planets are occopuied' do
# Make all the planets owned by player_2
universe.planets.each do |planet|
planet.change_owner(player_2)
end
expect(universe.add_player(player_1)).to be(false)
expect(universe.instance_variable_get(:@player_list)).to eq []
end
it 'raises an error if a planet can not be taken' do
# This is an exceptional case. This is actually proper behavior when
# not trying to deal out planets.
end
end # describe 'add_player'
describe '#remove_player' do
it 'can remove an existing player' do
universe.add_player(player_1)
expect(universe.remove_player(player_1)).to eq true
expect(universe.remove_player(player_2)).to eq true
expect(universe.instance_variable_get(:@player_list)).to eq []
end
it 'can remove a non existing player' do
expect(universe.remove_player(player_2)).to eq true
end
end # describe 'remove_player'
describe '#validate_player' do
it 'returns true when a player is valid' do
universe.add_player(player_1)
expect(universe.validate_player(player_1)).to eq true
end
it 'returns false when the player is not in the player list' do
expect(universe.validate_player(player_2)).to eq false
end
end # describe 'validate_player'
describe '#get_player_ships' do
it 'lists all ships owned by a player' do
universe.add_player(player_1)
universe.add_player(player_2)
expect(universe.get_player_ships(player_1)).to eq []
ship_1 = Ship.new(2, 4, player_1)
ship_2 = Ship.new(2, 4, player_2)
ship_3 = Ship.new(3, 5, player_1)
universe.instance_variable_set(:@ship_list, [ship_1, ship_2, ship_3])
expect(universe.get_player_ships(player_1)).to eq [ship_1, ship_3]
expect(universe.get_player_ships(player_2)).to eq [ship_2]
end
it 'returns an empty list when a player that is not registered gets ships' do
ship_2 = Ship.new(2, 4, player_2)
universe.instance_variable_set(:@ship_list, [ship_2])
expect(universe.get_player_ships(player_2)).to eq []
end
end # describe 'get_player_ships'
describe '#get_player_planets' do
it 'returns the planets owned by a player' do
universe.add_player(player_1)
expect(universe.get_player_planets(player_2)).to eq []
expect(universe.get_player_planets(player_1).length).to eq 1
end
it 'returns an empty list for a unregistered player' do
expect(universe.get_player_planets(player_2)).to eq []
end
end # describe 'get_player_planets'
end # describe 'PLAYER API'
end
+5 -5
View File
@@ -13,15 +13,15 @@ RSpec.describe Planet do
describe '#initialize' do describe '#initialize' do
it 'stores the random off' do it 'stores the random off' do
expect(planet.instance_variable_get(:@random)).to eq(random) expect(planet.instance_variable_get(:@random)).to eq random
end end
it 'creates a production rate' do it 'creates a production rate' do
expect(planet.instance_variable_get(:@prod_rate)).to eq(Random.new(seed).rand) expect(planet.instance_variable_get(:@prod_rate)).to eq Random.new(seed).rand
end end
it 'sets a resource' do it 'sets a resource' do
expect(planet.instance_variable_get(:@resource)).to eq(PLANET_PRODUCTION_RESOURCES[(Random.new(seed).rand * PLANET_PRODUCTION_RESOURCES.length).floor]) expect(planet.instance_variable_get(:@resource)).to eq PLANET_PRODUCTION_RESOURCES[(Random.new(seed).rand * PLANET_PRODUCTION_RESOURCES.length).floor]
end end
it 'has a nil owner' do it 'has a nil owner' do
@@ -31,13 +31,13 @@ RSpec.describe Planet do
describe '#change_owner' do describe '#change_owner' do
it 'allows an ownership change when the current owner is nil' do it 'allows an ownership change when the current owner is nil' do
expect(planet.change_owner(player_1)).to eq(true) expect(planet.change_owner(player_1)).to eq true
expect(planet.instance_variable_get(:@owner)).to eq player_1 expect(planet.instance_variable_get(:@owner)).to eq player_1
end end
it 'does not change when already owned' do it 'does not change when already owned' do
planet.change_owner(player_2) planet.change_owner(player_2)
expect(planet.change_owner(player_1)).to eq(false) expect(planet.change_owner(player_1)).to eq false
expect(planet.instance_variable_get(:@owner)).to eq player_2 expect(planet.instance_variable_get(:@owner)).to eq player_2
end end
end end
+7 -7
View File
@@ -10,8 +10,8 @@ RSpec.describe Position do
context 'with two arguments' do context 'with two arguments' do
it 'stores the coordinates when the sum is even' do it 'stores the coordinates when the sum is even' do
pos = Position.new(*even_pair) pos = Position.new(*even_pair)
expect(pos.x_pos).to eq(even_pair[0]) expect(pos.x_pos).to eq even_pair[0]
expect(pos.y_pos).to eq(even_pair[1]) expect(pos.y_pos).to eq even_pair[1]
end end
it 'raises ArgumentError when the sum is odd' do it 'raises ArgumentError when the sum is odd' do
@@ -43,30 +43,30 @@ RSpec.describe Position do
describe '#two_d_cartesian' do describe '#two_d_cartesian' do
it 'returns the original (x, y) pair' do it 'returns the original (x, y) pair' do
pos = Position.new(*even_pair) pos = Position.new(*even_pair)
expect(pos.two_d_cartesian).to eq(even_pair) expect(pos.two_d_cartesian).to eq even_pair
end end
end end
describe '#two_d_hexagonal' do describe '#two_d_hexagonal' do
it 'returns an array of nil values for a, b, c' do it 'returns an array of nil values for a, b, c' do
pos = Position.new(*even_pair) pos = Position.new(*even_pair)
expect(pos.two_d_hexagonal).to eq([nil, nil, nil]) expect(pos.two_d_hexagonal).to eq [nil, nil, nil]
end end
end end
describe '#to_s' do describe '#to_s' do
it 'puts out the coordinates' do it 'puts out the coordinates' do
expect(Position.new(*even_pair).to_s).to eq('(4, 6)') expect(Position.new(*even_pair).to_s).to eq '(4, 6)'
end end
end end
describe '#==' do describe '#==' do
it 'returns false when the positions differ' do it 'returns false when the positions differ' do
expect(Position.new(*even_pair) == Position.new(6, 8)).to eq(false) expect(Position.new(*even_pair) == Position.new(6, 8)).to eq false
end end
it 'returns true when the positions are the same' do it 'returns true when the positions are the same' do
expect(Position.new(*even_pair) == Position.new(4, 6)).to eq(true) expect(Position.new(*even_pair) == Position.new(4, 6)).to eq true
end end
end end
end end
+7 -5
View File
@@ -1,17 +1,19 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative '../ship' # <-- adjust to the actual path of ship.rb require './ship'
require './player'
RSpec.describe Ship do RSpec.describe Ship do
let(:ship) { Ship.new(0, 0) } let(:ship) { Ship.new(0, 0, Player.new('test player 01')) }
describe '#initialize' do describe '#initialize' do
it 'stores the given position' do it 'stores the given position' do
expect(ship.instance_variable_get(:@position)).to eq([0, 0]) expect(ship.instance_variable_get(:@position)).to eq [0, 0]
end end
it 'sets the speed to 0.1' do it 'sets the speed to 0.1' do
expect(ship.instance_variable_get(:@speed)).to eq(0.1) expect(ship.instance_variable_get(:@speed)).to eq 0.1
end end
it 'does not set @moving until a direction is chosen' do it 'does not set @moving until a direction is chosen' do
@@ -70,7 +72,7 @@ RSpec.describe Ship do
} }
mapping.each do |dir, expected| mapping.each do |dir, expected|
expect { ship.move_direction(dir) }.not_to raise_error expect { ship.move_direction(dir) }.not_to raise_error
expect(ship.instance_variable_get(:@moving)).to eq(expected) expect(ship.instance_variable_get(:@moving)).to eq expected
end end
end end
+1 -3
View File
@@ -52,7 +52,6 @@ RSpec.configure do |config|
# The settings below are suggested to provide a good initial experience # The settings below are suggested to provide a good initial experience
# with RSpec, but feel free to customize to your heart's content. # with RSpec, but feel free to customize to your heart's content.
=begin
# This allows you to limit a spec run to individual examples or groups # This allows you to limit a spec run to individual examples or groups
# you care about by tagging them with `:focus` metadata. When nothing # you care about by tagging them with `:focus` metadata. When nothing
# is tagged with `:focus`, all examples get run. RSpec also provides # is tagged with `:focus`, all examples get run. RSpec also provides
@@ -87,7 +86,7 @@ RSpec.configure do |config|
# Print the 10 slowest examples and example groups at the # Print the 10 slowest examples and example groups at the
# end of the spec run, to help surface which specs are running # end of the spec run, to help surface which specs are running
# particularly slow. # particularly slow.
config.profile_examples = 10 # config.profile_examples = 10
# Run specs in random order to surface order dependencies. If you find an # Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing # order dependency and want to debug it, you can fix the order by providing
@@ -100,5 +99,4 @@ RSpec.configure do |config|
# test failures related to randomization by passing the same `--seed` value # test failures related to randomization by passing the same `--seed` value
# as the one that triggered the failure. # as the one that triggered the failure.
Kernel.srand config.seed Kernel.srand config.seed
=end
end end
+7
View File
@@ -18,6 +18,13 @@ RSpec.describe UniverseArray do
uni_arr[0][0] = 'hi' uni_arr[0][0] = 'hi'
expect(uni_arr[Position.new(0, 0)]).to eq 'hi' expect(uni_arr[Position.new(0, 0)]).to eq 'hi'
end end
it 'returns nil when access outside universe' do
uni_arr = UniverseArray.new()
uni_arr[3] = []
expect(uni_arr[Position.new(3, 51)]).to eq nil
expect(uni_arr[Position.new(0, 0)]).to eq nil
end
end end
describe '#[]=' do describe '#[]=' do
+20 -16
View File
@@ -24,15 +24,15 @@ RSpec.describe Universe do
describe '#initialize' do describe '#initialize' do
it 'stores all expected instance variables' do it 'stores all expected instance variables' do
expect(universe.name).to eq(name) expect(universe.name).to eq name
expect(universe.instance_variable_get(:@universe_size)).to eq(universe_size) expect(universe.instance_variable_get(:@universe_size)).to eq universe_size
expect(universe.instance_variable_get(:@seed)).to eq(seed) expect(universe.instance_variable_get(:@seed)).to eq seed
end end
it 'creates a deterministic Random object when a seed is given' do it 'creates a deterministic Random object when a seed is given' do
rng = universe.instance_variable_get(:@random) rng = universe.instance_variable_get(:@random)
expect(rng).to be_a(Random) expect(rng).to be_a(Random)
expect(rng.rand(100)).to eq(Random.new(seed).rand(100)) expect(rng.rand(100)).to eq Random.new(seed).rand(100)
end end
it 'initializes the random if no seed is passed in' do it 'initializes the random if no seed is passed in' do
@@ -50,12 +50,12 @@ RSpec.describe Universe do
it 'is symmetric' do it 'is symmetric' do
a = Position.new(0, 0) a = Position.new(0, 0)
b = Position.new(4, 2) b = Position.new(4, 2)
expect(universe.distance(a, b)).to eq(universe.distance(b, a)) expect(universe.distance(a, b)).to eq universe.distance(b, a)
end end
it 'returns 0 when both points are identical' do it 'returns 0 when both points are identical' do
p = Position.new(1, 1) p = Position.new(1, 1)
expect(universe.distance(p, p)).to eq(0) expect(universe.distance(p, p)).to eq 0
end end
it 'correctly computes known hex distances' do it 'correctly computes known hex distances' do
@@ -64,13 +64,13 @@ RSpec.describe Universe do
p2 = Position.new(4, 2) p2 = Position.new(4, 2)
p3 = Position.new(2, 2) p3 = Position.new(2, 2)
# (0,0) to (2,0) → 1 # (0,0) to (2,0) → 1
expect(universe.distance(p0, p1)).to eq(1) expect(universe.distance(p0, p1)).to eq 1
# (0,0) to (4,2) → 3 # (0,0) to (4,2) → 3
expect(universe.distance(p0, p2)).to eq(3) expect(universe.distance(p0, p2)).to eq 3
# (0,0) to (2,2) → 2 # (0,0) to (2,2) → 2
expect(universe.distance(p0, p3)).to eq(2) expect(universe.distance(p0, p3)).to eq 2
end end
end end # describe '#distance'
describe '#map generation' do describe '#map generation' do
it 'creates the expected dimensions' do it 'creates the expected dimensions' do
@@ -80,7 +80,7 @@ RSpec.describe Universe do
# (our stub) and every other entry is nil. # (our stub) and every other entry is nil.
expect(map).to be_a(UniverseArray) expect(map).to be_a(UniverseArray)
# Check how may nodes were created: # Check how may nodes were created:
expect(map.flatten.compact.length).to eq(19) # 1 + 1*6 + 2*6 expect(map.flatten.compact.length).to eq 19 # 1 + 1*6 + 2*6
end end
it 'contains a planet at every valid point when create_chances is 1' do it 'contains a planet at every valid point when create_chances is 1' do
@@ -89,12 +89,16 @@ RSpec.describe Universe do
map.each do |row| map.each do |row|
row.each do |idx| row.each do |idx|
# The indexes are allowed to be nil # The indexes are allowed to be nil
if !idx.nil? if idx.nil?
expect(idx).to be_a(Planet) next # Is allowed to be nil
end end
if idx.is_a? Star
next # Is allowed to be star
end
expect(idx).to be_a(Planet)
end end
end end
end end # describe '#map generation'
it 'is deterministic when the same seed is used' do it 'is deterministic when the same seed is used' do
first_universe = Universe.new( first_universe = Universe.new(
@@ -113,7 +117,7 @@ RSpec.describe Universe do
) )
second_map = second_universe.instance_variable_get(:@universe_map) second_map = second_universe.instance_variable_get(:@universe_map)
expect(first_map).to eq(second_map) expect(first_map).to eq second_map
end end
end end
@@ -140,7 +144,7 @@ RSpec.describe Universe do
describe '#planets' do describe '#planets' do
it 'lists all of the generated planets' do it 'lists all of the generated planets' do
universe.create_universe universe.create_universe
expect(universe.planets.length).to eq(19) expect(universe.planets.length).to eq 18
end end
end end
end end
+8
View File
@@ -0,0 +1,8 @@
# Nathan Hinton Oct 2 2025
# Literally just a class to have something else in space...
class Star
def initialize
end
end
+52 -8
View File
@@ -4,6 +4,7 @@
require 'logger' require 'logger'
require './planet' require './planet'
require './star'
require './position' require './position'
require './universe_array' require './universe_array'
@@ -60,6 +61,7 @@ class Universe
# Setup internal lists: # Setup internal lists:
@player_list = [] @player_list = []
@planet_list = []
@ship_list = [] @ship_list = []
# initizlize RNG # initizlize RNG
@@ -73,6 +75,8 @@ class Universe
end # Initialize end # Initialize
# Create the universe. This will setup all of the planets and a blank slate
# for the universe.
def create_universe() def create_universe()
# Set center of universe # Set center of universe
@center = Position.new(@universe_size + 2, @universe_size) @center = Position.new(@universe_size + 2, @universe_size)
@@ -96,12 +100,17 @@ class Universe
# Skip if it is the center # Skip if it is the center
if position == @center if position == @center
@universe_map[position] = Star.new()
next
end end
# Get what the planet should be: # Get what the planet should be:
spot = nil spot = nil
if @random.rand < @create_chances[:planet] if @random.rand < @create_chances[:planet]
spot = Planet.new(@random) spot = Planet.new(@random)
@planet_list.push(spot)
#else
# spot = ''
end end
@@logger.debug "Creating something at (#{position})" @@logger.debug "Creating something at (#{position})"
@universe_map[position] = spot @universe_map[position] = spot
@@ -119,7 +128,6 @@ class Universe
# @return [Integer] The distance between points in the universe. # @return [Integer] The distance between points in the universe.
def distance(position_a, position_b) def distance(position_a, position_b)
result = 0 # We can just add the abs diff of each direction. result = 0 # We can just add the abs diff of each direction.
require 'byebug';debugger if position_a.nil?
dist_x = (position_b.x_pos - position_a.x_pos).abs dist_x = (position_b.x_pos - position_a.x_pos).abs
dist_y = (position_b.y_pos - position_a.y_pos).abs dist_y = (position_b.y_pos - position_a.y_pos).abs
@@ -176,9 +184,9 @@ class Universe
# Print what we are: # Print what we are:
value = @universe_map[position] value = @universe_map[position]
nextline += ' ' nextline += ' '
if position == @center if value.is_a?(Star)
print 'O' print 'O'
elsif value.class == Planet elsif value.is_a?(Planet)
print 'P' print 'P'
else else
print ' ' print ' '
@@ -262,6 +270,7 @@ class Universe
# @param player [Player] The player who owns the ship # @param player [Player] The player who owns the ship
# @param position [Position] The position that the ship should be created at # @param position [Position] The position that the ship should be created at
def create_ship(player, position) def create_ship(player, position)
return false unless validate_player(player)
end end
# Move a player's ship to a given position # Move a player's ship to a given position
@@ -270,6 +279,15 @@ class Universe
# @param ship [Ship] The ship that should be moved # @param ship [Ship] The ship that should be moved
# @param position [Position] The position the ship should be moved to. # @param position [Position] The position the ship should be moved to.
def move_ship(player, ship, position) def move_ship(player, ship, position)
return false unless validate_player(player)
# Ensure the ship exists before moving it.
end
# Remove a ship from the game
# @param player [Player] The player who owns the ship to be removed
# @param ship [Ship] The ship to be removed
def remove_ship(player, ship)
return false unless validate_player(player)
end end
@@ -301,14 +319,24 @@ class Universe
# #
# @param player [Player] The player who should be added to the universe # @param player [Player] The player who should be added to the universe
def add_player(player) def add_player(player)
@player_list.push(player)
# Give the player a planet # Give the player a planet
free_planets = [] free_planets = []
planets.each do |planet| planets.each do |planet|
free_planets.push(planet) if planet.owner.nil? free_planets.push(planet) if planet.owner.nil?
end end
if free_planets == []
return 'Added player to universe' @@logger.debug 'Failed to find an unoccopuied planet for new player!'
return false
end
home_planet = free_planets.sample(random: @random)
# Can;t figure out how to test this...
# if !home_planet.change_owner(player)
# raise Exception.new('Failed to allocate a new player a home planet!')
# end
home_planet.change_owner(player)
@player_list.push(player)
@@logger.debug "Added player '#{player.name}' with home planet #{home_planet}"
return true
end end
# Remove a player from the list in this universe # Remove a player from the list in this universe
@@ -316,15 +344,30 @@ class Universe
# @param player [Player] The player that should be removed from the player list. # @param player [Player] The player that should be removed from the player list.
def remove_player(player) def remove_player(player)
if @player_list.delete(player).nil? if @player_list.delete(player).nil?
return 'Failed to remove player! Does not exist in this universe!' @@logger.debug 'Failed to remove player! Does not exist in this universe! Returning true anyway though!'
end end
return 'Removed player from universe' @@logger.debug "Removed player '#{player.name}' from universe"
return true
end
# Validates if a player exists and is in a good state in the server
#
# @param player [Player] The player to validate
def validate_player(player)
# check if in player list:
unless @player_list.include?(player)
@@logger.warn "Player '#{player}' Tried to perform an action but is an invalid player!"
return false
end
return true
end end
# Returns a list of ships owned by the player # Returns a list of ships owned by the player
# #
# @param player [Player] The player who wants to get their ships. # @param player [Player] The player who wants to get their ships.
# @return [Array<Ship>]
def get_player_ships(player) def get_player_ships(player)
return [] unless validate_player(player)
result = [] result = []
@ship_list.each do |ship| @ship_list.each do |ship|
if ship.owner == player if ship.owner == player
@@ -338,6 +381,7 @@ class Universe
# #
# @param player [Player] The player who wants to get their planets. # @param player [Player] The player who wants to get their planets.
def get_player_planets(player) def get_player_planets(player)
return [] unless validate_player(player)
result = [] result = []
@planet_list.each do |planet| @planet_list.each do |planet|
if planet.owner == player if planet.owner == player
+22 -2
View File
@@ -1,22 +1,42 @@
# Nathan Hinton 1 Oct 2025 # Nathan Hinton 1 Oct 2025
# Create a custom hash class for the universe. # Create a custom hash class for the universe.
require 'logger'
require './position' require './position'
# This will contain the universe hash inside it. It will allow for array type # This will contain the universe hash inside it. It will allow for array type
# indexing as well as point type indexing # indexing as well as point type indexing
class UniverseArray < Array class UniverseArray < Array
def initialize
end
@@logger = Logger.new('logs/universe.log')
# Custom accessor. This allows us to access either with a position object
# (preferred as it does validation) or direct access.
#
# @param index [Integer, Position] If it is an integer nothing special. If a
# Position it will be intepreted for us into the regular indexint.
# @param rest [Object] Actually, I have no idea why this is here. (copy paste)
# @return Whatever is at that position. Can be anything.
def [](index, *rest) def [](index, *rest)
#require 'byebug';debugger
if index.is_a?(Position) if index.is_a?(Position)
if self[index.y_pos].nil?
@@logger.debug "attempted access outside of known universe!"
return nil
end
return self[index.y_pos][index.x_pos] return self[index.y_pos][index.x_pos]
else else
super super
end end
end end
# Custom writer. This allows us to access either with a position object
# (preferred as it does validation) or direct access.
#
# @param index [Integer, Position] If it is an integer nothing special. If a
# Position it will be intepreted for us into the regular indexint.
# @param rest [Object] This (if intercepted) has the value we should assign
def []=(index, *rest) def []=(index, *rest)
if index.is_a?(Position) if index.is_a?(Position)
return self[index.y_pos][index.x_pos] = rest[0] return self[index.y_pos][index.x_pos] = rest[0]