X-Git-Url: https://jxself.org/git/?p=super-star-trek.git;a=blobdiff_plain;f=src%2Fsst.py;h=477c05ab0765159e13f32b2b0b5b7859f5067514;hp=8e3842f045b30132845080f2486ee6301c5b8593;hb=9ae916e9144e84ef1de4a86ea73a45a2bc4cc1be;hpb=a0718b55ad87f433723f756dfe748701c7801695 diff --git a/src/sst.py b/src/sst.py index 8e3842f..477c05a 100644 --- a/src/sst.py +++ b/src/sst.py @@ -1,5 +1,15 @@ """ 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 @@ -15,6 +25,11 @@ MAXKLGAME = 127 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 = '#', @@ -46,24 +61,30 @@ class coord: 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": @@ -73,12 +94,16 @@ class ship(feature): 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." @@ -88,39 +113,33 @@ class planet(feature): 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' @@ -158,13 +177,11 @@ class snapshot: 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 @@ -291,8 +308,8 @@ def tryexit(look, ship, irun): 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: @@ -530,7 +547,7 @@ def movescom(ship, avoid): 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 @@ -553,10 +570,10 @@ def movescom(ship, avoid): 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) @@ -578,12 +595,12 @@ def scom(): 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") @@ -595,7 +612,7 @@ def scom(): # 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: @@ -609,16 +626,16 @@ def scom(): 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 @@ -632,11 +649,11 @@ def scom(): # 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: @@ -702,7 +719,7 @@ def movetho(void): 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() @@ -710,13 +727,13 @@ def movetho(void): # 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)