Use Python list operations to get rid of a lot of FORTRANish for loops.
[super-star-trek.git] / src / sst.py
index e4681e29b3331e42bee6e21551911d26d89f9149..be0aef9ad0b8e746dfe851579d89d5f52c562f03 100644 (file)
@@ -206,11 +206,6 @@ MAXBURST   = 3
 def VALID_QUADRANT(x, y):      return ((x)>=0 and (x)<GALSIZE and (y)>=0 and (y)<GALSIZE)
 def VALID_SECTOR(x, y):        return ((x)>=0 and (x)<QUADSIZE and (y)>=0 and (y)<QUADSIZE)
 
-def square(i):         return ((i)*(i))
-def distance(c1, c2):  return math.sqrt(square(c1.x - c2.x) + square(c1.y - c2.y))
-def invalidate(w):     w.x = w.y = 0
-def is_valid(w):       return (w.x != 0 and w.y != 0)
-
 # How to represent features
 IHR = 'R',
 IHK = 'K',
@@ -249,8 +244,16 @@ class coord:
         return coord(self.x+self.x, self.y+self.y)
     def __sub__(self, other):
         return coord(self.x-other.x, self.y-other.y)
-    def distance(self, other):
+    def __mul__(self, other):
+        return coord(self.x*other, self.y*other)
+    def __rmul__(self, other):
+        return coord(self.x*other, self.y*other)
+    def distance(self, other=None):
+        if not other: other = coord(0, 0)
         return math.sqrt((self.x - other.x)**2 + (self.y - other.y)**2)
+    def bearing(self, other=None):
+        if not other: other = coord(0, 0)
+        return 1.90985*math.atan2(self.x-other.x, self.y-other.y)
     def sgn(self):
         s = coord()
         if self.x == 0:
@@ -278,7 +281,7 @@ class coord:
 class planet:
     def __init__(self):
         self.name = None       # string-valued if inhabited
-        self.w = coord()       # quadrant located
+        self.quadrant = coord()        # quadrant located
         self.pclass = None     # could be ""M", "N", "O", or "destroyed"
         self.crystals = "absent"# could be "mined", "present", "absent"
         self.known = "unknown" # could be "unknown", "known", "shuttle_down"
@@ -317,9 +320,7 @@ class snapshot:
         self.snap = False      # snapshot taken
         self.crew = 0          # crew complement
        self.remkl = 0          # remaining klingons
-       self.remcom = 0         # remaining commanders
        self.nscrem = 0         # remaining super commanders
-       self.rembase = 0        # remaining bases
        self.starkl = 0         # destroyed stars
        self.basekl = 0         # destroyed bases
        self.nromrem = 0        # Romulans remaining
@@ -330,11 +331,7 @@ class snapshot:
        self.remres = 0         # remaining resources
        self.remtime = 0        # remaining time
         self.baseq = []        # Base quadrant coordinates
-        for i in range(BASEMAX):
-            self.baseq.append(coord())
         self.kcmdr = []        # Commander quadrant coordinates
-        for i in range(QUADSIZE):
-            self.kcmdr.append(coord())
        self.kscmdr = coord()   # Supercommander quadrant coordinates
         # the galaxy (subscript 0 not used)
         self.galaxy = fill2d(GALSIZE, lambda i, j: quadrant())
@@ -435,7 +432,7 @@ class enemy:
         if loc:
             self.kloc = copy.copy(loc)
             game.quad[self.kloc.x][self.kloc.y] = self.type
-            self.kdist = self.kavgd = distance(game.sector, loc)
+            self.kdist = self.kavgd = (game.sector - loc).distance()
         else:
             self.kloc = coord()
             self.kdist = self.kavgd = None
@@ -469,8 +466,6 @@ class gamestate:
         self.justin = False    # just entered quadrant
         self.shldup = False    # shields are up
         self.shldchg = False   # shield is changing (affects efficiency)
-        self.comhere = False   # commander here
-        self.ishere = False    # super-commander in quadrant
         self.iscate = False    # super commander is here
         self.ientesc = False   # attempted escape from supercommander
         self.resting = False   # rest time
@@ -534,12 +529,12 @@ class gamestate:
         self.height = 0.0      # height of orbit around planet
     def recompute(self):
         # Stas thinks this should be (C expression): 
-        # game.state.remkl + game.state.remcom > 0 ?
-       #       game.state.remres/(game.state.remkl + 4*game.state.remcom) : 99
+        # game.state.remkl + len(game.state.kcmdr) > 0 ?
+       #       game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
         # He says the existing expression is prone to divide-by-zero errors
         # after killing the last klingon when score is shown -- perhaps also
         # if the only remaining klingon is SCOM.
-        game.state.remtime = game.state.remres/(game.state.remkl + 4*game.state.remcom)
+        game.state.remtime = game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr))
 # From enumerated type 'feature'
 IHR = 'R'
 IHK = 'K'
@@ -602,9 +597,9 @@ def randrange(*args):
 def randreal(*args):
     v = random.random()
     if len(args) == 1:
-        v *= args[0]           # returns from [0, a1)
+        v *= args[0]           # returns from [0, args[0])
     elif len(args) == 2:
-        v = args[0] + v*args[1]        # returns from [a1, a2)
+        v = args[0] + v*(args[1]-args[0])      # returns from [args[0], args[1])
     #logfp.write("# randreal%s -> %s at %s\n" % (args, v, traceback.extract_stack()[-2][1:]))
     return v
 
@@ -624,9 +619,8 @@ def tryexit(enemy, look, irun):
     if not irun:
        # avoid intruding on another commander's territory 
        if enemy.type == IHC:
-           for n in range(game.state.remcom):
-               if game.state.kcmdr[n] == iq:
-                   return False
+            if iq in game.state.kcmdr:
+                return False
            # refuse to leave if currently attacking starbase 
            if game.battle == game.quadrant:
                return False
@@ -648,7 +642,6 @@ def tryexit(enemy, look, irun):
     game.state.galaxy[game.quadrant.x][game.quadrant.y].klingons -= 1
     game.state.galaxy[iq.x][iq.y].klingons += 1
     if enemy.type==IHS:
-       game.ishere = False
        game.iscate = False
        game.ientesc = False
        game.isatb = 0
@@ -656,11 +649,10 @@ def tryexit(enemy, look, irun):
        unschedule(FSCDBAS)
        game.state.kscmdr=iq
     else:
-       for n in range(game.state.remcom):
-           if game.state.kcmdr[n] == game.quadrant:
-               game.state.kcmdr[n]=iq
+       for cmdr in game.state.kcmdr:
+           if cmdr == game.quadrant:
+               game.state.kcmdr[n] = iq
                break
-       game.comhere = False
     return True; # success 
 
 #
@@ -707,11 +699,11 @@ def movebaddy(enemy):
     # tactical movement for the bad guys 
     next = coord(); look = coord()
     irun = False
-    # This should probably be just game.comhere + game.ishere 
+    # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant) 
     if game.skill >= SKILL_EXPERT:
-       nbaddys = ((game.comhere*2 + game.ishere*2+game.klhere*1.23+game.irhere*1.5)/2.0)
+       nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
     else:
-       nbaddys = game.comhere + game.ishere
+       nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
     dist1 = enemy.kdist
     mdist = int(dist1 + 0.5); # Nearest integer distance 
     # If SC, check with spy to see if should hi-tail it 
@@ -741,9 +733,9 @@ def movebaddy(enemy):
            motion = ((forces + randreal(200))/150.0) - 5.0
        else:
             if forces > 1000.0: # Very strong -- move in for kill 
-               motion = (1.0-square(randreal()))*dist1 + 1.0
+               motion = (1.0 - randreal())**2 * dist1 + 1.0
            if game.condition=="docked" and (game.options & OPTION_BASE): # protected by base -- back off ! 
-               motion -= game.skill*(2.0-square(randreal()))
+               motion -= game.skill*(2.0-randreal()**2)
        if idebug:
            proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
        # don't move if no motion 
@@ -858,11 +850,11 @@ def moveklings():
        prout("== MOVCOM")
     # Figure out which Klingon is the commander (or Supercommander)
     # and do move
-    if game.comhere:
+    if game.quadrant in game.state.kcmdr:
         for enemy in game.enemies:
            if enemy.type == IHC:
                movebaddy(enemy)
-    if game.ishere:
+    if game.state.kscmdr==game.quadrant:
         for enemy in game.enemies:
            if enemy.type == IHS:
                movebaddy(enemy)
@@ -882,22 +874,19 @@ def movescom(iq, avoid):
        game.state.galaxy[iq.x][iq.y].supernova or \
        game.state.galaxy[iq.x][iq.y].klingons > MAXKLQUAD-1:
        return 1
-    if avoid:
-       # Avoid quadrants with bases if we want to avoid Enterprise 
-       for i in range(game.state.rembase):
-           if game.state.baseq[i] == iq:
-               return True
+    # Avoid quadrants with bases if we want to avoid Enterprise 
+    if avoid and iq in game.state.baseq:
+        return True
     if game.justin and not game.iscate:
        return True
     # do the move 
     game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].klingons -= 1
     game.state.kscmdr = iq
     game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].klingons += 1
-    if game.ishere:
+    if game.state.kscmdr==game.quadrant:
        # SC has scooted, Remove him from current quadrant 
        game.iscate=False
        game.isatb=0
-       game.ishere = False
        game.ientesc = False
        unschedule(FSCDBAS)
        for enemy in game.enemies:
@@ -910,7 +899,7 @@ def movescom(iq, avoid):
         game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
     # check for a helpful planet 
     for i in range(game.inplan):
-       if game.state.planets[i].w == game.state.kscmdr and \
+       if game.state.planets[i].quadrant == game.state.kscmdr and \
            game.state.planets[i].crystals == "present":
            # destroy the planet 
            game.state.planets[i].pclass = "destroyed"
@@ -930,7 +919,7 @@ def supercommander():
     if idebug:
        prout("== SUPERCOMMANDER")
     # Decide on being active or passive 
-    avoid = ((game.incom - game.state.remcom + game.inkling - game.state.remkl)/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) or \
+    avoid = ((game.incom - len(game.state.kcmdr) + game.inkling - game.state.remkl)/(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 avoid:
        # compute move away from Enterprise 
@@ -941,33 +930,32 @@ def supercommander():
            idelta.y = game.quadrant.x-game.state.kscmdr.x
     else:
        # compute distances to starbases 
-       if game.state.rembase <= 0:
+       if not game.state.baseq:
            # nothing left to do 
            unschedule(FSCMOVE)
            return
        sc = game.state.kscmdr
-       for i in range(game.state.rembase):
-           basetbl.append((i, distance(game.state.baseq[i], sc)))
-       if game.state.rembase > 1:
+        for base in game.state.baseq:
+           basetbl.append((i, (base - sc).distance()))
+       if game.state.baseq > 1:
             basetbl.sort(lambda x, y: cmp(x[1]. y[1]))
        # look for nearest base without a commander, no Enterprise, and
         # without too many Klingons, and not already under attack. 
        ifindit = iwhichb = 0
-       for i2 in range(game.state.rembase):
+       for (i2, base) in enumerate(game.state.baseq):
            i = basetbl[i2][0]; # bug in original had it not finding nearest
-           ibq = game.state.baseq[i]
-           if ibq == game.quadrant or ibq == game.battle or \
-               game.state.galaxy[ibq.x][ibq.y].supernova or \
-               game.state.galaxy[ibq.x][ibq.y].klingons > MAXKLQUAD-1:
+           if base == game.quadrant or base == game.battle or \
+               game.state.galaxy[base.x][base.y].supernova or \
+               game.state.galaxy[base.x][base.y].klingons > MAXKLQUAD-1:
                continue
            # if there is a commander, and no other base is appropriate,
-           #   we will take the one with the commander
-           for j in range(game.state.remcom):
-               if ibq == game.state.kcmdr[j] and ifindit!= 2:
+           # we will take the one with the commander
+            for cmdr in game.state.kcmdr:
+               if base == cmdr and ifindit != 2:
                    ifindit = 2
                    iwhichb = i
                    break
-           if j > game.state.remcom: # no commander -- use this one 
+           else:       # no commander -- use this one 
                ifindit = 1
                iwhichb = i
                break
@@ -1004,11 +992,10 @@ def supercommander():
                iq.x = game.state.kscmdr.x
                movescom(iq, avoid)
     # check for a base 
-    if game.state.rembase == 0:
+    if len(game.state.baseq) == 0:
        unschedule(FSCMOVE)
     else:
-       for i in range(game.state.rembase):
-           ibq = game.state.baseq[i]
+        for (i, ibq) in enumerate(game.state.baseq):
            if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
                # attack the base 
                if avoid:
@@ -1073,7 +1060,7 @@ def movetholian():
     while here.x != id.x:
         #print "Moving in X", delta
         here.x += delta.x
-        if game.quad[here.kloc.x][here.y]==IHDOT:
+        if game.quad[here.x][here.y]==IHDOT:
             game.tholian.move(here)
     # move in y axis 
     while here.y != id.y:
@@ -1114,7 +1101,6 @@ def doshield(shraise):
            if scanner.sees("transfer"):
                action = "NRG"
            else:
-               scanner.chew()
                if damaged(DSHIELD):
                    prout(_("Shields damaged and down."))
                    return
@@ -1301,7 +1287,7 @@ def collision(rammed, enemy):
        game.damage[dev] += game.optime + extradm
     game.shldup = False
     prout(_("***Shields are down."))
-    if game.state.remkl + game.state.remcom + game.state.nscrem:
+    if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
        announce()
        damagereport()
     else:
@@ -1336,7 +1322,7 @@ def torpedo(course, dispersion, origin, number, nburst):
        if not VALID_SECTOR(w.x, w.y):
            break
        iquad=game.quad[w.x][w.y]
-       tracktorpedo(w, step, number, nburst, iquad)
+       tracktorpedo(origin, w, step, number, nburst, iquad)
        if iquad==IHDOT:
            continue
        # hit something 
@@ -1349,7 +1335,7 @@ def torpedo(course, dispersion, origin, number, nburst):
            crmshp()
            prout(".")
            hit = 700.0 + randreal(100) - \
-               1000.0 * distance(w, origin) * math.fabs(math.sin(bullseye-angle))
+               1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
            newcnd(); # we're blown out of dock 
            # We may be displaced. 
            if game.landed or game.condition=="docked":
@@ -1386,7 +1372,7 @@ def torpedo(course, dispersion, origin, number, nburst):
                    break
            kp = math.fabs(e.kpower)
            h1 = 700.0 + randrange(100) - \
-               1000.0 * distance(w, origin) * math.fabs(math.sin(bullseye-angle))
+               1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
            h1 = math.fabs(h1)
            if kp < h1:
                h1 = kp
@@ -1425,13 +1411,9 @@ def torpedo(course, dispersion, origin, number, nburst):
        elif iquad == IHB: # Hit a base 
            skip(1)
            prout(_("***STARBASE DESTROYED.."))
-           for ll in range(game.state.rembase):
-               if game.state.baseq[ll] == game.quadrant:
-                   game.state.baseq[ll]=game.state.baseq[game.state.rembase]
-                   break
+            game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
            game.quad[w.x][w.y]=IHDOT
-           game.state.rembase -= 1
-           game.base.x=game.base.y=0
+           game.base.invalidate()
            game.state.galaxy[game.quadrant.x][game.quadrant.y].starbase -= 1
            game.state.chart[game.quadrant.x][game.quadrant.y].starbase -= 1
            game.state.basekl += 1
@@ -1444,7 +1426,7 @@ def torpedo(course, dispersion, origin, number, nburst):
            game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = None
            game.iplnet.pclass = "destroyed"
            game.iplnet = None
-           invalidate(game.plnet)
+           game.plnet.invalidate()
            game.quad[w.x][w.y] = IHDOT
            if game.landed:
                # captain perishes on planet 
@@ -1457,7 +1439,7 @@ def torpedo(course, dispersion, origin, number, nburst):
            game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = None
            game.iplnet.pclass = "destroyed"
            game.iplnet = None
-           invalidate(game.plnet)
+           game.plnet.invalidate()
            game.quad[w.x][w.y] = IHDOT
            if game.landed:
                # captain perishes on planet 
@@ -1503,7 +1485,7 @@ def torpedo(course, dispersion, origin, number, nburst):
            return None
        elif iquad == IHT:  # Hit a Tholian 
            h1 = 700.0 + randrange(100) - \
-               1000.0 * distance(w, origin) * math.fabs(math.sin(bullseye-angle))
+               1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
            h1 = math.fabs(h1)
            if h1 >= 600:
                game.quad[w.x][w.y] = IHDOT
@@ -1534,7 +1516,7 @@ def torpedo(course, dispersion, origin, number, nburst):
        game.quad[jw.x][jw.y]=iquad
        prout(_(" displaced by blast to Sector %s ") % jw)
        for ll in range(len(game.enemies)):
-           game.enemies[ll].kdist = game.enemies[ll].kavgd = distance(game.sector,game.enemies[ll].kloc)
+           game.enemies[ll].kdist = game.enemies[ll].kavgd = (game.sector-game.enemies[ll].kloc).distance()
         game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
        return None
     skip(1)
@@ -1562,7 +1544,7 @@ def fry(hit):
     for (i, j) in enumerate(cdam):
        proutn(device[j])
         if skipcount % 3 == 2 and i < len(cdam)-1:
-            skip()
+            skip(1)
         skipcount += 1
         if i < len(cdam)-1:
             proutn(_(" and "))
@@ -1590,7 +1572,7 @@ def attack(torps_ok):
        game.neutz = False
        return
     # commanders get a chance to tac-move towards you 
-    if (((game.comhere or game.ishere) and not game.justin) or game.skill == SKILL_EMERITUS) and torps_ok:
+    if (((game.quadrant in game.state.kcmdr or game.state.kscmdr==game.quadrant) and not game.justin) or game.skill == SKILL_EMERITUS) and torps_ok:
        moveklings()
     # if no enemies remain after movement, we're done 
     if len(game.enemies)==0 or (len(game.enemies)==1 and thing == game.quadrant and not thing.angry):
@@ -1626,10 +1608,11 @@ def attack(torps_ok):
            if game.condition == "docked":
                continue; # Don't waste the effort! 
            attempt = True; # Attempt to attack 
-           dustfac = 0.8 + randreal(0.5)
+           dustfac = randreal(0.8, 0.85)
            hit = enemy.kpower*math.pow(dustfac,enemy.kavgd)
            enemy.kpower *= 0.75
        else: # Enemy uses photon torpedo 
+           #course2 = (enemy.kloc-game.sector).bearing()
            course = 1.90985*math.atan2(game.sector.y-enemy.kloc.y, enemy.kloc.x-game.sector.x)
            hit = 0
            proutn(_("***TORPEDO INCOMING"))
@@ -1641,7 +1624,7 @@ def attack(torps_ok):
            dispersion = (randreal()+randreal())*0.5 - 0.5
            dispersion += 0.002*enemy.kpower*dispersion
            hit = torpedo(course, dispersion, origin=enemy.kloc, number=1, nburst=1)
-           if (game.state.remkl + game.state.remcom + game.state.nscrem)==0:
+           if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
                finish(FWON); # Klingons did themselves in! 
            if game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova or game.alldone:
                return # Supernova or finished 
@@ -1741,31 +1724,24 @@ def deadkl(w, type, mv):
         game.state.galaxy[game.quadrant.x][game.quadrant.y].klingons -= 1
         game.klhere -= 1
         if type == IHC:
-            game.comhere = False
-            for i in range(game.state.remcom):
-                if game.state.kcmdr[i] == game.quadrant:
-                    break
-            game.state.kcmdr[i] = game.state.kcmdr[game.state.remcom]
-            game.state.kcmdr[game.state.remcom].x = 0
-            game.state.kcmdr[game.state.remcom].y = 0
-            game.state.remcom -= 1
+            game.state.kcmdr.remove(game.quadrant)
             unschedule(FTBEAM)
-            if game.state.remcom != 0:
-                schedule(FTBEAM, expran(1.0*game.incom/game.state.remcom))
+            if game.state.kcmdr:
+                schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
             if is_scheduled(FCDBAS) and game.battle == game.quadrant:
                 unschedule(FCDBAS)    
         elif type ==  IHK:
             game.state.remkl -= 1
         elif type ==  IHS:
             game.state.nscrem -= 1
-            game.ishere = False
-            game.state.kscmdr.x = game.state.kscmdr.y = game.isatb = 0
+            game.state.kscmdr.invalidate()
+            game.isatb = 0
             game.iscate = False
             unschedule(FSCMOVE)
             unschedule(FSCDBAS)
     # For each kind of enemy, finish message to player 
     prout(_(" destroyed."))
-    if (game.state.remkl + game.state.remcom + game.state.nscrem)==0:
+    if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
        return
     game.recompute()
     # Remove enemy ship from arrays describing local conditions
@@ -1776,20 +1752,19 @@ def deadkl(w, type, mv):
     return
 
 def targetcheck(w):
-    # Return None if target is invalid 
+    # Return None if target is invalid, otherwise return a course angle
     if not VALID_SECTOR(w.x, w.y):
        huh()
        return None
-    deltx = 0.1*(w.y - game.sector.y)
-    delty = 0.1*(w.x - game.sector.x)
-    if deltx==0 and delty== 0:
+    delta = 0.1*(w - game.sector)
+    if delta.x==0 and delta.y== 0:
        skip(1)
        prout(_("Spock-  \"Bridge to sickbay.  Dr. McCoy,"))
        prout(_("  I recommend an immediate review of"))
        prout(_("  the Captain's psychological profile.\""))
        scanner.chew()
        return None
-    return 1.90985932*math.atan2(deltx, delty)
+    return delta.bearing()
 
 def photon():
     # launch photon torpedo
@@ -1844,17 +1819,17 @@ def photon():
        if key != IHREAL:
            huh()
            return
-       targ[i].x = scanner.real
+       targ[i].x = scanner.int()
        key = scanner.next()
        if key != IHREAL:
            huh()
            return
-       targ[i].y = scanner.real
+       targ[i].y = scanner.int()
        course[i] = targetcheck(targ[i])
         if course[i] == None:
            return
     scanner.chew()
-    if i == 1 and key == IHEOL:
+    if i == 0 and key == IHEOL:
        # prompt for each one 
        for i in range(n):
            proutn(_("Target sector for torpedo number %d- ") % (i+1))
@@ -1862,12 +1837,12 @@ def photon():
            if key != IHREAL:
                huh()
                return
-           targ[i].x = int(scanner.real-0.5)
+           targ[i].x = scanner.int()
            key = scanner.next()
            if key != IHREAL:
                huh()
                return
-           targ[i].y = int(scanner.real-0.5)
+           targ[i].y = scanner.int()
            scanner.chew()
             course[i] = targetcheck(targ[i])
             if course[i] == None:
@@ -1897,7 +1872,7 @@ def photon():
        torpedo(course[i], dispersion, origin=game.sector, number=i, nburst=n)
        if game.alldone or game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
            return
-    if (game.state.remkl + game.state.remcom + game.state.nscrem)==0:
+    if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
        finish(FWON);
 
 def overheat(rpow):
@@ -1949,6 +1924,7 @@ def hittem(hits):
     nenhr2 = len(game.enemies); kk=0
     w = coord()
     skip(1)
+    print "Hits are:", hits
     for (k, wham) in enumerate(hits):
        if wham==0:
            continue
@@ -1977,7 +1953,7 @@ def hittem(hits):
        skip(1)
        if kpow == 0:
            deadkl(w, ienm, w)
-           if (game.state.remkl + game.state.remcom + game.state.nscrem)==0:
+           if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
                finish(FWON);           
            if game.alldone:
                return
@@ -2333,10 +2309,10 @@ def events():
         # Adjust finish time to time of tractor beaming 
         fintim = game.state.date+game.optime
         attack(torps_ok=False)
-        if game.state.remcom <= 0:
+        if not game.state.kcmdr:
             unschedule(FTBEAM)
         else: 
-            schedule(FTBEAM, game.optime+expran(1.5*game.intime/game.state.remcom))
+            schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
 
     def destroybase():
         # Code merges here for any commander destroying base 
@@ -2345,11 +2321,11 @@ def events():
         if game.battle == game.quadrant:
             game.state.chart[game.battle.x][game.battle.y].starbase = False
             game.quad[game.base.x][game.base.y] = IHDOT
-            game.base.x=game.base.y=0
+            game.base.invalidate()
             newcnd()
             skip(1)
             prout(_("Spock-  \"Captain, I believe the starbase has been destroyed.\""))
-        elif game.state.rembase != 1 and communicating():
+        elif game.state.baseq and communicating():
             # Get word via subspace radio 
             announce()
             skip(1)
@@ -2362,16 +2338,13 @@ def events():
             game.state.chart[game.battle.x][game.battle.y].starbase = False
         # Remove Starbase from galaxy 
         game.state.galaxy[game.battle.x][game.battle.y].starbase = False
-        for i in range(1, game.state.rembase+1):
-            if game.state.baseq[i] == game.battle:
-                game.state.baseq[i] = game.state.baseq[game.state.rembase]
-        game.state.rembase -= 1
+        game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
         if game.isatb == 2:
             # reinstate a commander's base attack 
             game.battle = hold
             game.isatb = 0
         else:
-            invalidate(game.battle)
+            game.battle.invalidate()
 
     if idebug:
        prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
@@ -2408,7 +2381,7 @@ def events():
        xtime = datemin-game.state.date
        game.state.date = datemin
        # Decrement Federation resources and recompute remaining time 
-       game.state.remres -= (game.state.remkl+4*game.state.remcom)*xtime
+       game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
         game.recompute()
        if game.state.remtime <=0:
            finish(FDEPLETE)
@@ -2468,19 +2441,19 @@ def events():
                  (game.torps < 5 or damaged(DPHOTON))):
                # Tractor-beam her! 
                istract = ictbeam = True
-                tractorbeam(distance(game.state.kscmdr, game.quadrant))
+                tractorbeam((game.state.kscmdr-game.quadrant).distance())
            else:
                return
        elif evcode == FTBEAM: # Tractor beam 
-            if game.state.remcom == 0:
+            if not game.state.kcmdr:
                 unschedule(FTBEAM)
                 continue
-            i = randrange(game.state.remcom)
-            yank = distance(game.state.kcmdr[i], game.quadrant)
+            i = randrange(len(game.state.kcmdr))
+            yank = (game.state.kcmdr[i]-game.quadrant).distance()
             if istract or game.condition == "docked" or yank == 0:
                 # Drats! Have to reschedule 
                 schedule(FTBEAM, 
-                         game.optime + expran(1.5*game.intime/game.state.remcom))
+                         game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
                 continue
             ictbeam = True
             tractorbeam(yank)
@@ -2489,21 +2462,17 @@ def events():
            game.state.snap = True
            schedule(FSNAP, expran(0.5 * game.intime))
        elif evcode == FBATTAK: # Commander attacks starbase 
-           if game.state.remcom==0 or game.state.rembase==0:
+           if not game.state.kcmdr or not game.state.baseq:
                # no can do 
                unschedule(FBATTAK)
                unschedule(FCDBAS)
                 continue
-           i = 0
-           for j in range(game.state.rembase):
-               for k in range(game.state.remcom):
-                   if game.state.baseq[j] == game.state.kcmdr[k] and \
-                       not game.state.baseq[j] == game.quadrant and \
-                        not game.state.baseq[j] == game.state.kscmdr:
-                       i = 1
-               if i == 1:
-                   continue
-           if j>game.state.rembase:
+            try:
+                for ibq in game.state.baseq:
+                   for cmdr in game.state.kcmdr: 
+                       if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
+                           raise "foundit"
+            except "foundit":
                # no match found -- try later 
                schedule(FBATTAK, expran(0.3*game.intime))
                unschedule(FCDBAS)
@@ -2536,14 +2505,16 @@ def events():
        elif evcode == FCDBAS: # Commander succeeds in destroying base 
            if evcode==FCDBAS:
                unschedule(FCDBAS)
+                if not game.state.baseq() \
+                       or not game.state.galaxy[game.battle.x][game.battle.y].starbase:
+                   game.battle.invalidate()
+                    continue
                # find the lucky pair 
-               for i in range(game.state.remcom):
-                   if game.state.kcmdr[i] == game.battle: 
+               for cmdr in game.state.kcmdr:
+                   if cmdr == game.battle: 
                        break
-               if i > game.state.remcom or game.state.rembase == 0 or \
-                   not game.state.galaxy[game.battle.x][game.battle.y].starbase:
+                else:
                    # No action to take after all 
-                   invalidate(game.battle)
                    continue
             destroybase()
        elif evcode == FSCMOVE: # Supercommander moves 
@@ -2803,19 +2774,15 @@ def nova(nov):
                     prout(_(" destroyed."))
                     game.iplnet.pclass = "destroyed"
                     game.iplnet = None
-                    invalidate(game.plnet)
+                    game.plnet.invalidate()
                     if game.landed:
                         finish(FPNOVA)
                         return
                     game.quad[neighbor.x][neighbor.y] = IHDOT
                 elif iquad == IHB: # Destroy base 
                     game.state.galaxy[game.quadrant.x][game.quadrant.y].starbase = False
-                    for i in range(game.state.rembase):
-                        if game.state.baseq[i] == game.quadrant: 
-                            break
-                    game.state.baseq[i] = game.state.baseq[game.state.rembase]
-                    game.state.rembase -= 1
-                    invalidate(game.base)
+                    game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
+                    game.base.invalidate()
                     game.state.basekl += 1
                     newcnd()
                     crmena(True, IHB, "sector", neighbor)
@@ -2936,13 +2903,12 @@ def supernova(induced, w=None):
        prouts(_("***RED ALERT!  RED ALERT!"))
        skip(1)
        prout(_("***Incipient supernova detected at Sector %s") % ns)
-       if square(ns.x-game.sector.x) + square(ns.y-game.sector.y) <= 2.1:
+       if (ns.x-game.sector.x)**2 + (ns.y-game.sector.y)**2 <= 2.1:
            proutn(_("Emergency override attempts t"))
            prouts("***************")
            skip(1)
            stars()
            game.alldone = True
-
     # destroy any Klingons in supernovaed quadrant 
     kldead = game.state.galaxy[nq.x][nq.y].klingons
     game.state.galaxy[nq.x][nq.y].klingons = 0
@@ -2952,17 +2918,12 @@ def supernova(induced, w=None):
        game.iscate = False
        unschedule(FSCMOVE)
        unschedule(FSCDBAS)
-    if game.state.remcom:
-       maxloop = game.state.remcom
-       for l in range(maxloop):
-           if game.state.kcmdr[l] == nq:
-               game.state.kcmdr[l] = game.state.kcmdr[game.state.remcom]
-               invalidate(game.state.kcmdr[game.state.remcom])
-               game.state.remcom -= 1
-               kldead -= 1
-               if game.state.remcom==0:
-                   unschedule(FTBEAM)
-               break
+    survivors = filter(lambda w: w != nq, game.state.kcmdr)
+    comkills = len(game.state.kcmdr) - len(survivors)
+    game.state.kcmdr = survivors
+    kldead -= comkills
+    if not game.state.kcmdr:
+        unschedule(FTBEAM)
     game.state.remkl -= kldead
     # destroy Romulans and planets in supernovaed quadrant 
     nrmdead = game.state.galaxy[nq.x][nq.y].romulans
@@ -2970,18 +2931,11 @@ def supernova(induced, w=None):
     game.state.nromrem -= nrmdead
     # Destroy planets 
     for loop in range(game.inplan):
-       if game.state.planets[loop].w == nq:
+       if game.state.planets[loop].quadrant == nq:
            game.state.planets[loop].pclass = "destroyed"
            npdead += 1
-    # Destroy any base in supernovaed quadrant 
-    if game.state.rembase:
-       maxloop = game.state.rembase
-       for loop in range(maxloop):
-           if game.state.baseq[loop] == nq:
-               game.state.baseq[loop] = game.state.baseq[game.state.rembase]
-               invalidate(game.state.baseq[game.state.rembase])
-               game.state.rembase -= 1
-               break
+    # Destroy any base in supernovaed quadrant
+    game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
     # If starship caused supernova, tally up destruction 
     if induced:
        game.state.starkl += game.state.galaxy[nq.x][nq.y].stars
@@ -2991,7 +2945,7 @@ def supernova(induced, w=None):
     if game.quadrant == nq or communicating():
        game.state.galaxy[nq.x][nq.y].supernova = True
     # If supernova destroys last Klingons give special message 
-    if (game.state.remkl + game.state.remcom + game.state.nscrem)==0 and not nq == game.quadrant:
+    if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
        skip(2)
        if not induced:
            prout(_("Lucky you!"))
@@ -3071,7 +3025,7 @@ def killrate():
         return 0
     else:
         starting = (game.inkling + game.incom + game.inscom)
-        remaining = (game.state.remkl + game.state.remcom + game.state.nscrem)
+        remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
         return (starting - remaining)/elapsed
 
 def badpoints():
@@ -3161,7 +3115,7 @@ def finish(ifin):
        prout(_("conquered.  Your starship is now Klingon property,"))
        prout(_("and you are put on trial as a war criminal.  On the"))
        proutn(_("basis of your record, you are "))
-       if (game.state.remkl + game.state.remcom + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
+       if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
            prout(_("acquitted."))
            skip(1)
            prout(_("LIVE LONG AND PROSPER."))
@@ -3274,9 +3228,9 @@ def finish(ifin):
     elif game.ship == IHE:
        game.ship = IHF
     game.alive = False
-    if (game.state.remkl + game.state.remcom + game.state.nscrem) != 0:
+    if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
        goodies = game.state.remres/game.inresor
-       baddies = (game.state.remkl + 2.0*game.state.remcom)/(game.inkling+2.0*game.incom)
+       baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
        if goodies/baddies >= randreal(1.0, 1.5):
            prout(_("As a result of your actions, a treaty with the Klingon"))
            prout(_("Empire has been signed. The terms of the treaty are"))
@@ -3300,7 +3254,7 @@ def score():
     # compute player's score 
     timused = game.state.date - game.indate
     iskill = game.skill
-    if (timused == 0 or (game.state.remkl + game.state.remcom + game.state.nscrem) != 0) and timused < 5.0:
+    if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
        timused = 5.0
     perdate = killrate()
     ithperd = 500*perdate + 0.5
@@ -3316,7 +3270,7 @@ def score():
     if not game.gamewon:
        game.state.nromrem = 0 # None captured if no win
     iscore = 10*(game.inkling - game.state.remkl) \
-             + 50*(game.incom - game.state.remcom) \
+             + 50*(game.incom - len(game.state.kcmdr)) \
              + ithperd + iwon \
              + 20*(game.inrom - game.state.nromrem) \
              + 200*(game.inscom - game.state.nscrem) \
@@ -3335,9 +3289,9 @@ def score():
     if game.inkling - game.state.remkl:
        prout(_("%6d ordinary Klingons destroyed        %5d") %
              (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
-    if game.incom - game.state.remcom:
+    if game.incom - len(game.state.kcmdr):
        prout(_("%6d Klingon commanders destroyed       %5d") %
-             (game.incom - game.state.remcom, 50*(game.incom - game.state.remcom)))
+             (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
     if game.inscom - game.state.nscrem:
        prout(_("%6d Super-Commander destroyed          %5d") %
              (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
@@ -3707,13 +3661,13 @@ def warble():
        #nosound()
         pass
 
-def tracktorpedo(w, step, i, n, iquad):
+def tracktorpedo(origin, w, step, i, n, iquad):
     "Torpedo-track animation." 
     if not game.options & OPTION_CURSES:
        if step == 1:
            if n != 1:
                skip(1)
-               proutn(_("Track for torpedo number %d-  ") % i)
+               proutn(_("Track for %s torpedo number %d-  ") % (game.quad[origin.x][origin.y],i+1))
            else:
                skip(1)
                proutn(_("Torpedo track- "))
@@ -3775,16 +3729,16 @@ def imove(novapush):
     def no_quad_change():
         # No quadrant change -- compute new average enemy distances 
         game.quad[game.sector.x][game.sector.y] = game.ship
-        if len(game.enemies):
-            for m in range(len(game.enemies)):
-                finald = distance(w, game.enemies[m].kloc)
-                game.enemies[m].kavgd = 0.5 * (finald+game.enemies[m].kdist)
-                game.enemies[m].kdist = finald
+        if game.enemies:
+            for enemy in game.enemies:
+                finald = (w-enemy.kloc).distance()
+                enemy.kavgd = 0.5 * (finald + enemy.kdist)
+                enemy.kdist = finald
             game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
             if not game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
                 attack(torps_ok=False)
-            for m in range(len(game.enemies)):
-                game.enemies[m].kavgd = game.enemies[m].kdist
+            for enemy in game.enemies:
+                enemy.kavgd = enemy.kdist
         newcnd()
         drawmaps(0)
         setwnd(message_window)
@@ -3823,9 +3777,9 @@ def imove(novapush):
                # Don't do it if being pushed by Nova 
                if len(game.enemies) != 0 and not novapush:
                    newcnd()
-                   for m in range(len(game.enemies)):
-                       finald = distance(w, game.enemies[m].kloc)
-                       game.enemies[m].kavgd = 0.5 * (finald + game.enemies[m].kdist)
+                   for enemy in game.enemies:
+                       finald = (w - enemy.kloc).distance()
+                       enemy.kavgd = 0.5 * (finald + enemy.kdist)
                    #
                    # Stas Sergeev added the condition
                    # that attacks only happen if Klingons
@@ -3888,7 +3842,7 @@ def imove(novapush):
            if iquad != IHDOT:
                # object encountered in flight path 
                stopegy = 50.0*game.dist/game.optime
-               game.dist = distance(game.sector, w) / (QUADSIZE * 1.0)
+               game.dist = (game.sector - w).distance() / (QUADSIZE * 1.0)
                 if iquad in (IHT, IHK, IHC, IHS, IHR, IHQUEST):
                    game.sector = w
                     for enemy in game.enemies:
@@ -3938,7 +3892,7 @@ def imove(novapush):
                 # We're here!
                no_quad_change()
                 return
-       game.dist = distance(game.sector, w) / (QUADSIZE * 1.0)
+       game.dist = (game.sector - w).distance() / (QUADSIZE * 1.0)
        game.sector = w
     final = game.sector
     no_quad_change()
@@ -3953,7 +3907,7 @@ def dock(verbose):
     if game.inorbit:
        prout(_("You must first leave standard orbit."))
        return
-    if not is_valid(game.base) or abs(game.sector.x-game.base.x) > 1 or abs(game.sector.y-game.base.y) > 1:
+    if not game.base.is_valid() or abs(game.sector.x-game.base.x) > 1 or abs(game.sector.y-game.base.y) > 1:
        crmshp()
        prout(_(" not adjacent to base."))
        return
@@ -4089,8 +4043,9 @@ def getcourse(isprobe, akey):
            else:
                prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
         # the actual deltas get computed here
-       deltax = dquad.y-game.quadrant.y + 0.1*(dsect.x-game.sector.y)
-       deltay = game.quadrant.x-dquad.x + 0.1*(game.sector.x-dsect.y)
+        delta = coord()
+       delta.x = dquad.y-game.quadrant.y + 0.1*(dsect.x-game.sector.y)
+       delta.y = game.quadrant.x-dquad.x + 0.1*(game.sector.x-dsect.y)
     else: # manual 
        while key == IHEOL:
            proutn(_("X and Y displacements- "))
@@ -4101,22 +4056,22 @@ def getcourse(isprobe, akey):
        if key != IHREAL:
            huh()
            return False
-       deltax = scanner.real
+       delta.x = scanner.real
        key = scanner.next()
        if key != IHREAL:
            huh()
            return False
-       deltay = scanner.real
+       delta.y = scanner.real
     # Check for zero movement 
-    if deltax == 0 and deltay == 0:
+    if delta.x == 0 and delta.y == 0:
        scanner.chew()
        return False
     if itemp == "verbose" and not isprobe:
        skip(1)
        prout(_("Helmsman Sulu- \"Aye, Sir.\""))
     # Course actually laid in.
-    game.dist = math.sqrt(deltax*deltax + deltay*deltay)
-    game.direc = math.atan2(deltax, deltay)*1.90985932
+    game.dist = delta.distance()
+    game.direc = delta.bearing()
     if game.direc < 0.0:
        game.direc += 12.0
     scanner.chew()
@@ -4227,7 +4182,7 @@ def warp(timewarp):
     if game.warpfac > 6.0:
        # Decide if engine damage will occur
         # ESR: Seems wrong. Probability of damage goes *down* with distance? 
-       prob = game.dist*square(6.0-game.warpfac)/66.666666666
+       prob = game.dist*(6.0-game.warpfac)**2/66.666666666
        if prob > randreal():
            blooey = True
            game.dist = randreal(game.dist)
@@ -4405,7 +4360,7 @@ def atover(igrab):
        # Repeat if another snova
         if not game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
             break
-    if (game.state.remkl + game.state.remcom + game.state.nscrem)==0: 
+    if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0: 
        finish(FWON) # Snova killed remaining enemy. 
 
 def timwrp():
@@ -4417,8 +4372,8 @@ def timwrp():
              int(game.state.date-game.snapsht.date))
        game.state = game.snapsht
        game.state.snap = False
-       if game.state.remcom:
-           schedule(FTBEAM, expran(game.intime/game.state.remcom))
+       if len(game.state.kcmdr):
+           schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
            schedule(FBATTAK, expran(0.3*game.intime))
        schedule(FSNOVA, expran(0.5*game.intime))
        # next snapshot will be sooner 
@@ -4429,7 +4384,7 @@ def timwrp():
        game.isatb = 0
        unschedule(FCDBAS)
        unschedule(FSCDBAS)
-       invalidate(game.battle)
+       game.battle.invalidate()
 
        # Make sure Galileo is consistant -- Snapshot may have been taken
         # when on planet, which would give us two Galileos! 
@@ -4543,7 +4498,6 @@ def probe():
 def mayday():
     # yell for help from nearest starbase 
     # There's more than one way to move in this game! 
-    line = 0
     scanner.chew()
     # Test for conditions which prevent calling for help 
     if game.condition == "docked":
@@ -4552,7 +4506,7 @@ def mayday():
     if damaged(DRADIO):
        prout(_("Subspace radio damaged."))
        return
-    if game.state.rembase==0:
+    if not game.state.baseq:
        prout(_("Lt. Uhura-  \"Captain, I'm not getting any response from Starbase.\""))
        return
     if game.landed:
@@ -4564,16 +4518,15 @@ def mayday():
     game.nhelp += 1
     if game.base.x!=0:
        # There's one in this quadrant 
-       ddist = distance(game.base, game.sector)
+       ddist = (game.base - game.sector).distance()
     else:
        ddist = FOREVER
-       for m in range(game.state.rembase):
-           xdist = QUADSIZE * distance(game.state.baseq[m], game.quadrant)
+        for ibq in game.state.baseq:
+           xdist = QUADSIZE * (ibq - game.quadrant).distance()
            if xdist < ddist:
                ddist = xdist
-               line = m
        # Since starbase not in quadrant, set up new quadrant 
-       game.quadrant = game.state.baseq[line]
+       game.quadrant = ibq
        newqad(True)
     # dematerialize starship 
     game.quad[game.sector.x][game.sector.y]=IHDOT
@@ -4587,7 +4540,7 @@ def mayday():
            # found one -- finish up 
             game.sector = w
            break
-    if not is_valid(game.sector):
+    if not game.sector.is_valid():
        prout(_("You have been lost in space..."))
        finish(FMATERIALIZE)
        return
@@ -4671,7 +4624,7 @@ def abandon():
        prouts(_("***ALL HANDS ABANDON SHIP!"))
        skip(2)
        prout(_("Captain and crew escape in shuttle craft."))
-       if game.state.rembase==0:
+       if not game.state.baseq:
            # Oops! no place to go... 
            finish(FABANDN)
            return
@@ -4695,7 +4648,7 @@ def abandon():
        game.nprobes = 0 # No probes 
        prout(_("You are captured by Klingons and released to"))
        prout(_("the Federation in a prisoner-of-war exchange."))
-       nb = randrange(game.state.rembase)
+       nb = randrange(len(game.state.baseq))
        # Set up quadrant and position FQ adjacient to base 
        if not game.quadrant == game.state.baseq[nb]:
            game.quadrant = game.state.baseq[nb]
@@ -4764,7 +4717,7 @@ def survey():
            iknow = True
            if idebug and game.state.planets[i].known=="unknown":
                proutn("(Unknown) ")
-           proutn(_("Quadrant %s") % game.state.planets[i].w)
+           proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
            proutn(_("   class "))
            proutn(game.state.planets[i].pclass)
            proutn("   ")
@@ -4786,7 +4739,7 @@ def orbit():
     if damaged(DWARPEN) and damaged(DIMPULS):
        prout(_("Both warp and impulse engines damaged."))
        return
-    if not is_valid(game.plnet) or abs(game.sector.x-game.plnet.x) > 1 or abs(game.sector.y-game.plnet.y) > 1:
+    if not game.plnet.is_valid() or abs(game.sector.x-game.plnet.x) > 1 or abs(game.sector.y-game.plnet.y) > 1:
        crmshp()
        prout(_(" not adjacent to planet."))
        skip(1)
@@ -5140,7 +5093,7 @@ def deathray():
        while len(game.enemies) > 0:
            deadkl(game.enemies[1].kloc, game.quad[game.enemies[1].kloc.x][game.enemies[1].kloc.y],game.enemies[1].kloc)
        prout(_("Ensign Chekov-  \"Congratulations, Captain!\""))
-       if (game.state.remkl + game.state.remcom + game.state.nscrem) == 0:
+       if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
            finish(FWON)    
        if (game.options & OPTION_PLAIN) == 0:
            prout(_("Spock-  \"Captain, I believe the `Experimental Death Ray'"))
@@ -5233,23 +5186,23 @@ def report():
     if game.tourn:
        prout(_("This is tournament game %d.") % game.tourn)
     prout(_("Your secret password is \"%s\"") % game.passwd)
-    proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + game.state.remcom + game.state.nscrem)), 
+    proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)), 
           (game.inkling + game.incom + game.inscom)))
-    if game.incom - game.state.remcom:
-       prout(_(", including %d Commander%s.") % (game.incom - game.state.remcom, (_("s"), "")[(game.incom - game.state.remcom)==1]))
+    if game.incom - len(game.state.kcmdr):
+       prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
     elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
        prout(_(", but no Commanders."))
     else:
        prout(".")
     if game.skill > SKILL_FAIR:
        prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
-    if game.state.rembase != game.inbase:
+    if len(game.state.baseq) != game.inbase:
        proutn(_("There "))
-       if game.inbase-game.state.rembase==1:
+       if game.inbase-len(game.state.baseq)==1:
            proutn(_("has been 1 base"))
        else:
-           proutn(_("have been %d bases") % (game.inbase-game.state.rembase))
-       prout(_(" destroyed, %d remaining.") % game.state.rembase)
+           proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
+       prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
     else:
        prout(_("There are %d bases.") % game.inbase)
     if communicating() or game.iseenit:
@@ -5449,7 +5402,7 @@ def status(req=0):
        prstat(_("Shields"), s+data)
     if not req or req == 9:
         prstat(_("Klingons Left"), "%d" \
-               % (game.state.remkl + game.state.remcom + game.state.nscrem))
+               % (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem))
     if not req or req == 10:
        if game.options & OPTION_WORLDS:
            plnet = game.state.galaxy[game.quadrant.x][game.quadrant.y].planet
@@ -5536,8 +5489,8 @@ def eta():
     if not VALID_QUADRANT(w1.x, w1.y) or not VALID_SECTOR(w2.x, w2.y):
        huh()
        return
-    game.dist = math.sqrt(square(w1.y-game.quadrant.y+0.1*(w2.y-game.sector.y))+
-               square(w1.x-game.quadrant.x+0.1*(w2.x-game.sector.x)))
+    game.dist = math.sqrt((w1.y-game.quadrant.y+0.1*(w2.y-game.sector.y))**2+
+               (w1.x-game.quadrant.x+0.1*(w2.x-game.sector.x))**2)
     wfl = False
     if prompt:
        prout(_("Answer \"no\" if you don't know the value:"))
@@ -5568,7 +5521,7 @@ def eta():
        prout(_("Captain, certainly you can give me one of these."))
     while True:
        scanner.chew()
-       ttime = (10.0*game.dist)/square(twarp)
+       ttime = (10.0*game.dist)/twarp**2
        tpower = game.dist*twarp*twarp*twarp*(game.shldup+1)
        if tpower >= game.energy:
            prout(_("Insufficient energy, sir."))
@@ -5793,24 +5746,6 @@ def setup():
            quad.starbase = False
            quad.supernova = False
            quad.status = "secure"
-    # Initialize times for extraneous events
-    schedule(FSNOVA, expran(0.5 * game.intime))
-    schedule(FTBEAM, expran(1.5 * (game.intime / game.state.remcom)))
-    schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
-    schedule(FBATTAK, expran(0.3*game.intime))
-    unschedule(FCDBAS)
-    if game.state.nscrem:
-       schedule(FSCMOVE, 0.2777)
-    else:
-       unschedule(FSCMOVE)
-    unschedule(FSCDBAS)
-    unschedule(FDSPROB)
-    if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
-       schedule(FDISTR, expran(1.0 + game.intime))
-    else:
-       unschedule(FDISTR)
-    unschedule(FENSLV)
-    unschedule(FREPRO)
     # Starchart is functional but we've never seen it
     game.lastchart = FOREVER
     # Put stars in the galaxy
@@ -5832,7 +5767,7 @@ def setup():
             # so it did them in the opposite order.
             for j in range(1, i):
                # Improved placement algorithm to spread out bases
-               distq = w.distance(game.state.baseq[j])
+               distq = (w - game.state.baseq[j]).distance()
                if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
                    contflag = True
                    if idebug:
@@ -5843,7 +5778,7 @@ def setup():
                        prout("=== Saving base #%d, close to #%d" % (i, j))
             if not contflag:
                 break
-       game.state.baseq[i] = w
+       game.state.baseq.append(w)
        game.state.galaxy[w.x][w.y].starbase = True
        game.state.chart[w.x][w.y].starbase = True
     # Position ordinary Klingon Battle Cruisers
@@ -5866,7 +5801,7 @@ def setup():
         if krem <= 0:
             break
     # Position Klingon Commander Ships
-    for i in range(1, game.incom+1):
+    for i in range(game.incom):
         while True:
             w = randplace(GALSIZE)
            if (game.state.galaxy[w.x][w.y].klingons or withprob(0.25)) and \
@@ -5875,7 +5810,7 @@ def setup():
                    not w in game.state.kcmdr[:i]:
                 break
        game.state.galaxy[w.x][w.y].klingons += 1
-       game.state.kcmdr[i] = w
+       game.state.kcmdr.append(w)
     # Locate planets in galaxy
     for i in range(game.inplan):
         while True:
@@ -5883,7 +5818,7 @@ def setup():
             if game.state.galaxy[w.x][w.y].planet == None:
                 break
         new = planet()
-       new.w = w
+       new.quadrant = w
         new.crystals = "absent"
        if (game.options & OPTION_WORLDS) and i < NINHAB:
            new.pclass = "M"    # All inhabited planets are class M
@@ -5911,6 +5846,24 @@ def setup():
                 break
        game.state.kscmdr = w
        game.state.galaxy[w.x][w.y].klingons += 1
+    # Initialize times for extraneous events
+    schedule(FSNOVA, expran(0.5 * game.intime))
+    schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
+    schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
+    schedule(FBATTAK, expran(0.3*game.intime))
+    unschedule(FCDBAS)
+    if game.state.nscrem:
+       schedule(FSCMOVE, 0.2777)
+    else:
+       unschedule(FSCMOVE)
+    unschedule(FSCDBAS)
+    unschedule(FDSPROB)
+    if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
+       schedule(FDISTR, expran(1.0 + game.intime))
+    else:
+       unschedule(FDISTR)
+    unschedule(FENSLV)
+    unschedule(FREPRO)
     # Place thing (in tournament game, we don't want one!)
     global thing
     if game.tourn is None:
@@ -5990,7 +5943,7 @@ def choose():
            return True
         if scanner.sees("regular"):
            break
-       proutn(_("What is \"%s\"?"), scanner.token)
+       proutn(_("What is \"%s\"?") % scanner.token)
        scanner.chew()
     while game.length==0 or game.skill==SKILL_NONE:
        if scanner.next() == IHALPHA:
@@ -6044,8 +5997,7 @@ def choose():
 
     # Use parameters to generate initial values of things
     game.damfac = 0.5 * game.skill
-    game.state.rembase = randrange(BASEMIN, BASEMAX+1)
-    game.inbase = game.state.rembase
+    game.inbase = randrange(BASEMIN, BASEMAX+1)
     game.inplan = 0
     if game.options & OPTION_PLANETS:
        game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
@@ -6056,14 +6008,11 @@ def choose():
     game.state.remtime = 7.0 * game.length
     game.intime = game.state.remtime
     game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
-    game.incom = int(game.skill + 0.0625*game.inkling*randreal())
-    game.state.remcom = min(10, game.incom)
-    game.incom = game.state.remcom
+    game.incom = min(10, int(game.skill + 0.0625*game.inkling*randreal()))
     game.state.remres = (game.inkling+4*game.incom)*game.intime
     game.inresor = game.state.remres
     if game.inkling > 50:
-        game.state.rembase += 1
-       game.inbase = game.state.rembase
+        game.state.inbase += 1
     return False
 
 def dropin(iquad=None):
@@ -6096,8 +6045,6 @@ def newqad(shutup):
     w = coord()
     game.justin = True
     game.klhere = 0
-    game.comhere = False
-    game.ishere = False
     game.irhere = 0
     game.iplnet = 0
     game.neutz = False
@@ -6125,12 +6072,11 @@ def newqad(shutup):
        for i in range(game.klhere):
             newkling()
        # If we need a commander, promote a Klingon
-       for i in range(game.state.remcom):
-           if game.state.kcmdr[i] == game.quadrant:
+        for cmdr in game.state.kcmdr:
+           if cmdr == game.quadrant:
                 e = game.enemies[game.klhere-1]
                 game.quad[e.kloc.x][e.kloc.y] = IHC
                 e.kpower = randreal(950,1350) + 50.0*game.skill
-                game.comhere = True
                break   
        # If we need a super-commander, promote a Klingon
        if game.quadrant == game.state.kscmdr:
@@ -6138,7 +6084,6 @@ def newqad(shutup):
            game.quad[e.kloc.x][e.kloc.y] = IHS
            e.kpower = randreal(1175.0,  1575.0) + 125.0*game.skill
            game.iscate = (game.state.remkl > 1)
-           game.ishere = True
     # Put in Romulans if needed
     for i in range(game.klhere, len(game.enemies)):
         enemy(IHR, loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
@@ -6571,7 +6516,7 @@ class sstscanner:
         self.real = 0.0
         self.token = ''
         # Fill the token quue if nothing here
-        while self.inqueue == None:
+        while not self.inqueue:
             line = cgetline()
             if curwnd==prompt_window:
                 clrscr()
@@ -6616,7 +6561,7 @@ class sstscanner:
         return s.startswith(self.token)
     def int(self):
         # Round token value to nearest integer
-        return int(round(scanner.real + 0.5))
+        return int(round(scanner.real))
 
 def ja():
     # yes-or-no confirmation