Space Merchant (#71)


#1

The three rules of Ruby Q.:

  1. Please do not post any solutions or spoiler discussion for this quiz
    until
    48 hours have passed from the time on this message.

  2. Support Ruby Q. by submitting ideas as often as you can:

http://www.rubyquiz.com/

  1. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem helps
everyone
on Ruby T. follow the discussion.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

This week’s Ruby Q. is to build a complete game with the help of your
fellow
Ruby P.mers. This is a multipart Ruby Q. all in one week. Each
person
should select one task they wish to solve and leave the other tasks for
other
solutions.

The Game

When I was young, I loved to play BBS door games. A very popular game I
was
hooked on was called TradeWars 2002. While the BBS is pretty much a
thing of
the past, that game has been cloned in some form or another for just
about every
platform that ever existed.

The premise of the game is simple: you play a space trader flying
around the
galaxy buying and selling goods. The main goal is to find places to buy
goods
at a low price and then unload those goods at another location with a
higher
price, turning a profit. Most versions of the game allow you to use
that money
to buy bigger and better space ships, which in turn allows you to carry
more
goods and make bigger profits. Many versions of the game don’t have a
clear
ending, though I have seen a version that eventually allowed you to buy
a moon
to retire on.

Common Elements

The thread tying all the pieces of the game together is the Player
object. It
is the centralized storage for game state information, like how much
money the
player currently has.

The other item we need is a trivial event loop. The options a player
has
available at any given time are a function of where they are. For
example,
while flying through space the player probably has commands to choose a
destination, but when docked with a space station the commands will
likely
center around buying and selling goods.

The following code provides both elements:

#!/usr/local/bin/ruby -w

# space_merchant.rb

require "singleton"

module SpaceMerchant
  VERSION = "1.0"

  # We will use a basic Hash, but feel free to add methods to it.
  class Player
    instance_methods.each { |meth| undef_method(meth) unless meth =~ 

/^__/ }

    include Singleton
    def initialize
      @game_data = Hash.new
    end

    def method_missing( meth, *args, &block )
      @game_data.send(meth, *args, &block)
    end
  end
end

if __FILE__ == $0
  require "galaxy"   # Task 1
  require "sector"   # Task 2
  require "station"  # Task 3
  require "planet"   # Task 4

  # collect beginning player information
  player = SpaceMerchant::Player.instance

  puts
  puts "Welcome to Space Merchant #{SpaceMerchant::VERSION}, " +
       "the Ruby Q. game!"
  puts

  print "What would you like to be called, pilot?  "
  loop do
    name = gets.chomp

    if name =~ /\S/
      player[:name] = name

      puts "#{player[:name]} it is."
      puts

      puts "May you find fame and fortune here in the Ruby Galaxy..."
      puts

      break
    else
      print "Please enter a name:  "
    end
  end

  player[:credits]  = 1000
  # we initialize player[:location], it should be changed to move the 

player
player[:location] = SpaceMerchant::Galaxy.instance.starting_location

  catch(:quit) do  # use throw(:quit) to exit the game
    # primary event loop
    loop { player[:location].handle_event(player) }
  end
end

As you can see in the event loop, all Sectors, Stations, and Planets
need to
support a handle_event() method that gives the player some choices,
fetches an
action from the keyboard, and responds appropriately.

The other four pieces I leave to you…

SpaceMerchant::Galaxy (Task 1)

We need an object representing the play-space as a whole. The Galaxy is
responsible for creating all of the game locations and allowing event
code to
access these locations.

There should only be one Galaxy, so please make it a Singleton (support
an
instance() class method to retrieve it).

The first concern of the Galaxy is to construct Sector, Planet and
Station
objects. Sectors are pieces of space the players can move between.
Think of
them as squares on the game board. These areas must be connected, so
the player
can move from location to location. Sectors will support these creation
methods, to aid this process:

Sector::new( name, location = nil )
Sector#link( other_sector )
Sector#add_planet( planet )
Sector#add_station( station )

Don’t sweat too much over the names for the Sectors, TradeWars simply
numbered
them: Sector 1, Sector 2, …, Sector 1051, … This works out
surprisingly
well because players can enter letter commands for game actions (say l
for land)
and numbers to move to a new Sector.

The location parameter is an optional way to divide Sectors into groups.
For
example, Sectors 1 through 10 were always “Fed Space” in TradeWars.

The add_*() methods are for placing Planet and Station objects in the
Sector.
Both are trivial to construct (again be creative with the names):

Planet.new( sector, name )
Station.new( sector, name )

Let’s keep the number objects fairly small, just so we don’t overwhelm
the
player. Something like up to five Planets, possibly one Station, and a
maximum
of six links to nearby Sectors sounds sane to me (but use your best
judgement).
Of course, a Sector can be empty.

Please provide these iterators to help the other classes locate objects
as well:

Galaxy::find_sectors { |sector| ... }
Galaxy::find_planets { |planet| ... }
Galaxy::find_stations { |station| ... }

Finally, the Galaxy should provide a pathfinding algorithm, for use in
navigation:

Galaxy::find_path( start_sector, finish_sector, *avoid_sectors )

This method should return an Array of Sectors beginning with the
start_sector
and ending with the finish_sector. If the optional avoid_sectors are
provided,
they should not be used. It’s okay to return nil, if a path could not
be found,
but this should only be possible with avoid_sectors.

Random idea: some games have wormholes, one way links between Sectors.
This
can make for very interesting layouts. Just be careful if you add
wormholes to
make sure all Sectors can still be reached from all other Sectors.

SpaceMerchant::Sector (Task 2)

(See Galaxy for the creation methods Sector needs to support.)

The Sector is the main interface for moving around the Galaxy. The
Sector
should show the player their location, and request a command:

Sector 302
The Reaches

Station:  ABC Station
Planets:  Myr III, Myr IV, Myr VII

(D)ock with station
(L)and on planet
(P)lot a course

(Q)uit game

Or warp to nearby sector:  [4], [25], 1021, [9919]

Feel free to deviate from that in anyway you choose.

With the Sector you are in charge of how the player can move about.
Should they
only be allowed to move to nearby Sectors or can they plot long range
courses?
Perhaps only to Sectors they have visited before? You decide.

Any game level functions also belong here. Quit is obvious, but can you
think
of an easy way to support save?

Random ideas: consider supporting random encounters with computer
controlled
ships to make the galaxy feel more alive. “Unidentified vessel, this is
the
Galactic Patrol and we suspect you are transporting illegal cargo…
Prepare to
be boarded!”

Also consider supporting other space features like nebulas, black holes,
asteroid belts, etc. How should these affect the player?

SpaceMerchant::Station (Task 3)

(See Galaxy for the constructor Station needs to support.)

Stations are where the player can buy and sell goods. There may be some
set
categories of goods available in the Galaxy, but an individual Station
should
probably just offer to trade in a subset of those.

Some games have Stations set prices based on where they are in the
Galaxy while
other games have the prices fluctuate everywhere over time. You can
even have
Stations set their prices based on demand, which could rise and fall as
the
player trades there.

The player’s ship should probably have a limited capacity of goods it
can carry
at a time. I purposefully haven’t set this, so that Station
implementations
could flesh out the player’s ship as they saw fit. Perhaps some
Stations could
even offer ship upgrades.

Random idea: The original TradeWars game even allowed players to choose
a
criminal path. They could try stealing goods from a Station, to trade
elsewhere. There were penalties for getting caught though and
eventually word
of your crimes got around and you weren’t safe from the other denizens
of space.

SpaceMerchant::Planet (Task 4)

(See Galaxy for the constructor Planet needs to support.)

Planets have had numerous functions in the various incarnations of space
trading
games. In the spirit of that, I’m leaving this section as a sort of
free-for-all.

My suggestion is to use the planets as a kind of a quest engine. Allow
the
player to pick-up unique cargos or people and transport them to other
planets in
the Galaxy. See if you can get these quests to build on each other and
form a
basic plot for the game.

Random idea: Some games have had items for sale which allowed the
creation and
destruction of planets. You might even be able to tie that into the
missions
somehow.

Sharing Your API

When you have finished a task, you are invited to send in a message
telling
others what you built, even if the spoiler period has not yet passed.
You may
include documentation for some methods your object provides, or detail
some
variables you set on the Player. This may help others to choose a
different
task and take advantage of features you provided.


#2

I’ve attached a library, GalaxyLoader, that parses a DSL for “world
builders”. There’s a brief example of the DSL following, and an
example world attached. The library also adds a class method
Galaxy.load to your Galaxy class. With this library, loading a galaxy
is as simple as:

require ‘galaxy_loader’
galaxy = Galaxy.load(‘sample.glx’)

do stuff with the galaxy…

The DSL is fairly simple. A galaxy can have many sectors, possibly
within regions:

galaxy {
region(“Federation Space”) {
sector(1) { … }
sector(2) { … }
}

region("Klingon Space") {
  sector(3) { ... }
  sector(4) { ... }
}

sector(5) { ... }
sector(6) { ... }

}

A sector can have planets, stations and neighbors:

galaxy {
sector(1) {
planet “Earth”
station “Alpha”
neighbors 2, 3
}
sector(2) {
station “Beta”
neighbors 1, 3
}

sector(3) {
  neighbors 1, 2
}

}

And that’s all there is to it! I tried to make the GalaxyLoader class
as consistent as possible, so it should be fairly easy to add further
attributes to planets and stations by following the pattern of the
existing methods.

Enjoy!

Jacob F.


#3

On Sat, 2006-03-18 at 03:33 +0900, Jacob F. wrote:

I’ve attached a library, GalaxyLoader, that parses a DSL for “world
builders”.

Pretty cool, beats my current random generation strategy :slight_smile:

I think I have a basic Galaxy implementation right now, with most of the
requirements in there. I’ve made rdoc off of it and posted it at [1].
I’ll probably make a few (additive) changes between now and Sunday
though.

I’ve left the tests in the rdoc to give some samples. It also seems to
work fine with the GalaxyLoader.

[1] http://roscopeco.co.uk/code/ruby-quiz-entries/71/rdoc/


#4

I’m working on a Sector implementation at the moment. I’ll post the
RDocs for it sometime tonight, but for now it’s designed to work with
Ross’s Galaxy, and also assumes that Planets and Stations implement
name => String. It also adds @visited_sectors to Player, so that
long range courses can only be plotted to (and through) previously
visited sectors. If I have time, I may add support for one of the
other ideas (nebulas, random encounters, black holes, etc.).

Is anyone working on the Planet or Station classes?

Tim


#5

Ok here is my quick SpaceMerchant::Sector class. I wasn’t able to
participate in last weeks quiz (and I suggested it!) so I want to be
sure and do something in this week. I need to go through and clean this
up now, but I wanted to get this out there quick because I haven’t seen
any parts besided the Galaxy put up. At the very end is the code I’ve
been using to tests with. Ok thanks!

-----Jay A.

module SpaceMerchant
class Sector
attr_reader :name

    def initialize(name, region)
        @name, @region = name, region
        @planets = []
        @stations = []
        @links = []
    end

    def link(other_sector)
        @links << other_sector
    end

    def add_planet(planet)
        @planets << planet
    end

    def add_station(station)
        @stations << station
    end

    def handle_event(player)
        menu = :main_menu
        while menu != :done
            menu = send menu, player
        end
    end

    def main_menu player
        puts "Sector #{name}"
        puts "#{@region.name}"
        puts
        if(@stations.length > 0) then
            puts "Station#{'s' if @stations.length>0}:

"removed_email_address@domain.invalid{|s|s.name}.join(’, ‘)
end
if(@planets.length > 0) then
puts "Planet#{‘s’ if @planets.length>0}:
"removed_email_address@domain.invalid{|p|p.name}.join(’, ')
end

        puts
        puts '(D)ock with station' if @stations.length > 0
        puts '(L)and on planet' if @stations.length > 0
        puts
        if(@links.length > 0) then
            puts 'Warp to nearby sector:

‘removed_email_address@domain.invalid{|l|’[’+l.name+’]’}.join(’, ')
end
puts
puts ‘(Q)uit game’
print ‘?’

        response = gets.chomp
        case response
        when /^d/i
            return :dock
        when /^l/i
            return :land
        when /^q/i
            puts "Are you sure you want to quit? (y/n)"
            y_or_n = ''
            while (y_or_n = gets) !~ /^(y|n)/i
                puts "Are you sure you want to quit? (y/n)"
            end
            if y_or_n =~ /^y/i then puts 'goodbye!'; exit 0; end
            return :main_menu
        else
            new_loc = @links.select{|l| l.name == response}
            if new_loc.length > 0 then
                puts "Travelling..."
                player[:location] = new_loc.first
                return :done
            else
                puts " *** INVALID CHOICE ***"
                return :main_menu
            end
        end
    end

    def dock player
        if @stations.length < 1 then
            puts "There are no stations to dock with"
            return :main_menu
        end
        puts "Choose station to dock with:"
        puts
        @stations.each_with_index do |s,index|
            puts "  #{index}: #{s.name}"
        end
        puts
        puts "(M)ain menu"
        print "?"

        response = gets.chomp
        choice = response.to_i
        if response =~ /^m/i then
            return :main_menu
        elsif choice.to_s != response || choice >= @stations.length

then
puts " *** INVALID CHOICE ***"
return :dock
else
puts “Docking…”
player[:location] = @stations[choice]
return :done
end
end

    def land player
        if @planets.length < 1 then
            puts "There are no planets to land on"
            return :main_menu
        end
        puts "Choose planet to land on:"
        puts
        @planets.each_with_index do |p,index|
            puts "  #{index}: #{p.name}"
        end
        puts
        puts "(M)ain menu"
        print "?"

        response = gets.chomp
        choice = response.to_i
        if response =~ /^m/i then
            return :main_menu
        elsif choice.to_s != response || choice >= @planets.length

then
puts " *** INVALID CHOICE ***"
return :dock
else
puts “Landing…”
player[:location] = @planets[choice]
return :done
end
end
end
end

if FILE == $0
Named = Struct.new(:name)
region = Named.new(‘The Region’)
s = SpaceMerchant::Sector.new(‘Test Sector’, region)
5.times do |i|
s.add_planet(Named.new(“planet #{i}”))
s.add_station(Named.new(“station #{i}”))
s.link(SpaceMerchant::Sector.new("#{i}", region))
end

player = {}
s.handle_event(player)
p player

end


#6

Correction to this solution: in plot_course, @path.nil? should be
path.nil?

I should note here that plot_course is almost completely untested,
since it depends heavily on Galaxy, which I haven’t completely
stubbed out.

Tim


#7

Here’s the Sector implementation I was working on. It can use a
bunch of cleaning up (choose_station and choose_planet need to be
merged together at least in part - much duplicate code there), but as
this is the second posted Sector implementation, and no one has
mentioned working on a Planet or Station implementation, I’m going to
go ahead and send in a Planet class tomorrow instead of cleaning this
up.

module SpaceMerchant
class Sector
attr_reader :links, :planets, :stations, :location

 def initialize ( name, location = nil )
   @name = name
   @location = location
   @links = []
   @planets = []
   @stations = []
 end

 def name
   @name.to_s
 end

 def to_s
   name
 end

 def add_planet ( planet )
   @planets << planet
 end

 def add_station ( station )
   @stations << station
 end

 def link ( to_sector )
   @links << to_sector
 end

 def handle_event ( player )
   player[:visited_sectors] ||= []
   player[:visited_sectors] << self unless player

[:visited_sectors].find { |sector| sector == self }
print_menu
choice = gets.chomp
case choice
when /d/i: choose_station
when /l/i: choose_planet
when /p/i: plot_course
when /q/i: throw(:quit)
when /\d+/: warp player, choice
else invalid_choice
end
end

 def == ( other )
   if other.class == Sector
     self.name == other.name
   elsif other.class == String
     self.name == other
   else
     false
   end
 end

 private

 def warp ( player, sector_name )
   sector = Galaxy.instance.sectors.find { |sector| sector_name

== sector.name }
if sector && @links.find { |sec| sector_name == sec }
player[:location] = sector
puts “Warping to Sector #{sector_name}…”
elsif sector.nil?
puts “Sector #{sector_name} does not exist.”
else
puts “Sector #{sector_name} cannot be reached from here.”
end
puts
end

 def print_menu
   puts "Sector #{@name}"
   puts @location if @location
   puts

   puts "Station" + (@stations.size == 1 ? '' : 's') +
     ": " + @stations.map{|stat| stat.name}.join(', ') unless

@stations.empty?

   puts "Planet" + (@planets.size == 1 ? '' : 's') +
     ": " + @planets.map{|plan| plan.name}.join(', ')} unless

@planets.empty?
puts “Nothing here!” if @stations.empty? && @planets.empty?
puts

   puts "(D)ock with station" unless @stations.empty?
   puts "(L)and on planet" unless @planets.empty?
   puts "(P)lot a course"
   puts

   puts "(Q)uit game"
   puts

   puts "Or warp to nearby sector: #{@links.join(', ')}"
   puts
 end

 def invalid_choice
   puts "Please enter a valid choice."
 end

 def choose_station
   player = Player.instance
   puts "There are no stations to dock with!" if @stations.empty?
   if @stations.size == 1
     dock @stations[0], player
   else
     @stations.each_with_index do |station, index|
       puts "(#{index + 1}) #{station.name}"
     end
     puts "Enter the number of the station to dock with: "

     station_index = gets.chomp.to_i - 1
     if @stations[station_index]
       dock @stations[station_index], player
     else
       puts "Invalid station."
     end
   end
 end

 def choose_planet
   player = Player.instance
   puts "There are no planets to land on!" if @planets.empty?
   if @planets.size == 1
     land @planets[0], player
   else
     @planets.each_with_index do |planet, index|
       puts "(#{index + 1}) #{planet}"
     end
     puts "Enter the number of the planet to land on: "

     planet_index = gets.chomp.to_i - 1
     if @planets[planet_index]
       dock @planets[planet_index], player
     else
       puts "Invalid planet."
     end
   end
 end

 def land (planet, player)
   puts "Landing on #{planet.name}..."
   player[:location] = planet
 end

 def dock (station, player)
   puts "Docking at #{station.name}..."
   player[:location] = station
 end

 def plot_course
   player = Player.instance
   galaxy = Galaxy.instance
   unknown_sectors = galaxy.sectors - player[:visited_sectors]
   reachable_sectors = galaxy.find_reachable(self, unknown_sectors)
   reachable_sectors.each do |sector|
     puts "#{sector}" + sector.location ? "(#

{sector.location})" : ‘’
end

   puts
   puts "Enter the sector name to which you wish to travel: "
   sector_name = gets.chomp
   destination = galaxy.sectors.find { |sector| sector ==

sector.name }
path = galaxy.find_path( self, destination, unknown_sectors)
puts
unless @path.nil?
puts “Your course:”
path.each do |sector|
puts “#{sector}” + sector.location ? “(#
{sector.location})” : ‘’
end

     puts "Confirm course (y/n)?"
     confirm = gets.chomp =~ /y/i

     if confirm
       me[:location] = destination
       puts "Traveling to Sector #{destination}..."
     end
   else
     puts "That sector can not be reached."
   end
 end

end
end


#8

Ok, here’s my somewhat cleaned up version. I added a rudamentary
ability to save the game, but it would require changing the main code
to actually be able to load it.

module SpaceMerchant
class Sector
attr_reader :name, :region, :planets, :stations, :links

    def initialize(name, region)
        @name, @region = name, region
        @planets = []
        @stations = []
        @links = []
    end

    def link(other_sector)
        @links << other_sector
    end

    def add_planet(planet)
        @planets << planet
    end

    def add_station(station)
        @stations << station
    end

    def handle_event(player)
        @player = player
        @menu = :main_menu
        while @menu != :done
            puts '-'*60
            send @menu
        end
    end

    def main_menu
        puts "Sector #{name}"
        puts "#{@region.name}"
        puts
        if(@stations.length > 0) then
            puts "Station#{'s' if @stations.length>0}:

"removed_email_address@domain.invalid{|s|s.name}.join(’, ‘)
end
if(@planets.length > 0) then
puts "Planet#{‘s’ if @planets.length>0}:
"removed_email_address@domain.invalid{|p|p.name}.join(’, ‘)
end
if(@links.length > 0) then
puts "Nearby Sector#{‘s’ if @links.length>0}:
"removed_email_address@domain.invalid{|s|s.name}.join(’, ')
end

        puts
        puts '(D)ock with station' if @stations.length > 0
        puts '(L)and on planet' if @stations.length > 0
        puts '(W)arp to nearby sector' if @links.length > 0
        puts
        puts '(S)ave game'
        puts '(Q)uit game'
        print '?'

        response = gets.chomp
        case response
        when /^d/i
            @menu = :dock
        when /^l/i
            @menu = :land
        when /^w/i
            @menu = :warp
        when /^s/i
            @menu = :save
        when /^q/i
            @menu = :quit
        else
            puts " *** INVALID CHOICE ***"
            @menu = :main_menu
        end
    end

    def warp
        result = nil
        begin
            result = choose_move(@links, 'sector to warp to')
        end until result != :bad
        puts "Warping..." if result != :main_menu
    end

    def dock
        result = nil
        begin
            result = choose_move(@stations, 'station to dock with')
        end until result != :bad
        puts "Docking..." if result != :main_menu
    end

    def land
        result = nil
        begin
            result = choose_move(@planets, 'planet to land on')
        end until result != :bad
        puts "Landing..." if result != :main_menu
    end

    def choose_move choices, string
        if choices.length < 1 then
            puts "There is no #{string}"
            return @menu = :main_menu
        end
        puts "Choose #{string}:"
        puts
        choices.each_with_index do |c,index|
            puts "  #{index}: #{c.name}"
        end
        puts
        puts "(M)ain menu"
        print "?"

        response = gets.chomp
        choice = response.to_i
        if response =~ /^m/i then
            return @menu = :main_menu
        elsif choice.to_s != response || choice >= choices.length

then
puts " *** INVALID CHOICE ***"
return :bad
else
@player[:location] = choices[choice]
return @menu = :done
end
end

    def save
        @menu = :main_menu
        filename = @player[:name]+".save"
        if(File.exists? filename) then
            puts "Do you want to overwrite previous saved game?"
            if gets.chomp !~ /^y/i
                puts "Game not saved"
                return
            end
        end
        File.open(filename, 'wb') do |f|
            Marshal.dump(@player, f)
        end
        puts "Game Saved."
    end

    def quit
        puts "Are you sure you want to quit? (y/n)"
        y_or_n = gets.chomp
        case y_or_n
        when /^y/i
            puts 'goodbye!'
            exit 0
        when /^n/i
            @menu = :main_menu
        else
            puts "Hmm... I'll assume you don't want to quit from

that."
@menu = :main_menu
end
end
end
end

if FILE == $0
Named = Struct.new(:name)
region = Named.new(‘The Region’)
s = SpaceMerchant::Sector.new(‘Test Sector’, region)
5.times do |i|
s.add_planet(Named.new(“planet #{i}”))
s.add_station(Named.new(“station #{i}”))
s.link(SpaceMerchant::Sector.new("#{i}", region))
end

player = {:name => "test"}
s.handle_event(player)
p player

end


#9

Here is my Galaxy implementation. It seems to do everything it needs to
do, but I didn’t go overboard with extra stuff since I don’t know what
kind of stuff might be useful for the Galaxy to do…

The easiest way to use this with the GalaxyLoader seems to be to remove
the ‘require galaxy’ from GalaxyLoader and do it the other way around.
Then you can run the tests including the dump test with:

ruby -rgalaxy_loader galaxy.rb

There are some naive benchmarks I used to make the obvious
optimizations, run them with:

ruby galaxy.rb -bm

One additional thing I did consider was multiplayer - it’s fairly easy
to get a galaxy working over DRb, and I did work up a basic multiplayer
version like this but had one overriding problem - all output ends up on
the server, or the game ends up useless because of constantly
marshalling sectors to send down the wire. I toyed with routing output
through the Player but still had problems… Ho hum.

Finally, I need to thank a couple of people: Dominik B.'s solution
to Ruby Q. 31 ( see
http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-talk/141783 ) gave me
a much-needed start with Dijkstra’s shortest path algorithm (in fact
it’s only very slightly modified from his original) and Mauricio
Fernandez’s WeakHash class let’s me cache stuff irresponsibly (see
http://eigenclass.org/hiki.rb?weakhash+and+weakref )


#10

On Mar 20, 2006, at 2:41 AM, Ross B. wrote:

One additional thing I did consider was multiplayer - it’s fairly easy
to get a galaxy working over DRb, and I did work up a basic
multiplayer
version like this but had one overriding problem - all output ends
up on
the server, or the game ends up useless because of constantly
marshalling sectors to send down the wire. I toyed with routing output
through the Player but still had problems… Ho hum.

This might be a fun follow-up quiz someday, if we can get the other
two pieces we need. Anyone working on station.rb or planet.rb?

I’ll see if I can steal a few hours tonight and knock one out…

James Edward G. II


#11

I’m working on a planet.rb.

Tim


#12

On Mon, 2006-03-20 at 17:41 +0900, Ross B. wrote:

Here is my Galaxy implementation.

I must’ve run these tests a few hundred times over the past few days,
and again before I posted - all green. Immediately after posting I’m
seeing failures roughly two fifths of the time because two or three
sectors are unreachable. Ain’t it just typical?

I don’t have time right now to fix it, but I’ll have a look later on and
try to find out what’s wrong.


#13

Here is my improved sector.rb. Yes, I know I said I wasn’t going to
fix it up, but once Ross posted a working Galaxy implementation, I
couldn’t resist testing it and fixing it up. I fixed a few more bugs
and some problems it had due to a misunderstanding of Ross’s galaxy
implementation. One thing with this is that it no longer prepends
“Sector” in front of the sector name, since Ross’s randomly generated
galaxy has sectors named “Sector 530” and so forth, and it looked
really stupid to have “Sector Sector 530.” The sample galaxy file
for the galaxy loader, on the other hand, just has the numbers, so if
used with that galaxy, it will just print “530” without any real
indication that 530 is a sector. Still, I figured this was better
than “Sector Sector,” and I didn’t want to take the time to prepend
Sector if it wasn’t all ready there.

Anyway, I’ll be going ahead and putting together a planet.rb.


#14

James (or whoever else is doing station.rb), how are you representing
cargo and passengers, and where are you putting them in the player?
I was just starting to work on classes to represent items and people
that can be found and/or used on planets, and realized that there may
be a bit of overlap between items found on planets and bought at
stations, so they should at least be the same duck type. I was
thinking that they’d be stored in player[:cargo] and player[:passengers]

Tim


#15

On Mar 20, 2006, at 11:10 AM, Timothy B. wrote:

James (or whoever else is doing station.rb), how are you
representing cargo and passengers, and where are you putting them
in the player?

I’m thinking I will introduce a Ship object in there. I’ve cleared
some hours this evening to work on it and will post some details when
I get something going…

James Edward G. II


#16

Ross B. wrote:

One additional thing I did consider was multiplayer - it’s fairly easy
to get a galaxy working over DRb, and I did work up a basic multiplayer
version like this but had one overriding problem - all output ends up on
the server, or the game ends up useless because of constantly
marshalling sectors to send down the wire. I toyed with routing output
through the Player but still had problems… Ho hum.

What about including DRbUndumped in the sector class, to keep them on
the server?


#17

On Mar 20, 2006, at 8:35 AM, Timothy B. wrote:

Here is my improved sector.rb.

<sector.rb>

Would you guys like a public svn repository for this? That way you
could all keep all of the various parts together.

If so, just say the word, I’ll gladly host one for you…

–Steve


#18

On Tue, 2006-03-21 at 01:35 +0900, Timothy B. wrote:

One thing with this is that it no longer prepends
“Sector” in front of the sector name, since Ross’s randomly generated
galaxy has sectors named “Sector 530” and so forth, and it looked
really stupid to have “Sector Sector 530.” The sample galaxy file
for the galaxy loader, on the other hand, just has the numbers, so if
used with that galaxy, it will just print “530” without any real
indication that 530 is a sector. Still, I figured this was better
than “Sector Sector,” and I didn’t want to take the time to prepend
Sector if it wasn’t all ready there.

Now you mention that, I think it’s probably better if I remove that
automatic ‘Sector’ in the generated galaxies, assuming we’re sticking
with the numbered sectors throughout. That way, the sector can decide on
how the number fits into it’s name.


#19

On 3/20/06, Timothy B. removed_email_address@domain.invalid wrote:

James (or whoever else is doing station.rb), how are you representing
cargo and passengers, and where are you putting them in the player?
I was just starting to work on classes to represent items and people
that can be found and/or used on planets, and realized that there may
be a bit of overlap between items found on planets and bought at
stations, so they should at least be the same duck type. I was
thinking that they’d be stored in player[:cargo] and player[:passengers]

I’m working on an implementation of Station and just representing
cargo items as symbols. Ie. the Station has a @trading hash keyed by
:machinery, :organics, etc. (whatever the world builder populates the
station with). When the player docks at the station, they see what’s
available for what prices and are presented with a Buy/Sell/Exit
choice. When they, for instance, Buy, the Station will call two
methods on the Player: Player#pay(price) and Player#load_cargo(good,
quantity) where ‘good’ is the symbol representing that good. As such,
I don’t need to know anything about the Player’s representation, I
just require that Players visiting my Station provide the appropriate
methods. This representation of goods by symbols of course assumes
that a transported good has no state or operations beyond
classification.

Jacob F.


#20

On Mar 20, 2006, at 11:41 AM, Ross B. wrote:

Anyway, the problem with that was that, since Sector handles most
of the
output (and will probably just call puts) the output all goes to the
server’s terminal :frowning:

Could you have the client pass you $stdout and $stdin, then set them
on the server?

James Edward G. II