def __init__(self, dictionary):
        self.dictionary = dictionary
        self.running = True
        self.isGameOver = False
        self.score = 0

        # Init the screen
        screenWidth = FIELD_WIDTH + 2 * FIELD_MARGIN
        screenHeight = FIELD_HEIGHT + 2 * FIELD_MARGIN
        self.screen = pygame.display.set_mode((screenWidth, screenHeight))

        # Prepare the background
        self.background = pygame.Surface(self.screen.get_size())
        self.background = self.background.convert()
        self.background.fill(BACKGROUND_COLOR)

        # Add hud fields
        self.hudTitle = HudText(FIELD_MARGIN, 5, 300, "Intellectual Snake!")
        self.hudGameStatus = HudText(FIELD_MARGIN + FIELD_WIDTH - 150,
                                     FIELD_MARGIN + FIELD_HEIGHT + 5, 300, "")
        self.hudScore = HudText(FIELD_MARGIN + FIELD_WIDTH - 100, 5, 100, "Score: 0")

        # Init The Snake
        headX = SEGMENT_SIZE * COLUMNS / 2
        headY = SEGMENT_SIZE * ROWS / 2
        self.head = Head(headX, headY)
        self.segments = []
        for i in xrange(0, INIT_SNAKE_LENGTH):
            self.segments.append(Segment(headX - i * SEGMENT_SIZE, headY))

        # Init direction controls
        self.directionControls = \
            DirectionControl(headX, headY, UP), \
            DirectionControl(headX, headY, DOWN), \
            DirectionControl(headX, headY, LEFT), \
            DirectionControl(headX, headY, RIGHT)

        for control in self.directionControls:
            control.setLetter(self.generateNewDirectionLetter())

        # Init Group of field objects that should not collide
        self.fieldObjects = pygame.sprite.Group()
        self.fieldObjects.add(self.segments)

        # Add initial food to the field
        self.addNewFood()

        # Add walls marking up the field
        self.fieldObjects.add((
            Wall(-1, -1, FIELD_WIDTH + 2, 1),
            Wall(FIELD_WIDTH + 2, -1, 1, FIELD_HEIGHT + 2),
            Wall(-1, FIELD_HEIGHT + 2, FIELD_WIDTH + 2, 1),
            Wall(-1, -1, 1, FIELD_HEIGHT)
        ))

        # Init empty array of obstacles
        self.obstacles = []

        # Init Bonus word
        self.bonusWord = None
class IntellectualSnake:
    def __init__(self, dictionary):
        self.dictionary = dictionary
        self.running = True
        self.isGameOver = False
        self.score = 0

        # Init the screen
        screenWidth = FIELD_WIDTH + 2 * FIELD_MARGIN
        screenHeight = FIELD_HEIGHT + 2 * FIELD_MARGIN
        self.screen = pygame.display.set_mode((screenWidth, screenHeight))

        # Prepare the background
        self.background = pygame.Surface(self.screen.get_size())
        self.background = self.background.convert()
        self.background.fill(BACKGROUND_COLOR)

        # Add hud fields
        self.hudTitle = HudText(FIELD_MARGIN, 5, 300, "Intellectual Snake!")
        self.hudGameStatus = HudText(FIELD_MARGIN + FIELD_WIDTH - 150,
                                     FIELD_MARGIN + FIELD_HEIGHT + 5, 300, "")
        self.hudScore = HudText(FIELD_MARGIN + FIELD_WIDTH - 100, 5, 100, "Score: 0")

        # Init The Snake
        headX = SEGMENT_SIZE * COLUMNS / 2
        headY = SEGMENT_SIZE * ROWS / 2
        self.head = Head(headX, headY)
        self.segments = []
        for i in xrange(0, INIT_SNAKE_LENGTH):
            self.segments.append(Segment(headX - i * SEGMENT_SIZE, headY))

        # Init direction controls
        self.directionControls = \
            DirectionControl(headX, headY, UP), \
            DirectionControl(headX, headY, DOWN), \
            DirectionControl(headX, headY, LEFT), \
            DirectionControl(headX, headY, RIGHT)

        for control in self.directionControls:
            control.setLetter(self.generateNewDirectionLetter())

        # Init Group of field objects that should not collide
        self.fieldObjects = pygame.sprite.Group()
        self.fieldObjects.add(self.segments)

        # Add initial food to the field
        self.addNewFood()

        # Add walls marking up the field
        self.fieldObjects.add((
            Wall(-1, -1, FIELD_WIDTH + 2, 1),
            Wall(FIELD_WIDTH + 2, -1, 1, FIELD_HEIGHT + 2),
            Wall(-1, FIELD_HEIGHT + 2, FIELD_WIDTH + 2, 1),
            Wall(-1, -1, 1, FIELD_HEIGHT)
        ))

        # Init empty array of obstacles
        self.obstacles = []

        # Init Bonus word
        self.bonusWord = None

    def update(self, time):
        for event in pygame.event.get():
            if event.type == QUIT:
                self.running = False
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                self.running = False
            elif event.type == KEYDOWN and not self.isGameOver:
                self.handleKeyDown(event.key)

        if self.isGameOver:
            return

        # Update the snake
        self.head.update(time)
        for segment in self.segments:
            segment.update(time)

        # Update the direction controls
        for control in self.directionControls:
            control.update(time)

        # Generate random obstacle
        if didOccur(OBSTACLE_RATE, time):
            self.addNewObstacle()

        # Generate random bonus word
        if self.bonusWord is None and didOccur(BONUS_WORD_RATE, time):
            self.addNewBonusWord()

        if self.head.moved:
            eatenFood = False

            # Check for collisions
            for sprite in pygame.sprite.spritecollide(self.head, self.fieldObjects, False):
                if type(sprite) is Food:
                    self.fieldObjects.remove(sprite)
                    self.addNewFood()
                    eatenFood = True
                    self.score += 1
                    self.hudScore.setContent("Score: %d" % self.score)
                elif type(sprite) is Segment or type(sprite) is Obstacle:
                    self.hudGameStatus.setContent("Game over :-(")
                    self.isGameOver = True

            # Move the snake's body (possibly extend it if some food was eaten)
            self.moveBody(eatenFood)

            # Move direction controls to follow the snake's head
            for control in self.directionControls:
                control.setHeadPosition(self.head.rect.x, self.head.rect.y)

    def render(self):
        # Render field objects on a separate Surface (which allows us to work in an independent
        # coordinate system)
        field = pygame.Surface([FIELD_WIDTH, FIELD_HEIGHT])
        field.fill(FIELD_COLOR)
        field.blit(self.head.image, self.head.rect)
        self.fieldObjects.draw(field)

        # Render the game field and other UI objects directly on the screen
        self.screen.blit(self.background, (0, 0))
        self.screen.blit(field, (FIELD_MARGIN, FIELD_MARGIN))

        for control in self.directionControls:
            self.screen.blit(control.image, control.rect)

        self.screen.blit(self.hudTitle.image, self.hudTitle.rect)
        self.screen.blit(self.hudGameStatus.image, self.hudGameStatus.rect)
        self.screen.blit(self.hudScore.image, self.hudScore.rect)

        if self.bonusWord is not None:
            self.screen.blit(self.bonusWord.image, self.bonusWord.rect)

    def isRunning(self):
        return self.running

    def handleKeyDown(self, key):
        letter = pygame.key.name(key)

        # Find direction control matching the pressed letter. If found, change the snake's
        # direction according to the control
        control = self.findControlByLetter(letter)
        if control:
            if self.head.changeDirection(control.direction):
                control.setLetter(self.generateNewDirectionLetter())

        # Update the obstacles with the current letter
        for obstacle in self.obstacles:
            if obstacle.typeLetter(letter):
                self.obstacles.remove(obstacle)
                self.fieldObjects.remove(obstacle)

        # Update Bonus word with the current letter
        if self.bonusWord is not None:
            if self.bonusWord.typeLetter(letter):
                self.removeTail(len(self.bonusWord.word))
                self.bonusWord = None

    def generateNewDirectionLetter(self):
        letter = getRandomLetter()

        # The new letter must be different from the previous one and must be unique across all
        # direction letters (to avoid ambiguity)
        while len(filter(lambda control: control.letter == letter, self.directionControls)) > 0:
            letter = getRandomLetter()

        return letter

    def addNewFood(self):
        food = self.generateRandomFood()

        while pygame.sprite.spritecollide(food, self.fieldObjects, False):
            food = self.generateRandomFood()

        self.fieldObjects.add(food)

    def generateRandomFood(self):
        x, y = generateRandomFieldPosition()
        return Food(x, y)

    def addNewObstacle(self):
        obstacle = self.generateRandomObstacle()

        while pygame.sprite.spritecollide(obstacle, self.fieldObjects, False):
            obstacle = self.generateRandomObstacle()

        self.fieldObjects.add(obstacle)
        self.obstacles.append(obstacle)

    def generateRandomObstacle(self):
        x, y = generateRandomFieldPosition()
        word = random.choice(self.dictionary)
        orientation = random.choice((HORIZONTAL, VERTICAL))
        return Obstacle(x, y, word, orientation)

    def addNewBonusWord(self):
        self.bonusWord = BonusWord(FIELD_MARGIN, FIELD_MARGIN + FIELD_HEIGHT + 10,
                                   random.choice(self.dictionary))

    def findControlByLetter(self, letter):
        controls = [control for control in self.directionControls if control.letter == letter]
        if not controls:
            return False
        else:
            return controls[0]

    def moveBody(self, eatenFood):
        # Add new segment to the end of the snake's body (the position of the last segment) and then
        # let it smoothly move to the head's position.
        newSegment = Segment(
            self.head.rect.x - self.head.direction[0] * SEGMENT_SIZE,
            self.head.rect.y - self.head.direction[1] * SEGMENT_SIZE)
        newSegment.moveTo(self.head.rect.x, self.head.rect.y)
        self.segments[0].setDirection(self.head.direction)
        self.segments.insert(0, newSegment)
        self.fieldObjects.add(newSegment)

        # Unless food was eaten, Remove tail and let the last segment smoothly move in the
        # body direction.
        if not eatenFood:
            self.removeTail(1)

    def removeTail(self, length):
        for i in xrange(length):
            if len(self.segments) > 1:
                self.fieldObjects.remove(self.segments.pop())

        self.segments[-1].moveInDirection(self.segments[-1].direction)