import fcntl import math import os import random import subprocess import xml.sax.saxutils from PIL import Image, ImageColor, ImageDraw try: from ctf import teams except: import sys path = '/home/pflarr/repos/gctf/' sys.path.append(path) from ctf import teams import Tank class Pflanzarr: FRAME_DELAY = 15 SPACING = 150 backgroundColor = '#ffffff' def __init__(self, dir, difficulty='easy'): """Initialize a new game of Pflanzarr. @param dir: The data directory.""" assert difficulty in ('easy', 'medium', 'hard') # Setup the game environment self._setupDirectories(dir) # Figure out what game number this is. self._gameNum = self._getGameNum() self._gameDir = os.path.join(self._resultsDir, str(self._gameNum)) if not os.path.exists(self._gameDir): os.mkdir(self._gameDir) tmpPlayers = os.listdir(self._playerDir) players = [] for p in tmpPlayers: p = unquote(p) if not (p.startswith('.') or p.endswith('#') or p.endswith('~')) and p in teams.teams: players.append(p) AIs = {} for player in players: AIs[player] = open(os.path.join(self._playerDir, player)).read() defaultAIs = self._getDefaultAIs(dir, difficulty) assert len(players) >= 1, "There must be at least one player." # The one is added to ensure that there is at least one defaultAI bot. size = math.sqrt(len(players) + 1) if int(size) != size: size = size + 1 size = int(size) if size < 2: size = 2 self._board = (size*self.SPACING, size*self.SPACING) while len(players) < size**2: players.append('#default') self._tanks = [] for i in range(size): for j in range(size): startX = i*self.SPACING + self.SPACING/2 startY = j*self.SPACING + self.SPACING/2 player = random.choice(players) players.remove(player) if player == '#default': color = '#a0a0a0' else: color = team.teams[player][1] tank = Tank.Tank( player, (startX, startY), color, self._board, testMode=True) if player == '#default': tank.program(random.choice(defaultAIs)) else: tank.program(AIs[player]) self._tanks.append(tank) # We only want to make these once, so we do it here. self._tanksByX = list(self._tanks) self._tanksByY = list(self._tanks) self._deadTanks = set() def run(self, maxTurns=None): print "Starting new game with %d players." % len(self._tanks) kills = {} for tank in self._tanks: kills[tank] = set() turn = 0 lastTurns = 3 while ((maxTurns is None) or turn < maxTurns) and lastTurns > 0: if len(self._tanks) - len(self._deadTanks) < 2: lastTurns = lastTurns - 1 image = Image.new('RGB', self._board) draw = ImageDraw.Draw(image) draw.rectangle(((0,0), self._board), fill=self.backgroundColor) near = self._getNear() deadThisTurn = set() liveTanks = set(self._tanks).difference(self._deadTanks) for tank in liveTanks: # Shoot now, if we said to shoot last turn dead = tank.fire( near[tank] ) kills[tank] = kills[tank].union(dead) self._killTanks(dead, 'Shot by %s' % tank.name) for tank in liveTanks: # We also check for collisions here, while we're at it. dead = tank.sense( near[tank] ) kills[tank] = kills[tank].union(dead) self._killTanks(dead, 'Collision') # Draw the explosions for tank in self._deadTanks: tank.draw(image) # Draw the live tanks. for tank in self._tanksByX: # Have the tank run its program, move, etc. tank.draw(image) # Have the live tanks do their turns for tank in self._tanksByX: tank.execute() fileName = os.path.join(self._imageDir, '%05d.ppm' % turn) image.save(fileName, 'PPM') turn = turn + 1 # Removes tanks from their own kill lists. for tank in kills: if tank in kills[tank]: kills[tank].remove(tank) self._saveResults(kills) for tank in self._tanks: self._outputErrors(tank) self._makeMovie() def _killTanks(self, tanks, reason): for tank in tanks: if tank in self._tanksByX: self._tanksByX.remove(tank) if tank in self._tanksByY: self._tanksByY.remove(tank) tank.die(reason) self._deadTanks = self._deadTanks.union(tanks) def _saveResults(self, kills): """Choose a winner. In case of a tie, live tanks prevail, in case of further ties, a winner is chosen at random. This outputs the winner to the winners file and outputs a results table html file.""" resultsFile = open(os.path.join(self._gameDir, 'results.html'), 'w') winnerFile = open(os.path.join(self._dir, 'winner'),'w') tanks = list(self._tanks) def winSort(t1, t2): """Sort by # of kill first, then by life status.""" result = cmp(len(kills[t1]), len(kills[t2])) if result != 0: return result if t1.isDead and not t2.isDead: return -1 elif not t1.isDead and t2.isDead: return 1 else: return 0 tanks.sort(winSort, reverse=1) # Get the list of potential winners winners = [] for i in range(len(tanks)): if len( kills[tanks[0]] ) == len( kills[tanks[i]] ) and \ tanks[0].isDead == tanks[i].isDead: winners.append(tanks[i]) else: break winner = random.choice(winners) html = ['
', 'Team | Kills | Cause of Death'] for tank in tanks: if tank is winner: rowStyle = 'style="color:red;"' else: rowStyle = '' html.append(' |
---|---|---|
%s | %d | %s' % (rowStyle, xml.sax.saxutils.escape(tank.name), len(kills[tank]), xml.sax.saxutils.escape(tank.deathReason))) html.append(' |