"""
sst.py =-- Super Star Trek in Python
+
+Control flow of this translation is pretty much identical to the C version
+(and thus like the ancestral FORTRAN) but the data structures are
+radically different -- the Python code makes heavy use of objects.
+
+Note that the game.quad, game.snap.galaxy and game.snap.chart members
+are not actually arrays but dictioaries indixed by coord tuples. Be setting
+the hash of a coord equal to the hash of a literal tuple containing its
+coordinate data, we ensure these can be indexed both ways.
+
"""
import math
MAXKLQUAD = 9
FOREVER = 1e30
+# These macros hide the difference between 0-origin and 1-origin addressing.
+# They're a step towards de-FORTRANizing the code.
+def VALID_QUADRANT(x,y): ((x)>=1 and (x)<=GALSIZE and (y)>=1 and (y)<=GALSIZE)
+def VALID_SECTOR(x, y): ((x)>=1 and (x)<=QUADSIZE and (y)>=1 and (y)<=QUADSIZE)
+
# These types have not been dealt with yet
IHQUEST = '?',
IHWEB = '#',
return "%d - %d" % (self.x, self.y)
class feature:
- "A feature in the current quadrant (ship, star, black hole, etc)."
+ "A feature in the current quadrant (ship, star, black hole, base, etc)."
def __init__(self):
self.type = None # name of feature type
- self.location = None # location
+ self.sector = None # sector location
def distance(self):
- return self.location.distance(game.sector)
+ return self.sector.distance(game.sector)
def __str__(self):
+ "This will be overridden by subclasses."
return self.name[0]
-
-empty = None # Value of empty space in game.quad
+ def sectormove(self, dest):
+ "Move this feature within the current quadrant."
+ if self.sector:
+ game.quad[self.sector] = None
+ game.quad[dest] = self
+ self.sector = dest
class ship(feature):
- "An enemy ship in the current quadrant."
- def __init__(self):
+ "A starship, frindly or enemy."
+ def __init__(self, type, power):
feature.__init__(self)
- self.type = None # klingon, romulan, commander,
- # supercommander, tholian
- self.power = None # power
+ self.type = type # klingon, romulan, commander,
+ # supercommander, tholian,
+ # enterprise, faerie queene.
+ self.power = power # power
if self.type in ("Klingon", "Commander", "Super-Commander"):
game.remkl += 1
elif self.type == "Romulan":
game.remkl -= 1
elif self.type == "Romulan":
game.romrem -= 1
- def sectormove(self, dest):
- "Move this ship within the current quadrant."
- if self.location:
- game.quad[self.location] = None
- game.quad[dest] = self
- self.location = dest
+
+class space(feature):
+ "Empty space. Has no state, just knows how to identify iself."
+ def __str__(self):
+ return '*'
+
+class star(feature):
+ "A star. Has no state, just knows how to identify iself."
+ def __str__(self):
+ return '*'
class planet(feature):
"A planet. May be inhabited or not, may hold dilithium crystals or not."
self.crystals = None # "absent", "present", or "mined"
self.inhabited = False
self.known = "unknown" # Other values: "known" and "shuttle down"
+ game.state.planets.append(self)
+ def __del__(self):
+ game.state.planets.remove(self)
def __str__(self):
if self.inhabited:
return '@'
else:
return 'P'
-class star(feature):
- "A star. Has no state, just knows how to identify iself."
- def __init(self):
- feature.__init__(self)
- def __str__(self):
- return '*'
-
class web(feature):
"A bit of Tholian web. Has no state, just knows how to identify iself."
- def __init(self):
- feature.__init__(self)
def __str__(self):
return '*'
class blackhole(feature):
"A black hole. Has no hair, just knows how to identify iself."
- def __init(self):
- feature.__init__(self)
def __str__(self):
- return '*'
+ return ' '
class starbase(feature):
- "Starbases also have no features."
- def __init(self):
+ "Starbases also have no features, just a location."
+ def __init(self, quadrant):
feature.__init__(self)
+ self.quadrant = quadrant
+ game.state.bases.append(self)
def __del__(self):
- game.state.bases.remove(self.location)
+ game.state.bases.remove(self)
def __str__(self):
return 'B'
self.remkl = None # remaining klingons
self.remcom = None # remaining commanders
self.nscrem = None # remaining super commanders
- self.rembase = None # remaining bases
self.starkl = None # destroyed stars
self.basekl = None # destroyed bases
self.nromrem = None # Romulans remaining
- self.nplankl = None # destroyed uninhabited planets
- self.nworldkl = None # destroyed inhabited planets
- self.plnets = []; # List of planets known
+ self.nplankl = None # destroyed uninhabited planets self.nworldkl = None # destroyed inhabited planets
+ self.planets = []; # List of planets known
self.date = None # stardate
self.remres = None # remaining resources
self. remtime = None # remaining time
def communicating():
"Are we in communication with Starfleet Command?"
- return (not damaged("DRADIO")) or game.condition == docked
+ return (not damaged("DRADIO")) or game.condition == "docked"
# Code corresponding to ai.c begins here
iq.y = game.quadrant.y+(look.y+(QUADSIZE-1))/QUADSIZE - 1
if not valid_quadrant(iq) or \
game.state.galaxy[iq].supernova or \
- game.state.galaxy[iq].klingons > 8:
- return False; # no can do -- neg energy, supernovae, or >8 Klingons
+ game.state.galaxy[iq].klingons > MAXKLQUAD-1:
+ return False; # no can do -- neg energy, supernovae, or >MAXKLQUAD-1 Klingons
if ship.type == "Romulan":
return False # Romulans cannot escape
if not irun:
if ship.distance() < dist1:
prout(" advances to sector %s" % ship.location)
else:
- proutn(" retreats to sector %s" % ship.location)
+ prout(" retreats to sector %s" % ship.location)
ship.sectormove(next)
-def movcom():
+def moveklings():
"Allow enemies to move."
for enemy in self.quad.enemies():
if enemy.type == "Commander":
global ipage
if game.state.kscmdr == game.quadrant or \
game.state.galaxy[iq].supernova or \
- game.state.galaxy[iq].klingons > 8:
+ game.state.galaxy[iq].klingons > MAXKLQUAD-1:
return True
if avoid:
# Avoid quadrants with bases if we want to avoid Enterprise
game.state.kscmdr = iq
game.state.galaxy[game.state.kscmdr].klingons += 1
# check for a helpful planet in the destination quadrant
- for planet in game.state.plnets:
+ for planet in game.state.planets:
if planet.location == game.state.kscmdr and planet.crystals=="present":
# destroy the planet
- game.state.plnets.remove(planet)
+ del planet
if communicating():
if not ipage:
pause_game(True)
passive = ((NKILLC+NKILLK)/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) \
or (game.state.date-game.indate) < 3.0)
if not game.iscate and passive:
- # compute move away from Enterprise
- idelta = game.state.kscmdr - game.quadrant
+ # coxmpute move away from Enterprise
+ delta = game.state.kscmdr - game.quadrant
if distance(game.state.kscmdr) > 2.0:
# circulate in space
- idelta,x = game.state.kscmdr.y-game.quadrant.y
- idelta,y = game.quadrant.x-game.state.kscmdr.x
+ delta.x = game.state.kscmdr.y-game.quadrant.y
+ delta.y = game.quadrant.x-game.state.kscmdr.x
else:
if len(game.state.bases):
unschedule("FSCMOVE")
# without too many Klingons, and not already under attack.
nearest = filter(game.starbases,
lambda x: game.state.galaxy[x].supernova \
- and game.state.galaxy[x].klingons <= 8)
+ and game.state.galaxy[x].klingons <= MAXKLQUAD-1)
if game.quadrant in nearest:
nearest.remove(game.quadrant)
if game.battle in nearest:
if len(nearest) == 0:
return # Nothing suitable -- wait until next time
# decide how to move toward base
- idelta = ibq - game.state.kscmdr
+ delta = ibq - game.state.kscmdr
# maximum movement is 1 quadrant in either or both axis
delta = delta.sgn()
# try moving in both x and y directions
- iq = game.state.kscmdr + idelta
+ iq = game.state.kscmdr + delta
if movescom(iq, passive):
# failed -- try some other maneuvers
- if ideltax==0 or ideltay==0:
+ if delta.x==0 or delta.y==0:
# attempt angle move
- if ideltax != 0:
+ if delta.x != 0:
iq.y = game.state.kscmdr.y + 1
if movescom(iq, passive):
iq.y = game.state.kscmdr.y - 1
# try moving just in x or y
iq.y = game.state.kscmdr.y
if movescom(iq, passive):
- iq.y = game.state.kscmdr.y + ideltay
+ iq.y = game.state.kscmdr.y + delta.y
iq.x = game.state.kscmdr.x
movescom(iq, passive)
# check for a base
- if game.state.rembase == 0:
+ if len(game.state.bases) == 0:
unschedule("FSCMOVE")
else:
for ibq in game.bases:
game.tholian = None
return
# Do nothing if we are blocked
- if game.quad[next] != empty and not isinstance(game.quad[next]. web):
+ if not (isinstance(game.quad[next], space) or isinstance(game.quad[next], web)):
return
# Now place some web
im = (next - game.tholian.location).sgn()
# move in x axis
while game.tholian.location.x != next.x:
game.tholian.location.x += im.x
- if game.quad[game.tholian.location] == empty:
+ if isinstance(game.quad[game.tholian.location], space):
game.quad[game.tholian.location] = web()
elif game.tholian.y != next.y:
# move in y axis
while game.tholian.y != next.y:
game.tholian.y += im.y
- if game.quad[game.tholian.location] == empty:
+ if isinstance(game.quad[game.tholian.location], space):
game.quad[game.tholian.location] = web()
# web is done, move ship
game.tholian.movesector(next)