<commit_before>import random
import sys
import math

class Preprocessor():
    def makeRobotStartAtZero(self, filename, firstLocation=8):
        with open(filename, 'r') as inputFile:
            fileAsList = inputFile.readlines()
            lastLocation = len(fileAsList)-1
            startPos = fileAsList[firstLocation].split()
            startX = float(startPos[2])
            startY = float(startPos[3])
            for i in range(firstLocation, lastLocation):
                coordinates = fileAsList[i].split()
                coordinates[2] = str(float(coordinates[2]) - startX)
                coordinates[3] = str(float(coordinates[3]) - startY)
                fileAsList[i] = "\t".join(coordinates)+"\n"
            inputFile.close()

        with open(filename, 'w') as outputFile:
            outputFile.write("".join(fileAsList))
            outputFile.close()

    def addRandomStartingPoint(self, filename, firstLocation=8, arenaXsize=5, arenaYsize=5):
        xStart = random.uniform(0,arenaXsize)
        yStart = random.uniform(0,arenaYsize)

        with open(filename, 'r') as inputFile:
            fileAsList = inputFile.readlines()
            lastLocation = len(fileAsList)-1
            for i in range(firstLocation, lastLocation):
                coordinates = fileAsList[i].split()
                coordinates[2] = str(float(coordinates[2]) + xStart)
                coordinates[3] = str(float(coordinates[3]) + yStart)
                fileAsList[i] = "\t".join(coordinates)+"\n"
            inputFile.close()

        with open(filename, 'w') as outputFile:
            outputFile.write("".join(fileAsList))
            outputFile.close()

    def forceStep(val, step):
        a = val/step
        b = math.floor(a)
        c = b * step
        return c

    def correctBirth(self, coordinates, birthX, birthY, birthTime, endTime, step):
        coordinates[1] = self.forceStep(float(coordinates[1]) + birthTime, step)
        if (coordinates[1] > endTime):
            return False
        coordinates[2] = float(coordinates[2]) + birthX
        coordinates[3] = float(coordinates[3]) + birthY
        return coordinates

    def correctArenaBouncy(self, coordinates, arenaX, arenaY):
        #TODO: implement bouncy
        pass

    def correctArenaInfinite(self, coordinates, arenaX, arenaY):
        if coordinates[2] < 0:
            coordinates[2] = float(coordinates[2]) + arenaX
        if coordinates[2] > arenaX:
            coordinates[2] = float(coordinates[2]) - arenaX
        if coordinates[3] < 0:
            coordinates[3] = float(coordinates[3]) + arenaY
        if coordinates[3] > arenaY:
            coordinates[3] = float(coordinates[3]) - arenaY
        return coordinates

    def correctArena(self, coordinates, arenaX, arenaY, arenaType):
        if (arenaType == "i"):
            return self.correctArenaInfinite(coordinates, arenaX, arenaY)
        else:
            return self.correctArenaBouncy(coordinates, arenaX, arenaY)

    def stringify(self, coordinates):
        coordinates[1] = str(coordinates[1])
        coordinates[2] = str(coordinates[2])
        coordinates[3] = str(coordinates[3])
        return coordinates

    def addStartingPointArenaAndTime(self, filename, vox_preamble=8, arenaX=5, arenaY=5, arenaType="i", birthX=0, birthY=0, birthTime=0, endTime=120, timestep=0.002865):
        with open(filename, 'r') as inputFile:
            fileAsList = inputFile.readlines()
            lastLocation = len(fileAsList)-1
            out = []
            for i in range(vox_preamble, lastLocation):
                coordinates = fileAsList[i].split()

                # birth correction
                coordinates = self.correctBirth(coordinates, birthX, birthY, birthTime, endTime, timestep)
                if (coordinates == False): # then the individual lived past the time limit
                    break

                # arena correction
                coordinates = self.correctArena(coordinates, arenaX, arenaY, arenaType)

                # convert the elements into strings again
                coordinates = self.stringify(coordinates)

                # fileAsList[i] = "\t".join(coordinates)+"\n"
                out.append("\t".join(coordinates)+"\n")

            inputFile.close()

        with open(filename, 'w') as outputFile:
            # outputFile.write("".join(fileAsList))
            outputFile.write("".join(out))
            outputFile.close()

    def addParentStartingPoint(self, filename, firstLocation=8, arenaXsize=5, arenaYsize=5, birthX=0, birthY=0):
        with open(filename, 'r') as inputFile:
            fileAsList = inputFile.readlines()
            lastLocation = len(fileAsList)-1
            for i in range(firstLocation, lastLocation):
                coordinates = fileAsList[i].split()
                coordinates[2] = str(float(coordinates[2]) + birthX)
                coordinates[3] = str(float(coordinates[3]) + birthY)
                fileAsList[i] = "\t".join(coordinates)+"\n"
            inputFile.close()

        with open(filename, 'w') as outputFile:
            outputFile.write("".join(fileAsList))
            outputFile.close()

    def correctArenaBoundaries(self, filename, firstLocation=8, arenaXsize=5, arenaYsize=5):
        with open(filename, 'r') as inputFile:
            fileAsList = inputFile.readlines()
            lastLocation = len(fileAsList)-1
            for i in range(firstLocation, lastLocation):
                coordinates = fileAsList[i].split()
                if float(coordinates[2]) < 0:
                    coordinates[2] = str(float(coordinates[2]) + arenaXsize)
                if float(coordinates[2]) > arenaXsize:
                    coordinates[2] = str(float(coordinates[2]) - arenaXsize)
                if float(coordinates[3]) < 0:
                    coordinates[3] = str(float(coordinates[3]) + arenaYsize)
                if float(coordinates[3]) > arenaYsize:
                    coordinates[3] = str(float(coordinates[3]) - arenaYsize)
                fileAsList[i] = "\t".join(coordinates)+"\n"
            inputFile.close()

        with open('testOutput.trace', 'w') as outputFile:
            outputFile.write("".join(fileAsList))
            outputFile.close()

if __name__ == "__main__": #if the script is being run standalone
    #parse command line parameters and make sure there is at least 1 parameter,
    #and this parameter is a filename for a trace file
    #and we can read and write to that trace file
    filename = sys.argv[1]
    if len(sys.argv)>2:
        firstLocation = int(sys.argv[2])
    else: firstLocation = 8
    if len(sys.argv)>3:
        arenaXsize = int(sys.argv[3])
    else: arenaXsize = 5
    if len(sys.argv)>4:
        arenaYsize = int(sys.argv[4])
    else: arenaYsize = 5
    if len(sys.argv)>5:
        birthX = int(sys.argv[5])
    else: birthX = 0
    if len(sys.argv)>6:
        birthY = int(sys.argv[6])
    else: birthY = 0

    pp = Preprocessor()
    pp.makeRobotStartAtZero(filename, firstLocation)
    pp.addRandomStartingPoint(filename, firstLocation, arenaXsize, arenaYsize)
    pp.correctArenaBoundaries(filename, firstLocation, arenaXsize, arenaYsize)

<commit_msg>fix for parameter count<commit_after>import random
import sys
import math

class Preprocessor():
    def makeRobotStartAtZero(self, filename, firstLocation=8):
        with open(filename, 'r') as inputFile:
            fileAsList = inputFile.readlines()
            lastLocation = len(fileAsList)-1
            startPos = fileAsList[firstLocation].split()
            startX = float(startPos[2])
            startY = float(startPos[3])
            for i in range(firstLocation, lastLocation):
                coordinates = fileAsList[i].split()
                coordinates[2] = str(float(coordinates[2]) - startX)
                coordinates[3] = str(float(coordinates[3]) - startY)
                fileAsList[i] = "\t".join(coordinates)+"\n"
            inputFile.close()

        with open(filename, 'w') as outputFile:
            outputFile.write("".join(fileAsList))
            outputFile.close()

    def addRandomStartingPoint(self, filename, firstLocation=8, arenaXsize=5, arenaYsize=5):
        xStart = random.uniform(0,arenaXsize)
        yStart = random.uniform(0,arenaYsize)

        with open(filename, 'r') as inputFile:
            fileAsList = inputFile.readlines()
            lastLocation = len(fileAsList)-1
            for i in range(firstLocation, lastLocation):
                coordinates = fileAsList[i].split()
                coordinates[2] = str(float(coordinates[2]) + xStart)
                coordinates[3] = str(float(coordinates[3]) + yStart)
                fileAsList[i] = "\t".join(coordinates)+"\n"
            inputFile.close()

        with open(filename, 'w') as outputFile:
            outputFile.write("".join(fileAsList))
            outputFile.close()

    def forceStep(self, val, step):
        a = val/step
        b = math.floor(a)
        c = b * step
        return c

    def correctBirth(self, coordinates, birthX, birthY, birthTime, endTime, step):
        coordinates[1] = self.forceStep(float(coordinates[1]) + birthTime, step)
        if (coordinates[1] > endTime):
            return False
        coordinates[2] = float(coordinates[2]) + birthX
        coordinates[3] = float(coordinates[3]) + birthY
        return coordinates

    def correctArenaBouncy(self, coordinates, arenaX, arenaY):
        #TODO: implement bouncy
        pass

    def correctArenaInfinite(self, coordinates, arenaX, arenaY):
        if coordinates[2] < 0:
            coordinates[2] = float(coordinates[2]) + arenaX
        if coordinates[2] > arenaX:
            coordinates[2] = float(coordinates[2]) - arenaX
        if coordinates[3] < 0:
            coordinates[3] = float(coordinates[3]) + arenaY
        if coordinates[3] > arenaY:
            coordinates[3] = float(coordinates[3]) - arenaY
        return coordinates

    def correctArena(self, coordinates, arenaX, arenaY, arenaType):
        if (arenaType == "i"):
            return self.correctArenaInfinite(coordinates, arenaX, arenaY)
        else:
            return self.correctArenaBouncy(coordinates, arenaX, arenaY)

    def stringify(self, coordinates):
        coordinates[1] = str(coordinates[1])
        coordinates[2] = str(coordinates[2])
        coordinates[3] = str(coordinates[3])
        return coordinates

    def addStartingPointArenaAndTime(self, filename, vox_preamble=8, arenaX=5, arenaY=5, arenaType="i", birthX=0, birthY=0, birthTime=0, endTime=120, timestep=0.002865):
        with open(filename, 'r') as inputFile:
            fileAsList = inputFile.readlines()
            lastLocation = len(fileAsList)-1
            out = []
            for i in range(vox_preamble, lastLocation):
                coordinates = fileAsList[i].split()

                # birth correction
                coordinates = self.correctBirth(coordinates, birthX, birthY, birthTime, endTime, timestep)
                if (coordinates == False): # then the individual lived past the time limit
                    break

                # arena correction
                coordinates = self.correctArena(coordinates, arenaX, arenaY, arenaType)

                # convert the elements into strings again
                coordinates = self.stringify(coordinates)

                # fileAsList[i] = "\t".join(coordinates)+"\n"
                out.append("\t".join(coordinates)+"\n")

            inputFile.close()

        with open(filename, 'w') as outputFile:
            # outputFile.write("".join(fileAsList))
            outputFile.write("".join(out))
            outputFile.close()

    def addParentStartingPoint(self, filename, firstLocation=8, arenaXsize=5, arenaYsize=5, birthX=0, birthY=0):
        with open(filename, 'r') as inputFile:
            fileAsList = inputFile.readlines()
            lastLocation = len(fileAsList)-1
            for i in range(firstLocation, lastLocation):
                coordinates = fileAsList[i].split()
                coordinates[2] = str(float(coordinates[2]) + birthX)
                coordinates[3] = str(float(coordinates[3]) + birthY)
                fileAsList[i] = "\t".join(coordinates)+"\n"
            inputFile.close()

        with open(filename, 'w') as outputFile:
            outputFile.write("".join(fileAsList))
            outputFile.close()

    def correctArenaBoundaries(self, filename, firstLocation=8, arenaXsize=5, arenaYsize=5):
        with open(filename, 'r') as inputFile:
            fileAsList = inputFile.readlines()
            lastLocation = len(fileAsList)-1
            for i in range(firstLocation, lastLocation):
                coordinates = fileAsList[i].split()
                if float(coordinates[2]) < 0:
                    coordinates[2] = str(float(coordinates[2]) + arenaXsize)
                if float(coordinates[2]) > arenaXsize:
                    coordinates[2] = str(float(coordinates[2]) - arenaXsize)
                if float(coordinates[3]) < 0:
                    coordinates[3] = str(float(coordinates[3]) + arenaYsize)
                if float(coordinates[3]) > arenaYsize:
                    coordinates[3] = str(float(coordinates[3]) - arenaYsize)
                fileAsList[i] = "\t".join(coordinates)+"\n"
            inputFile.close()

        with open('testOutput.trace', 'w') as outputFile:
            outputFile.write("".join(fileAsList))
            outputFile.close()

if __name__ == "__main__": #if the script is being run standalone
    #parse command line parameters and make sure there is at least 1 parameter,
    #and this parameter is a filename for a trace file
    #and we can read and write to that trace file
    filename = sys.argv[1]
    if len(sys.argv)>2:
        firstLocation = int(sys.argv[2])
    else: firstLocation = 8
    if len(sys.argv)>3:
        arenaXsize = int(sys.argv[3])
    else: arenaXsize = 5
    if len(sys.argv)>4:
        arenaYsize = int(sys.argv[4])
    else: arenaYsize = 5
    if len(sys.argv)>5:
        birthX = int(sys.argv[5])
    else: birthX = 0
    if len(sys.argv)>6:
        birthY = int(sys.argv[6])
    else: birthY = 0

    pp = Preprocessor()
    pp.makeRobotStartAtZero(filename, firstLocation)
    pp.addRandomStartingPoint(filename, firstLocation, arenaXsize, arenaYsize)
    pp.correctArenaBoundaries(filename, firstLocation, arenaXsize, arenaYsize)

<|endoftext|>


<commit_before>import asyncio
import logging

logger = logging.getLogger(__name__)

class GameException(Exception):
    pass

class SquareException(GameException):
    pass

class WinnerException(GameException):
    pass

class HistoryException(GameException):
    pass

class Board:

    def __init__(self, width=8, height=8, players=4, bots=0):
        self.width = width
        self.height = height

        self.tasks = []
        self.listeners = []

        from .bot import Bot
        self.players = \
            [Player(self, i) for i in range(players - bots)] \
            + [Bot(self, i) for i in range(players - bots, players)]
        self.players_wheel = PlayersWheel(self.players)
        self.actual_player = next(self.players_wheel)

        squares = [[Square(self, x, y) for y in range(height)]
                                       for x in range(width)
                  ]
        for x, column in enumerate(squares):
            for y, square in enumerate(column):
                if x > 0:
                    square.neighbours['left'] = squares[x-1][y]
                if x < width - 1:
                    square.neighbours['right'] = squares[x+1][y]
                if y > 0:
                    square.neighbours['up'] = squares[x][y-1]
                if y < height - 1:
                    square.neighbours['down'] = squares[x][y+1]
        self.squares = squares

        self.history = [self.dump()]
        self.history_position = 0

    def __getitem__(self, index):
        if isinstance(index, tuple):
            try:
                column, row = index
                return self.squares[column][row]
            except IndexError:
                raise SquareException('bad coordinate', index)

        if isinstance(index, int):
            column = index // len(self.squares[0])
            if column >= len(self.squares):
                raise SquareException("there's not that many squares")
            row = index % len(self.squares[0])
            return self[column, row]

    def __iter__(self):
        return SquaresIterator(self)

    async def play(self, x, y):
        await self[x, y].increment()
        await self.process()

    async def process(self):
        while self.tasks:
            task = self.tasks.pop(0)
            await asyncio.wait([task])

        self.actual_player = next(self.players_wheel)

        self.history_position += 1
        self.history = self.history[:self.history_position]
        self.history.append(self.dump())

        if self.is_victory():
            raise WinnerException(self.actual_player)

    def is_victory(self):
        actives = sum(int(player.active) for player in self.players)
        if actives == 1:
            return True
        elif actives < 1:
            raise GameException('No active players')
        return False

    def dump(self):
        dump = ''
        for square in self:
            player_number = square.player.number if square.player else '-'
            dump += '%s%d' % (player_number, square.value)
        dump += '%s' % self.actual_player.number
        return dump

    def load(self, dump, soft=False):
        assert len(dump) == self.width * self.height * 2 + 1

        for sq_nr, square in enumerate(self):
            player_number = dump[2 * sq_nr]
            square.player = self.players[int(player_number)] \
                            if player_number != '-' else None
            square.value = int(dump[2 * sq_nr + 1])

        self.recalculate_players(soft)

        self.players_wheel.set_number(int(dump[-1]))
        self.actual_player = next(self.players_wheel)

    def recalculate_players(self, soft=False):
        for player in self.players:
            player.amount = 0
            player.active = True
        for square in self:
            if square.player:
                square.player.amount += square.value
        if not soft:
            for player in self.players:
                if player.amount <= 0:
                    player.active = False

    @property
    def overall_value(self):
        return sum(square.value for square in self)

    def history_jump(self, step):
        if 0 <= self.history_position + step < len(self.history):
            self.history_position += step
            soft = self.history_position <= len(self.players)
            self.load(self.history[self.history_position], soft)
        else:
            raise HistoryException('already at a corner')

class Square:

    def __init__(self, board, x, y):
        self.board = board
        self.x = x
        self.y = y

        self.neighbours = {}
        self.value = 0
        self.player = None

    def __repr__(self):
        return '<Square %d,%d>' % (self.x, self.y)

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            if self.x == other.x and self.y == other.y:
                return True
        return False

    def __getattr__(self, name):
        if name in self.neighbours:
            return self.neighbours[name]

    async def increment(self):
        if self.player and self.player != self.board.actual_player:
            raise SquareException('%s does not belong to %s'
                                  % (self, self.board.actual_player))
        if not self.player:
            self.player = self.board.actual_player

        self.value += 1
        self.player.amount += 1

        if self.value >= len(self.neighbours) and not self.board.is_victory():
            self.player.amount -= self.value
            self.value = 0

            for neighbour in self.neighbours.values():
                if neighbour.player and neighbour.player != self.player:
                    neighbour.player.amount -= neighbour.value
                    if neighbour.player.amount == 0:
                        neighbour.player.active = False
                    self.player.amount += neighbour.value

                neighbour.player = self.player

                self.board.tasks.append(
                    asyncio.ensure_future(neighbour.increment())
                )

        for listener in self.board.listeners:
            listener.refresh_square(self)

    @property
    def color(self):
        if self.player:
            return self.player.color
        return 0

class Player:

    NAMES = ['Tesla', 'Lacrum', 'Loana', 'Tatra']

    def __init__(self, board, number, name=None):
        self.board = board
        self.number = number
        self.name = name or self.NAMES[self.number]
        self.amount = 0
        self.active = True

    def __repr__(self):
        return '<Player %s>' % self.name

    def __str__(self):
        return self.name

    @property
    def color(self):
        return self.number + 1

    @property
    def is_bot(self):
        return False

class SquaresIterator:
    def __init__(self, board):
        self.board = board
        self._iter_square = 0

    def __next__(self):
        try:
            square = self.board[self._iter_square]
            self._iter_square += 1
            return square
        except SquareException:
            raise StopIteration

class PlayersWheel:

    def __init__(self, players):
        self.players = players
        self._iter_player = 0

    def __next__(self):
        if self._iter_player >= len(self.players):
            self._iter_player = 0

        player = self.players[self._iter_player]
        self._iter_player += 1

        if player.active:
            return player
        else:
            # beware, might end as an infinite loop
            return next(self)

    def set_number(self, number):
        self._iter_player = number
<commit_msg>#17: expanding by LIFO, not FIFO.<commit_after>import asyncio
import logging

logger = logging.getLogger(__name__)

class GameException(Exception):
    pass

class SquareException(GameException):
    pass

class WinnerException(GameException):
    pass

class HistoryException(GameException):
    pass

class Board:

    def __init__(self, width=8, height=8, players=4, bots=0):
        self.width = width
        self.height = height

        self.tasks = []
        self.listeners = []

        from .bot import Bot
        self.players = \
            [Player(self, i) for i in range(players - bots)] \
            + [Bot(self, i) for i in range(players - bots, players)]
        self.players_wheel = PlayersWheel(self.players)
        self.actual_player = next(self.players_wheel)

        squares = [[Square(self, x, y) for y in range(height)]
                                       for x in range(width)
                  ]
        for x, column in enumerate(squares):
            for y, square in enumerate(column):
                if x > 0:
                    square.neighbours['left'] = squares[x-1][y]
                if x < width - 1:
                    square.neighbours['right'] = squares[x+1][y]
                if y > 0:
                    square.neighbours['up'] = squares[x][y-1]
                if y < height - 1:
                    square.neighbours['down'] = squares[x][y+1]
        self.squares = squares

        self.history = [self.dump()]
        self.history_position = 0

    def __getitem__(self, index):
        if isinstance(index, tuple):
            try:
                column, row = index
                return self.squares[column][row]
            except IndexError:
                raise SquareException('bad coordinate', index)

        if isinstance(index, int):
            column = index // len(self.squares[0])
            if column >= len(self.squares):
                raise SquareException("there's not that many squares")
            row = index % len(self.squares[0])
            return self[column, row]

    def __iter__(self):
        return SquaresIterator(self)

    async def play(self, x, y):
        await self[x, y].increment()
        await self.process()

    async def process(self):
        while self.tasks:
            task = self.tasks.pop(0)
            await asyncio.wait([task])

        self.actual_player = next(self.players_wheel)

        self.history_position += 1
        self.history = self.history[:self.history_position]
        self.history.append(self.dump())

        if self.is_victory():
            raise WinnerException(self.actual_player)

    def is_victory(self):
        actives = sum(int(player.active) for player in self.players)
        if actives == 1:
            return True
        elif actives < 1:
            raise GameException('No active players')
        return False

    def dump(self):
        dump = ''
        for square in self:
            player_number = square.player.number if square.player else '-'
            dump += '%s%d' % (player_number, square.value)
        dump += '%s' % self.actual_player.number
        return dump

    def load(self, dump, soft=False):
        assert len(dump) == self.width * self.height * 2 + 1

        for sq_nr, square in enumerate(self):
            player_number = dump[2 * sq_nr]
            square.player = self.players[int(player_number)] \
                            if player_number != '-' else None
            square.value = int(dump[2 * sq_nr + 1])

        self.recalculate_players(soft)

        self.players_wheel.set_number(int(dump[-1]))
        self.actual_player = next(self.players_wheel)

    def recalculate_players(self, soft=False):
        for player in self.players:
            player.amount = 0
            player.active = True
        for square in self:
            if square.player:
                square.player.amount += square.value
        if not soft:
            for player in self.players:
                if player.amount <= 0:
                    player.active = False

    @property
    def overall_value(self):
        return sum(square.value for square in self)

    def history_jump(self, step):
        if 0 <= self.history_position + step < len(self.history):
            self.history_position += step
            soft = self.history_position <= len(self.players)
            self.load(self.history[self.history_position], soft)
        else:
            raise HistoryException('already at a corner')

class Square:

    def __init__(self, board, x, y):
        self.board = board
        self.x = x
        self.y = y

        self.neighbours = {}
        self.value = 0
        self.player = None

    def __repr__(self):
        return '<Square %d,%d>' % (self.x, self.y)

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            if self.x == other.x and self.y == other.y:
                return True
        return False

    def __getattr__(self, name):
        if name in self.neighbours:
            return self.neighbours[name]

    async def increment(self):
        if self.player and self.player != self.board.actual_player:
            raise SquareException('%s does not belong to %s'
                                  % (self, self.board.actual_player))
        if not self.player:
            self.player = self.board.actual_player

        self.value += 1
        self.player.amount += 1

        if self.value >= len(self.neighbours) and not self.board.is_victory():
            self.player.amount -= self.value
            self.value = 0

            for neighbour in self.neighbours.values():
                if neighbour.player and neighbour.player != self.player:
                    neighbour.player.amount -= neighbour.value
                    if neighbour.player.amount == 0:
                        neighbour.player.active = False
                    self.player.amount += neighbour.value

                neighbour.player = self.player

                self.board.tasks.insert(
                    0,
                    asyncio.ensure_future(neighbour.increment())
                )

        for listener in self.board.listeners:
            listener.refresh_square(self)

    @property
    def color(self):
        if self.player:
            return self.player.color
        return 0

class Player:

    NAMES = ['Tesla', 'Lacrum', 'Loana', 'Tatra']

    def __init__(self, board, number, name=None):
        self.board = board
        self.number = number
        self.name = name or self.NAMES[self.number]
        self.amount = 0
        self.active = True

    def __repr__(self):
        return '<Player %s>' % self.name

    def __str__(self):
        return self.name

    @property
    def color(self):
        return self.number + 1

    @property
    def is_bot(self):
        return False

class SquaresIterator:
    def __init__(self, board):
        self.board = board
        self._iter_square = 0

    def __next__(self):
        try:
            square = self.board[self._iter_square]
            self._iter_square += 1
            return square
        except SquareException:
            raise StopIteration

class PlayersWheel:

    def __init__(self, players):
        self.players = players
        self._iter_player = 0

    def __next__(self):
        if self._iter_player >= len(self.players):
            self._iter_player = 0

        player = self.players[self._iter_player]
        self._iter_player += 1

        if player.active:
            return player
        else:
            # beware, might end as an infinite loop
            return next(self)

    def set_number(self, number):
        self._iter_player = number
<|endoftext|>


<commit_before>'''
if
The MIT License (MIT)

Copyright (c) 2014 NTHUOJ team

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
'''
from django.http import HttpResponse, HttpResponseBadRequest, Http404
from django.shortcuts import render, redirect
from django.core.exceptions import PermissionDenied
from django.contrib.auth.decorators import login_required
from django.core.servers.basehttp import FileWrapper

from users.models import User
from problem.models import Problem, Tag, Testcase
from problem.forms import ProblemForm
from utils import log_info, config_info
from problem.problem_info import *

import os
import json

logger = log_info.get_logger()

# Create your views here.
def problem(request):
    a = {'name': 'my_problem', 'pid': 1, 'pass': 60, 'not_pass': 40}
    b = {'name': 'all_problem', 'pid': 1, 'pass': 60, 'not_pass': 40}
    return render(request, 'problem/panel.html', {'my_problem':[a,a,a], 'all_problem':[a,a,a,b,b,b]})

def volume(request):
    problem_id=[]
    if Problem.objects.count() != 0:
        problems = Problem.objects.latest('id')
        volume_number = (problems.id - 1) // 100
        for i in range(1,volume_number + 2):
            start_id = ((i - 1) * 100 + 1)
            if problems.id < i * 100:
                end_id = problems.id
            else:
                end_id = i * 100
            problem_id.append(str(start_id) + ' ~ ' + str(end_id))

    return render(request, 'problem/volume.html', {'problem_id':problem_id})

def detail(request, pid):
    user = request.user
    try:
        problem = Problem.objects.get(pk=pid)
    except Problem.DoesNotExist:
        logger.warning('problem %s not found' % (pid))
        raise Http404('problem %s does not exist' % (pid))
    problem.testcase = get_testcase(problem)
    return render(request, 'problem/detail.html', {'problem': problem})

@login_required
def edit(request, pid=None):
    if pid is not None:
        is_new = False
        try:
            problem = Problem.objects.get(pk=pid)
            if not request.user.is_admin and request.user != problem.owner:
                logger.warning("user %s has no permission to edit problem %s" % (request.user, pid))
                raise PermissionDenied()
        except Problem.DoesNotExist:
            logger.warning("problem %s does not exist" % (pid))
            raise Http404("problem %s does not exist" % (pid))
        testcase = Testcase.objects.filter(problem=problem)
        tags = problem.tags.all()
    else:
        is_new = True
    if request.method == 'GET':
        if is_new:
            form = ProblemForm()
        else:
            form = ProblemForm(instance=problem)
    if request.method == 'POST':
        if is_new:
            form = ProblemForm(request.POST)
        else:
            form = ProblemForm(request.POST, instance=problem)
        if form.is_valid():
            problem = form.save()
            problem.description = request.POST['description']
            problem.input= request.POST['input_description']
            problem.output = request.POST['output_description']
            problem.sample_in = request.POST['sample_in']
            problem.sample_out = request.POST['sample_out']
            problem.save()
            file_ex = get_problem_file_extension(problem)
            if "special_judge_code" in request.FILES:
                with open('%s%s%s' % (SPECIAL_PATH, problem.pk, file_ex), 'w') as t_in:
                    for chunk in request.FILES['special_judge_code'].chunks():
                        t_in.write(chunk)
            if "partial_judge_code" in request.FILES:
                with open('%s%s%s' % (PARTIAL_PATH, problem.pk, file_ex), 'w') as t_in:
                    for chunk in request.FILES['partial_judge_code'].chunks():
                        t_in.write(chunk)
            logger.info('edit problem, pid = %d' % (problem.pk))
            return redirect('/problem/%d' % (problem.pk))
    if not request.user.is_admin:
        del form.fields['owner']
    if is_new:
        return render(request, 'problem/edit.html',
                    { 'form': form, 'owner': request.user, 'is_new': True })
    else:
        return render(request, 'problem/edit.html',
                  {'form': form, 'pid': pid, 'is_new': False,
                   'tags': tags, 'description': problem.description,
                   'input': problem.input, 'output': problem.output,
                   'sample_in': problem.sample_in, 'sample_out': problem.sample_out,
                   'testcase': testcase,
                   'path': {
                       'TESTCASE_PATH': TESTCASE_PATH,
                       'SPECIAL_PATH': SPECIAL_PATH,
                       'PARTIAL_PATH': PARTIAL_PATH, },
                   'has_special_judge_code': has_special_judge_code(problem),
                   'has_partial_judge_code': has_partial_judge_code(problem),
                   'file_ex': get_problem_file_extension(problem)})

@login_required
def tag(request, pid):
    if request.method == "POST":
        tag = request.POST['tag']
        try:
            problem = Problem.objects.get(pk=pid)
        except Problem.DoesNotExist:
            logger.warning("problem %s does not exist" % (pid))
            raise Http404("problem %s does not exist" % (pid))
        if not problem.tags.filter(tag_name=tag).exists():
            logger.info("add new tag '%s' to problem %s" % (tag, pid))
            new_tag, created = Tag.objects.get_or_create(tag_name=tag)
            problem.tags.add(new_tag)
            problem.save()
            return HttpResponse(json.dumps({'tag_id': new_tag.pk}),
                                content_type="application/json")
        return HttpRequestBadRequest()
    return HttpResponse()

@login_required
def delete_tag(request, pid, tag_id):
    try:
        problem = Problem.objects.get(pk=pid)
        tag = Tag.objects.get(pk=tag_id)
    except Problem.DoesNotExist:
        logger.warning("problem %s does not exist" % (pid))
        raise Http404("problem %s does not exist" % (pid))
    except Tag.DoesNotExist:
        logger.warning("tag %s does not exist" % (tag_id))
        raise Http404("tag %s does not exist" % (tag_id))
    if not request.user.is_admin and request.user != problem.owner:
        raise PermissionDenied()
    logger.info("tag %d deleted" % (tag.pk))
    problem.tags.remove(tag)
    return HttpResponse()

@login_required
def testcase(request, pid, tid=None):
    if request.method == 'POST':
        try:
            problem = Problem.objects.get(pk=pid)
        except Problem.DoesNotExist:
            logger.warning("problem %s does not exist" % (pid))
            raise Http404("problem %s does not exist" % (pid))
        if tid == None:
            testcase = Testcase()
            testcase.problem = problem
        else:
            try:
                testcase = Testcase.objects.get(pk=tid)
            except Testcase.DoesNotExist:
                logger.warning("testcase %s does not exist" % (tid))
                raise Http404("testcase %s does not exist" % (tid))
            if testcase.problem != problem:
                logger.warning("testcase %s does not belong to problem %s" % (tid, pid))
                raise Http404("testcase %s does not belong to problem %s" % (tid, pid))
        if 'time_limit' in request.POST:
            testcase.time_limit = request.POST['time_limit']
            testcase.memory_limit = request.POST['memory_limit']
            testcase.save()
            logger.info("testcase saved, tid = %s" % (testcase.pk))
        if 't_in' in request.FILES:
            TESTCASE_PATH = config_info.get_config('path', 'testcase_path')
            try:
                with open('%s%s.in' % (TESTCASE_PATH, testcase.pk), 'w') as t_in:
                    for chunk in request.FILES['t_in'].chunks():
                        t_in.write(chunk)
                    logger.info("testcase %s.in saved" % (testcase.pk))
                with open('%s%s.out' % (TESTCASE_PATH, testcase.pk), 'w') as t_out:
                    for chunk in request.FILES['t_out'].chunks():
                        t_out.write(chunk)
                    logger.info("testcase %s.out saved" % (testcase.pk))
            except IOError:
                logger.error("saving testcase error")
            return HttpResponse(json.dumps({'tid': testcase.pk}),
                                content_type="application/json")
    return HttpResponse()

@login_required
def delete_testcase(request, pid, tid):
    try:
        problem = Problem.objects.get(pk=pid)
        testcase = Testcase.objects.get(pk=tid)
    except Problem.DoesNotExist:
        logger.warning("problem %s does not exist" % (pid))
        raise Http404("problem %s does not exist" % (pid))
    except Testcase.DoesNotExist:
        logger.warning("testcase %s does not exist" % (tid))
        raise Http404("testcase %s does not exist" % (tid))
    if not request.user.is_admin and request.user != problem.owner:
        raise PermissionDenied
    logger.info("testcase %d deleted" % (testcase.pk))
    try:
        os.remove('%s%d.in' % (TESTCASE_PATH, testcase.pk))
        os.remove('%s%d.out' % (TESTCASE_PATH, testcase.pk))
    except IOError, OSError:
        logger.error("remove testcase %s error" % (testcase.pk))
    testcase.delete()
    return HttpResponse()

def preview(request):
    form = ProblemForm(request.GET)
    problem = form.save()
    problem.description = request.GET['description']
    problem.input= request.GET['input_description']
    problem.output = request.GET['output_description']
    problem.sample_in = request.GET['sample_in']
    problem.sample_out = request.GET['sample_out']
    return render(request, 'problem/preview.html', {'problem': problem, 'preview': True})

def download_testcase(request, filename):
    try:
        f = open(TESTCASE_PATH+filename, "r")
    except IOError:
        raise Http404()
    response = HttpResponse(FileWrapper(f), content_type="text/plain")
    response['Content-Disposition'] = 'attachment; filename=' + filename
    return response

<commit_msg>add testcase log<commit_after>'''
if
The MIT License (MIT)

Copyright (c) 2014 NTHUOJ team

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
'''
from django.http import HttpResponse, HttpResponseBadRequest, Http404
from django.shortcuts import render, redirect
from django.core.exceptions import PermissionDenied
from django.contrib.auth.decorators import login_required
from django.core.servers.basehttp import FileWrapper

from users.models import User
from problem.models import Problem, Tag, Testcase
from problem.forms import ProblemForm
from utils import log_info, config_info
from problem.problem_info import *

import os
import json

logger = log_info.get_logger()

# Create your views here.
def problem(request):
    a = {'name': 'my_problem', 'pid': 1, 'pass': 60, 'not_pass': 40}
    b = {'name': 'all_problem', 'pid': 1, 'pass': 60, 'not_pass': 40}
    return render(request, 'problem/panel.html', {'my_problem':[a,a,a], 'all_problem':[a,a,a,b,b,b]})

def volume(request):
    problem_id=[]
    if Problem.objects.count() != 0:
        problems = Problem.objects.latest('id')
        volume_number = (problems.id - 1) // 100
        for i in range(1,volume_number + 2):
            start_id = ((i - 1) * 100 + 1)
            if problems.id < i * 100:
                end_id = problems.id
            else:
                end_id = i * 100
            problem_id.append(str(start_id) + ' ~ ' + str(end_id))

    return render(request, 'problem/volume.html', {'problem_id':problem_id})

def detail(request, pid):
    user = request.user
    try:
        problem = Problem.objects.get(pk=pid)
    except Problem.DoesNotExist:
        logger.warning('problem %s not found' % (pid))
        raise Http404('problem %s does not exist' % (pid))
    problem.testcase = get_testcase(problem)
    return render(request, 'problem/detail.html', {'problem': problem})

@login_required
def edit(request, pid=None):
    if pid is not None:
        is_new = False
        try:
            problem = Problem.objects.get(pk=pid)
            if not request.user.is_admin and request.user != problem.owner:
                logger.warning("user %s has no permission to edit problem %s" % (request.user, pid))
                raise PermissionDenied()
        except Problem.DoesNotExist:
            logger.warning("problem %s does not exist" % (pid))
            raise Http404("problem %s does not exist" % (pid))
        testcase = Testcase.objects.filter(problem=problem)
        tags = problem.tags.all()
    else:
        is_new = True
    if request.method == 'GET':
        if is_new:
            form = ProblemForm()
        else:
            form = ProblemForm(instance=problem)
    if request.method == 'POST':
        if is_new:
            form = ProblemForm(request.POST)
        else:
            form = ProblemForm(request.POST, instance=problem)
        if form.is_valid():
            problem = form.save()
            problem.description = request.POST['description']
            problem.input= request.POST['input_description']
            problem.output = request.POST['output_description']
            problem.sample_in = request.POST['sample_in']
            problem.sample_out = request.POST['sample_out']
            problem.save()
            file_ex = get_problem_file_extension(problem)
            if "special_judge_code" in request.FILES:
                with open('%s%s%s' % (SPECIAL_PATH, problem.pk, file_ex), 'w') as t_in:
                    for chunk in request.FILES['special_judge_code'].chunks():
                        t_in.write(chunk)
            if "partial_judge_code" in request.FILES:
                with open('%s%s%s' % (PARTIAL_PATH, problem.pk, file_ex), 'w') as t_in:
                    for chunk in request.FILES['partial_judge_code'].chunks():
                        t_in.write(chunk)
            logger.info('edit problem, pid = %d' % (problem.pk))
            return redirect('/problem/%d' % (problem.pk))
    if not request.user.is_admin:
        del form.fields['owner']
    if is_new:
        return render(request, 'problem/edit.html',
                    { 'form': form, 'owner': request.user, 'is_new': True })
    else:
        return render(request, 'problem/edit.html',
                  {'form': form, 'pid': pid, 'is_new': False,
                   'tags': tags, 'description': problem.description,
                   'input': problem.input, 'output': problem.output,
                   'sample_in': problem.sample_in, 'sample_out': problem.sample_out,
                   'testcase': testcase,
                   'path': {
                       'TESTCASE_PATH': TESTCASE_PATH,
                       'SPECIAL_PATH': SPECIAL_PATH,
                       'PARTIAL_PATH': PARTIAL_PATH, },
                   'has_special_judge_code': has_special_judge_code(problem),
                   'has_partial_judge_code': has_partial_judge_code(problem),
                   'file_ex': get_problem_file_extension(problem)})

@login_required
def tag(request, pid):
    if request.method == "POST":
        tag = request.POST['tag']
        try:
            problem = Problem.objects.get(pk=pid)
        except Problem.DoesNotExist:
            logger.warning("problem %s does not exist" % (pid))
            raise Http404("problem %s does not exist" % (pid))
        if not problem.tags.filter(tag_name=tag).exists():
            logger.info("add new tag '%s' to problem %s" % (tag, pid))
            new_tag, created = Tag.objects.get_or_create(tag_name=tag)
            problem.tags.add(new_tag)
            problem.save()
            return HttpResponse(json.dumps({'tag_id': new_tag.pk}),
                                content_type="application/json")
        return HttpRequestBadRequest()
    return HttpResponse()

@login_required
def delete_tag(request, pid, tag_id):
    try:
        problem = Problem.objects.get(pk=pid)
        tag = Tag.objects.get(pk=tag_id)
    except Problem.DoesNotExist:
        logger.warning("problem %s does not exist" % (pid))
        raise Http404("problem %s does not exist" % (pid))
    except Tag.DoesNotExist:
        logger.warning("tag %s does not exist" % (tag_id))
        raise Http404("tag %s does not exist" % (tag_id))
    if not request.user.is_admin and request.user != problem.owner:
        raise PermissionDenied()
    logger.info("tag %d deleted" % (tag.pk))
    problem.tags.remove(tag)
    return HttpResponse()

@login_required
def testcase(request, pid, tid=None):
    if request.method == 'POST':
        try:
            problem = Problem.objects.get(pk=pid)
        except Problem.DoesNotExist:
            logger.warning("problem %s does not exist" % (pid))
            raise Http404("problem %s does not exist" % (pid))
        if tid == None:
            testcase = Testcase()
            testcase.problem = problem
        else:
            try:
                testcase = Testcase.objects.get(pk=tid)
            except Testcase.DoesNotExist:
                logger.warning("testcase %s does not exist" % (tid))
                raise Http404("testcase %s does not exist" % (tid))
            if testcase.problem != problem:
                logger.warning("testcase %s does not belong to problem %s" % (tid, pid))
                raise Http404("testcase %s does not belong to problem %s" % (tid, pid))
        if 'time_limit' in request.POST:
            testcase.time_limit = request.POST['time_limit']
            testcase.memory_limit = request.POST['memory_limit']
            testcase.save()
            logger.info("testcase saved, tid = %s by %s" % (testcase.pk, request.user))
        if 't_in' in request.FILES:
            TESTCASE_PATH = config_info.get_config('path', 'testcase_path')
            try:
                with open('%s%s.in' % (TESTCASE_PATH, testcase.pk), 'w') as t_in:
                    for chunk in request.FILES['t_in'].chunks():
                        t_in.write(chunk)
                    logger.info("testcase %s.in saved by %s" % (testcase.pk, request.user))
                with open('%s%s.out' % (TESTCASE_PATH, testcase.pk), 'w') as t_out:
                    for chunk in request.FILES['t_out'].chunks():
                        t_out.write(chunk)
                    logger.info("testcase %s.out saved by %s" % (testcase.pk, request.user))
            except IOError, OSError:
                logger.error("saving testcase error")
            return HttpResponse(json.dumps({'tid': testcase.pk}),
                                content_type="application/json")
    return HttpResponse()

@login_required
def delete_testcase(request, pid, tid):
    try:
        problem = Problem.objects.get(pk=pid)
        testcase = Testcase.objects.get(pk=tid)
    except Problem.DoesNotExist:
        logger.warning("problem %s does not exist" % (pid))
        raise Http404("problem %s does not exist" % (pid))
    except Testcase.DoesNotExist:
        logger.warning("testcase %s does not exist" % (tid))
        raise Http404("testcase %s does not exist" % (tid))
    if not request.user.is_admin and request.user != problem.owner:
        raise PermissionDenied
    logger.info("testcase %d deleted" % (testcase.pk))
    try:
        os.remove('%s%d.in' % (TESTCASE_PATH, testcase.pk))
        os.remove('%s%d.out' % (TESTCASE_PATH, testcase.pk))
    except IOError, OSError:
        logger.error("remove testcase %s error" % (testcase.pk))
    testcase.delete()
    logger.info("testcase %d deleted by %s" % (testcase.pk, request.user))
    return HttpResponse()

def preview(request):
    form = ProblemForm(request.GET)
    problem = form.save()
    problem.description = request.GET['description']
    problem.input= request.GET['input_description']
    problem.output = request.GET['output_description']
    problem.sample_in = request.GET['sample_in']
    problem.sample_out = request.GET['sample_out']
    return render(request, 'problem/preview.html', {'problem': problem, 'preview': True})

def download_testcase(request, filename):
    try:
        f = open(TESTCASE_PATH+filename, "r")
    except IOError:
        raise Http404()
    response = HttpResponse(FileWrapper(f), content_type="text/plain")
    response['Content-Disposition'] = 'attachment; filename=' + filename
    return response

<|endoftext|>


<commit_before># coding=utf-8
import zipfile
import re
import os
import hashlib
import json

from django.shortcuts import render
from django.db.models import Q, Count
from django.core.paginator import Paginator

from rest_framework.views import APIView

from django.conf import settings

from announcement.models import Announcement
from utils.shortcuts import (serializer_invalid_response, error_response,
                             success_response, paginate, rand_str, error_page)
from .serizalizers import (CreateProblemSerializer, EditProblemSerializer, ProblemSerializer,
                           ProblemTagSerializer, CreateProblemTagSerializer)
from .models import Problem, ProblemTag

def problem_page(request, problem_id):
    try:
        problem = Problem.objects.get(id=problem_id, visible=True)
    except Problem.DoesNotExist:
        return error_page(request, u"题目不存在")
    return render(request, "oj/problem/problem.html", {"problem": problem, "samples": json.loads(problem.samples)})

class ProblemTagAdminAPIView(APIView):
    def get(self, request):
        return success_response(ProblemTagSerializer(ProblemTag.objects.all(), many=True).data)

class ProblemAdminAPIView(APIView):
    def post(self, request):
        """
        题目发布json api接口
        ---
        request_serializer: CreateProblemSerializer
        response_serializer: ProblemSerializer
        """
        serializer = CreateProblemSerializer(data=request.data)
        if serializer.is_valid():
            data = serializer.data
            problem = Problem.objects.create(title=data["title"],
                                             description=data["description"],
                                             input_description=data["input_description"],
                                             output_description=data["output_description"],
                                             test_case_id=data["test_case_id"],
                                             source=data["source"],
                                             samples=json.dumps(data["samples"]),
                                             time_limit=data["time_limit"],
                                             memory_limit=data["memory_limit"],
                                             difficulty=data["difficulty"],
                                             created_by=request.user,
                                             hint=data["hint"])
            for tag in data["tags"]:
                try:
                    tag = ProblemTag.objects.get(name=tag)
                except ProblemTag.DoesNotExist:
                    tag = ProblemTag.objects.create(name=tag)
                problem.tags.add(tag)
            return success_response(ProblemSerializer(problem).data)
        else:
            return serializer_invalid_response(serializer)

    def put(self, request):
        """
        题目编辑json api接口
        ---
        request_serializer: EditProblemSerializer
        response_serializer: ProblemSerializer
        """
        serializer = EditProblemSerializer(data=request.data)
        if serializer.is_valid():
            data = serializer.data
            try:
                problem = Problem.objects.get(id=data["id"])
            except Problem.DoesNotExist:
                return error_response(u"该题目不存在！")

            problem.title = data["title"]
            problem.description = data["description"]
            problem.input_description = data["input_description"]
            problem.output_description = data["output_description"]
            problem.test_case_id = data["test_case_id"]
            problem.source = data["source"]
            problem.time_limit = data["time_limit"]
            problem.memory_limit = data["memory_limit"]
            problem.difficulty = data["difficulty"]
            problem.samples = json.dumps(data["samples"])
            problem.hint = data["hint"]
            problem.visible = data["visible"]

            # 删除原有的标签的对应关系
            problem.tags.remove(*problem.tags.all())
            # 重新添加所有的标签
            for tag in data["tags"]:
                try:
                    tag = ProblemTag.objects.get(name=tag)
                except ProblemTag.DoesNotExist:
                    tag = ProblemTag.objects.create(name=tag)
                problem.tags.add(tag)
            problem.save()
            return success_response(ProblemSerializer(problem).data)
        else:
            return serializer_invalid_response(serializer)

    def get(self, request):
        """
        题目分页json api接口
        ---
        response_serializer: ProblemSerializer
        """
        problem_id = request.GET.get("problem_id", None)
        if problem_id:
            try:
                problem = Problem.objects.get(id=problem_id)
                return success_response(ProblemSerializer(problem).data)
            except Problem.DoesNotExist:
                return error_response(u"题目不存在")
        problem = Problem.objects.all().order_by("-create_time")
        visible = request.GET.get("visible", None)
        if visible:
            problem = problem.filter(visible=(visible == "true"))
        keyword = request.GET.get("keyword", None)
        if keyword:
            problem = problem.filter(Q(title__contains=keyword) |
                                     Q(description__contains=keyword))

        return paginate(request, problem, ProblemSerializer)

class TestCaseUploadAPIView(APIView):
    def _is_legal_test_case_file_name(self, file_name):
        # 正整数开头的 .in 或者.out 结尾的
        regex = r"^[1-9]\d*\.(in|out)$"
        return re.compile(regex).match(file_name) is not None

    def post(self, request):
        if "file" not in request.FILES:
            return error_response(u"文件上传失败")

        f = request.FILES["file"]

        tmp_zip = "/tmp/" + rand_str() + ".zip"
        with open(tmp_zip, "wb") as test_case_zip:
            for chunk in f:
                test_case_zip.write(chunk)

        test_case_file = zipfile.ZipFile(tmp_zip, 'r')
        name_list = test_case_file.namelist()

        l = []

        # 如果文件是直接打包的，那么name_list 就是["1.in", "1.out"]这样的
        # 如果文件还有一层文件夹test_case，那么name_list就是["test_case/", "test_case/1.in", "test_case/1.out"]
        # 现在暂时只支持第一种，先判断一下是什么格式的

        # 第一种格式的
        if "1.in" in name_list and "1.out" in name_list:
            for file_name in name_list:
                if self._is_legal_test_case_file_name(file_name):
                    name = file_name.split(".")
                    # 有了.in 判断对应的.out 在不在
                    if name[1] == "in":
                        if (name[0] + ".out") in name_list:
                            l.append(file_name)
                        else:
                            return error_response(u"测试用例文件不完整，缺少" + name[0] + ".out")
                    else:
                        # 有了.out 判断对应的 .in 在不在
                        if (name[0] + ".in") in name_list:
                            l.append(file_name)
                        else:
                            return error_response(u"测试用例文件不完整，缺少" + name[0] + ".in")

            problem_test_dir = rand_str()
            test_case_dir = settings.TEST_CASE_DIR + problem_test_dir + "/"

            # 得到了合法的测试用例文件列表 然后去解压缩
            os.mkdir(test_case_dir)
            for name in l:
                f = open(test_case_dir + name, "wb")
                f.write(test_case_file.read(name).replace("\r\n", "\n"))
                f.close()
            l.sort()

            file_info = {"test_case_number": len(l) / 2, "test_cases": {}}

            # 计算输出文件的md5
            for i in range(len(l) / 2):
                md5 = hashlib.md5()
                f = open(test_case_dir + str(i + 1) + ".out", "r")
                while True:
                    data = f.read(2 ** 8)
                    if not data:
                        break
                    md5.update(data)

                file_info["test_cases"][str(i + 1)] = {"input_name": str(i + 1) + ".in",
                                                       "output_name": str(i + 1) + ".out",
                                                       "output_md5": md5.hexdigest(),
                                                       "output_size": os.path.getsize(test_case_dir + str(i + 1) + ".out")}
                # 写入配置文件
                open(test_case_dir + "info", "w").write(json.dumps(file_info))

            return success_response({"test_case_id": problem_test_dir,
                                     "file_list": {"input": l[0::2],
                                                   "output": l[1::2]}})
        else:
            return error_response(u"测试用例压缩文件格式错误，请保证测试用例文件在根目录下直接压缩")

def problem_list_page(request, page=1):
    # 正常情况
    problems = Problem.objects.filter(visible=True)

    # 搜索的情况
    keyword = request.GET.get("keyword", None)
    if keyword:
        problems = problems.filter(title__contains=keyword)

    # 按照标签筛选
    tag_text = request.GET.get("tag", None)
    if tag_text:
        try:
            tag = ProblemTag.objects.get(name=tag_text)
        except ProblemTag.DoesNotExist:
            return error_page(request, u"标签不存在")
        problems = tag.problem_set.all()

    paginator = Paginator(problems, 20)
    try:
        current_page = paginator.page(int(page))
    except Exception:
        return error_page(request, u"不存在的页码")

    previous_page = next_page = None

    try:
        previous_page = current_page.previous_page_number()
    except Exception:
        pass

    try:
        next_page = current_page.next_page_number()
    except Exception:
        pass

    # 右侧的公告列表
    announcements = Announcement.objects.filter(is_global=True, visible=True).order_by("-create_time")
    # 右侧标签列表 按照关联的题目的数量排序 排除题目数量为0的
    tags = ProblemTag.objects.annotate(problem_number=Count("problem")).filter(problem_number__gt=0).order_by("-problem_number")

    return render(request, "oj/problem/problem_list.html",
                  {"problems": current_page, "page": int(page),
                   "previous_page": previous_page, "next_page": next_page,
                   "keyword": keyword, "tag": tag_text,
                   "announcements": announcements, "tags": tags})
<commit_msg>用户上传测试用例文件过大时引发memoryERROR<commit_after># coding=utf-8
import zipfile
import re
import os
import hashlib
import json

from django.shortcuts import render
from django.db.models import Q, Count
from django.core.paginator import Paginator

from rest_framework.views import APIView

from django.conf import settings

from announcement.models import Announcement
from utils.shortcuts import (serializer_invalid_response, error_response,
                             success_response, paginate, rand_str, error_page)
from .serizalizers import (CreateProblemSerializer, EditProblemSerializer, ProblemSerializer,
                           ProblemTagSerializer, CreateProblemTagSerializer)
from .models import Problem, ProblemTag

def problem_page(request, problem_id):
    try:
        problem = Problem.objects.get(id=problem_id, visible=True)
    except Problem.DoesNotExist:
        return error_page(request, u"题目不存在")
    return render(request, "oj/problem/problem.html", {"problem": problem, "samples": json.loads(problem.samples)})

class ProblemTagAdminAPIView(APIView):
    def get(self, request):
        return success_response(ProblemTagSerializer(ProblemTag.objects.all(), many=True).data)

class ProblemAdminAPIView(APIView):
    def post(self, request):
        """
        题目发布json api接口
        ---
        request_serializer: CreateProblemSerializer
        response_serializer: ProblemSerializer
        """
        serializer = CreateProblemSerializer(data=request.data)
        if serializer.is_valid():
            data = serializer.data
            problem = Problem.objects.create(title=data["title"],
                                             description=data["description"],
                                             input_description=data["input_description"],
                                             output_description=data["output_description"],
                                             test_case_id=data["test_case_id"],
                                             source=data["source"],
                                             samples=json.dumps(data["samples"]),
                                             time_limit=data["time_limit"],
                                             memory_limit=data["memory_limit"],
                                             difficulty=data["difficulty"],
                                             created_by=request.user,
                                             hint=data["hint"])
            for tag in data["tags"]:
                try:
                    tag = ProblemTag.objects.get(name=tag)
                except ProblemTag.DoesNotExist:
                    tag = ProblemTag.objects.create(name=tag)
                problem.tags.add(tag)
            return success_response(ProblemSerializer(problem).data)
        else:
            return serializer_invalid_response(serializer)

    def put(self, request):
        """
        题目编辑json api接口
        ---
        request_serializer: EditProblemSerializer
        response_serializer: ProblemSerializer
        """
        serializer = EditProblemSerializer(data=request.data)
        if serializer.is_valid():
            data = serializer.data
            try:
                problem = Problem.objects.get(id=data["id"])
            except Problem.DoesNotExist:
                return error_response(u"该题目不存在！")

            problem.title = data["title"]
            problem.description = data["description"]
            problem.input_description = data["input_description"]
            problem.output_description = data["output_description"]
            problem.test_case_id = data["test_case_id"]
            problem.source = data["source"]
            problem.time_limit = data["time_limit"]
            problem.memory_limit = data["memory_limit"]
            problem.difficulty = data["difficulty"]
            problem.samples = json.dumps(data["samples"])
            problem.hint = data["hint"]
            problem.visible = data["visible"]

            # 删除原有的标签的对应关系
            problem.tags.remove(*problem.tags.all())
            # 重新添加所有的标签
            for tag in data["tags"]:
                try:
                    tag = ProblemTag.objects.get(name=tag)
                except ProblemTag.DoesNotExist:
                    tag = ProblemTag.objects.create(name=tag)
                problem.tags.add(tag)
            problem.save()
            return success_response(ProblemSerializer(problem).data)
        else:
            return serializer_invalid_response(serializer)

    def get(self, request):
        """
        题目分页json api接口
        ---
        response_serializer: ProblemSerializer
        """
        problem_id = request.GET.get("problem_id", None)
        if problem_id:
            try:
                problem = Problem.objects.get(id=problem_id)
                return success_response(ProblemSerializer(problem).data)
            except Problem.DoesNotExist:
                return error_response(u"题目不存在")
        problem = Problem.objects.all().order_by("-create_time")
        visible = request.GET.get("visible", None)
        if visible:
            problem = problem.filter(visible=(visible == "true"))
        keyword = request.GET.get("keyword", None)
        if keyword:
            problem = problem.filter(Q(title__contains=keyword) |
                                     Q(description__contains=keyword))

        return paginate(request, problem, ProblemSerializer)

class TestCaseUploadAPIView(APIView):
    def _is_legal_test_case_file_name(self, file_name):
        # 正整数开头的 .in 或者.out 结尾的
        regex = r"^[1-9]\d*\.(in|out)$"
        return re.compile(regex).match(file_name) is not None

    def post(self, request):
        if "file" not in request.FILES:
            return error_response(u"文件上传失败")

        f = request.FILES["file"]

        tmp_zip = "/tmp/" + rand_str() + ".zip"
        with open(tmp_zip, "wb") as test_case_zip:
            for chunk in f:
                test_case_zip.write(chunk)

        test_case_file = zipfile.ZipFile(tmp_zip, 'r')
        name_list = test_case_file.namelist()

        l = []

        # 如果文件是直接打包的，那么name_list 就是["1.in", "1.out"]这样的
        # 如果文件还有一层文件夹test_case，那么name_list就是["test_case/", "test_case/1.in", "test_case/1.out"]
        # 现在暂时只支持第一种，先判断一下是什么格式的

        # 第一种格式的
        if "1.in" in name_list and "1.out" in name_list:
            for file_name in name_list:
                if self._is_legal_test_case_file_name(file_name):
                    name = file_name.split(".")
                    # 有了.in 判断对应的.out 在不在
                    if name[1] == "in":
                        if (name[0] + ".out") in name_list:
                            l.append(file_name)
                        else:
                            return error_response(u"测试用例文件不完整，缺少" + name[0] + ".out")
                    else:
                        # 有了.out 判断对应的 .in 在不在
                        if (name[0] + ".in") in name_list:
                            l.append(file_name)
                        else:
                            return error_response(u"测试用例文件不完整，缺少" + name[0] + ".in")

            problem_test_dir = rand_str()
            test_case_dir = settings.TEST_CASE_DIR + problem_test_dir + "/"

            # 得到了合法的测试用例文件列表 然后去解压缩
            os.mkdir(test_case_dir)
            for name in l:
                f = open(test_case_dir + name, "wb")
                try:
                    f.write(test_case_file.read(name).replace("\r\n", "\n"))
                except MemoryError:
                    return error_response(u"单个测试数据体积过大!")
                finally:
                    f.close()
            l.sort()

            file_info = {"test_case_number": len(l) / 2, "test_cases": {}}

            # 计算输出文件的md5
            for i in range(len(l) / 2):
                md5 = hashlib.md5()
                f = open(test_case_dir + str(i + 1) + ".out", "r")
                while True:
                    data = f.read(2 ** 8)
                    if not data:
                        break
                    md5.update(data)

                file_info["test_cases"][str(i + 1)] = {"input_name": str(i + 1) + ".in",
                                                       "output_name": str(i + 1) + ".out",
                                                       "output_md5": md5.hexdigest(),
                                                       "output_size": os.path.getsize(test_case_dir + str(i + 1) + ".out")}
                # 写入配置文件
                open(test_case_dir + "info", "w").write(json.dumps(file_info))

            return success_response({"test_case_id": problem_test_dir,
                                     "file_list": {"input": l[0::2],
                                                   "output": l[1::2]}})
        else:
            return error_response(u"测试用例压缩文件格式错误，请保证测试用例文件在根目录下直接压缩")

def problem_list_page(request, page=1):
    # 正常情况
    problems = Problem.objects.filter(visible=True)

    # 搜索的情况
    keyword = request.GET.get("keyword", None)
    if keyword:
        problems = problems.filter(title__contains=keyword)

    # 按照标签筛选
    tag_text = request.GET.get("tag", None)
    if tag_text:
        try:
            tag = ProblemTag.objects.get(name=tag_text)
        except ProblemTag.DoesNotExist:
            return error_page(request, u"标签不存在")
        problems = tag.problem_set.all()

    paginator = Paginator(problems, 20)
    try:
        current_page = paginator.page(int(page))
    except Exception:
        return error_page(request, u"不存在的页码")

    previous_page = next_page = None

    try:
        previous_page = current_page.previous_page_number()
    except Exception:
        pass

    try:
        next_page = current_page.next_page_number()
    except Exception:
        pass

    # 右侧的公告列表
    announcements = Announcement.objects.filter(is_global=True, visible=True).order_by("-create_time")
    # 右侧标签列表 按照关联的题目的数量排序 排除题目数量为0的
    tags = ProblemTag.objects.annotate(problem_number=Count("problem")).filter(problem_number__gt=0).order_by("-problem_number")

    return render(request, "oj/problem/problem_list.html",
                  {"problems": current_page, "page": int(page),
                   "previous_page": previous_page, "next_page": next_page,
                   "keyword": keyword, "tag": tag_text,
                   "announcements": announcements, "tags": tags})
<|endoftext|>