# Nathan Hinton 1 Oct 2025 require 'logger' require './planet' require './position' require './universe_array' # Universe class. Holds a universe and provides the api for it. Universes are # created on a 2d grid. I would like it to be hexagonal movement type so that # it feels less like a grid and more like a circle. This means that we will # have some interesting point systems. For now I am thinking that we will have # three directions, a, b, c which will corespond to moving along one of the # lines to another system. Here is an ascii art: # # # (0, 0, 1) (0, 1, 0) # \ / # \ / # \ / # (+c) (+b) # \ / # \ / # \ / # (-1, 0, 0) <--- (-a) --- (0, 0, 0) --- (+a) ---> (1, 0, 0) # / \ # / \ # / # (-b) (-c) # / \ # / \ # / \ # (0, -1, 0) (0, 0, -1) # # # This means that we are adding vector together. I do not think that this will # work super well though with a system that is other than 2D. I think that will # be fine. # # After thinking some more I will have the universe class hold everything in # the universe. It will be in charge of holding all of the ships and # planets. Then the Player class will be connected to the ships and planets # that they own/control # # @param name [String] The name of the game # @param universe_size [Integer] Controlls the size of the generated universe. This is a radius from the center point. class Universe # Setup logger for this class: sh 'mkdir -p logs' @@logger = Logger.new('logs/universe.log') def initialize(name, universe_size: 4, create_chances: {planet: 1}, seed: nil) @name = name @universe_size = universe_size @create_chances = create_chances # Setup internal lists: @player_list = [] @ship_list = [] # initizlize RNG if seed.nil? @random = Random.new() @seed = @random.seed else @seed = seed @random = Random.new(@seed) end # Set center of universe @center = Position.new(@universe_size + 2, @universe_size) @@logger.info "Generating Universe '#{@name}' with seed #{@seed}" puts "Center is #{@center}" @universe_map = UniverseArray.new() # Generate the universe. First generate the x values: (0 .. (@universe_size * 2)).each do |y_pos| @universe_map[y_pos] = [] (0 .. (@universe_size * 2 + 2)).each do |x_pos| # Make the grid work right, x is actually skipping every other. x_pos *= 2 x_pos += 1 if y_pos.odd? position = Position.new(x_pos, y_pos) # Skip if the node is too far if distance(@center, position) >= @universe_size next end # Get what the planet should be: spot = nil if @random.rand < @create_chances[:planet] spot = Planet.new(@random) end @@logger.debug "Creating something at (#{position.x_pos} #{position.y_pos})" @universe_map[position.y_pos][position.x_pos] = spot end # Create y points end # Create x points end # Function initialize # Returns the distance between points. This is returned as a number which # indicates how far you have to go to get to a point. This is actually # supurisingly hard... # # @param position_a [Position] A start point in the universe # @param position_b [Position] Another point in the universe # @return [Integer] The distance between points in the universe. def distance(position_a, position_b) result = 0 # We can just add the abs diff of each direction. dist_x = (position_b.x_pos - position_a.x_pos).abs dist_y = (position_b.y_pos - position_a.y_pos).abs # Sanity check, our coordinates should add to be even: if (dist_x + dist_y).odd? raise RangeError.new('When calculating the distance we calculated a non even number. This is not allowed!') end res = (dist_x / 2) + dist_y if dist_x >= dist_y res = (dist_x + dist_y) / 2 end @@logger.debug "Distance: #{position_a} and #{position_b} are #{res} units away" return res end # Function distance # Prints the universe to the screen. def print_universe(simple: false) (0 .. (@universe_size * 2)).each do |y_pos| # Print empty space before chart (for angles) nextline = '' if y_pos < @universe_size nextline += ' ' * ((@universe_size - y_pos).abs - 1) else nextline += ' ' * ((@universe_size - y_pos).abs) end # Print more empty space for the odd places (provides offset) if y_pos.odd? print ' ' end #Actually loop through everything (0 .. (@universe_size * 2)).each do |x_pos| # Make the grid work right, x is actually skipping every other. x_pos *= 2 x_pos += 1 if y_pos.odd? position = Position.new(x_pos, y_pos) # Print empty space if we are outside the universe (For items) if distance(@center, position) >= @universe_size print ' ' next end # Print what we are: value = @universe_map[position.y_pos][position.x_pos] nextline += ' ' if [x_pos, y_pos] == @center print 'O' elsif value.class == Planet print 'P' else print ' ' end # Calculate what we should print on the next line and if we should print dashes if y_pos < @universe_size nextline += '/ \\' end if distance(@center, Position.new(x_pos + 2, y_pos)) < @universe_size print '---' if y_pos >= @universe_size nextline += '\\ /' end end end # For each col in row puts '' if (y_pos + 1) / 2 < @universe_size && !simple puts nextline end end # For each row end # Function print_universe ################################################## ################### UNIVERSE ##################### ################################################## # This is where API stuff for the universe should go # Gets a position from the universe for a player. Eventually this will take # into account that the player can not actually see the whole universe # # @param player [Player] The player who is asking for the position # @param position [Position] The position that is being requested def get_position(player, position) end # Sets a position as explored for a player. This should be called as ships # move around and explore the universe. # # @param player [Player] The player who should be set # @param position [Position] The position that is being modified def explore_position(player, position) end ################################################## ##################### SHIPS ###################### ################################################## # Create a ship in the universe. This ship is registered to a specific player # # @param player [Player] The player who owns the ship # @param position [Position] The position that the ship should be created at def create_ship(player, position) end # Move a player's ship to a given position # # @param player [Player] The player whose ship should be moved # @param ship [Ship] The ship that should be moved # @param position [Position] The position the ship should be moved to. def move_ship(player, ship, position) end ################################################## ##################### PLANETS #################### ################################################## # As all planets are created when the galaxy is generated there are no create # planet functions. It is possible that we want to remove them though # Remove a planet from the universe # # @param planet [Planet] The planet that should be removed # @param position [Position] The position that it should be removed from def remove_planet(planet, position) end ################################################## ##################### PLAYER ##################### ################################################## # Add a player to the player list in the universe # # @param player [Player] The player who should be added to the universe def add_player(player) @player_list.push(player) return 'Added player to universe' end # Remove a player from the list in this universe # # @param player [Player] The player that should be removed from the player list. def remove_player(player) if @player_list.delete(player).nil? return 'Failed to remove player! Does not exist in this universe!' end return 'Removed player from universe' end # Returns a list of ships owned by the player # # @param player [Player] The player who wants to get their ships. def get_player_ships(player) result = [] @ship_list.each do |ship| if ship.owner == player result.push(ship) end end return result end # Function get_player_ships # Returns a list of planets owned by the player # # @param player [Player] The player who wants to get their planets. def get_player_planets(player) result = [] @planet_list.each do |planet| if planet.owner == player result.push(planet) end end return result end end # Class Universe