import pygame
from pygame.locals import * 
pygame.mixer.pre_init(44100, -16, 2, 1024)
pygame.init()
import random


class Fruit(pygame.sprite.Sprite):
    fruits = []

    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        if len(Fruit.fruits) == 0:
            self.load_fruits()
        self.image = random.choice(Fruit.fruits).copy()
        self.rect = self.image.get_rect()
        self.rect.left = random.randint(0, (game_size[0]-self.rect.width)/self.rect.width )*self.rect.width
        self.rect.top = random.randint(0, (game_size[1]-self.rect.height)/self.rect.height )*self.rect.height

    def load_fruits(self):
        Fruit.fruits += [pygame.image.load("fruit1.jpg").convert()]
        Fruit.fruits += [pygame.image.load("fruit2.jpg").convert()]
        Fruit.fruits += [pygame.image.load("fruit3.jpg").convert()]
        Fruit.fruits += [pygame.image.load("fruit4.jpg").convert()]
        Fruit.fruits += [pygame.image.load("fruit5.jpg").convert()]

    
    
    
class Snake_Cell(pygame.sprite.Sprite):
    cell_image = pygame.image.load("worm_cell.jpg")
    face_image = pygame.image.load("worm_face.jpg")
    width = cell_image.get_width()

    def __init__(self, x=0, y=0, is_face=False):
        pygame.sprite.Sprite.__init__(self)
        if is_face:
            self.image = Snake_Cell.face_image.copy().convert()
        else:
            self.image = Snake_Cell.cell_image.copy().convert()
        self.rect = self.image.get_rect()
        self.rect.topleft = (x, y)
        
    def __str__(self):
        return "(%i,%i)" %(self.rect.left, self.rect.top)
    
    def __eq__(self, other):
        return self.rect.topleft == other.rect.topleft

    
class Snake(object):
    def __init__(self, size=4, start_x=0, start_y=0):
        #cell at [-1] is the face
        self.cells = []
        for i in range(size-1):
            self.cells += [Snake_Cell(start_x+i*Snake_Cell.width, start_y)]
        self.cells += [Snake_Cell(start_x+(i+1)*Snake_Cell.width, start_y, True)] #face
        self.direc = (1,0)
        self.score = 0
        self.speed = 1
        self.group = pygame.sprite.Group(self.cells)


    def get_vert_dir(self):
        return self.direc[1]
    def get_horiz_dir(self):
        return self.direc[0]

    def change_dir(self, key):
        if key == K_UP and self.get_vert_dir()!=1:
            self.direc=(0,-1)
        elif key == K_DOWN and self.get_vert_dir()!=-1:
            self.direc=(0,1)
        elif key == K_LEFT and self.get_horiz_dir()!=1:
            self.direc=(-1,0)
        elif key == K_RIGHT and self.get_horiz_dir()!=-1:
            self.direc=(1,0)
        
    def hit_wall(self):
        return self.direc[0]==1 and self.cells[-1].rect.right > game_size[0] or \
        self.direc[1]==1 and self.cells[-1].rect.bottom > game_size[1] or \
        self.direc[0]==-1 and self.cells[-1].rect.left < 0 or \
        self.direc[1]==-1 and self.cells[-1].rect.top < 0

    def add_cell(self):
        new_cell = Snake_Cell(self.cells[0].rect.left, self.cells[0].rect.top)
        self.cells[0:0] = [new_cell]
        self.group.add(new_cell)

    
game_size = (630, 450)
score_size = (game_size[0], 30)
screen = pygame.display.set_mode((game_size[0],game_size[1]+score_size[1]))
pygame.display.set_caption("ICSnake  Score: 0")

background = pygame.Surface(game_size).convert()
background.fill((255, 255, 255))
screen.blit(background, (0,0))

score_bar = pygame.Surface(score_size).convert()
score_bar.fill((0, 0, 0))

label_font = pygame.font.Font("Neurochr.ttf", 48) #<-- custom fonts, need to be included in distribution
score_font = pygame.font.Font("Neurochr.ttf", 24) #<-- custom fonts, need to be included in distribution
snake = Snake(4)

    
#random fruit
fruit = Fruit()

#sounds
gulp = pygame.mixer.Sound("gulp.wav")
boo = pygame.mixer.Sound("boo.wav")
level = pygame.mixer.Sound("level_up.wav")
pygame.mixer.music.load("background.wav")
pygame.mixer.music.play(-1)


score_label = score_font.render("Score: %i" %(snake.score), True, (255,255,255))        
speed_label = score_font.render("Speed: %i" %(snake.speed), True, (255,255,255))   
window_closed = False

clock = pygame.time.Clock() 

frame_rate =5*snake.speed #we will have a dynamic framerate here
#This decision is for simplicity, but does cause some undesirable effects with
#delays in event handling, so it would be best to change it

keep_going = True
while keep_going:
    clock.tick(frame_rate)

    for ev in pygame.event.get():
        if ev.type == QUIT:
            keep_going = False
            window_closed = True
        elif ev.type == KEYDOWN:
            snake.change_dir(ev.key)
    
    #check boundaries
    if snake.hit_wall():
        keep_going = False    
    
        
    if keep_going:
        #Update chain of cells
        for i in range(len(snake.cells)-1):
            snake.cells[i].rect = snake.cells[i+1].rect.copy()
        #Update face
        snake.cells[-1].rect.left += (snake.cells[-1].rect.width*snake.get_horiz_dir())
        snake.cells[-1].rect.top += (snake.cells[-1].rect.height*snake.get_vert_dir())
        
        #check crossover
        if snake.cells[-1] in snake.cells[:-1]: #easier than collision code, uses equality
            keep_going = False
        else:
            #did I eat a fruit?
            if pygame.sprite.spritecollide(fruit, snake.group, False):
                gulp.play()
                fruit = Fruit() #replace the fruit
                snake.score += 1
        
                #change the score in the header
                pygame.display.set_caption("ICSnake  Score: " + str(snake.score))
                score_label = score_font.render("Score: %i" %(snake.score), True, (255,255,255)) #<-- text, anti-alias, colour        
                        
                #Increase the speed every 3 fruits
                if snake.score%3 == 0:
                    level.play()
                    snake.speed += 1
                    frame_rate=4*snake.speed
                    speed_label = score_font.render("Speed: %i" %(snake.speed), True, (255,255,255))
    
                #insert a new cell at the tail of the snake
                snake.add_cell()

    
    #if the game is over, make the snake and fruit transparent
    else:
        for a_cell in snake.cells:
            a_cell.image.set_alpha(100)
        fruit.image.set_alpha(100)

    #blit the images and fruit
    screen.blit(score_bar, (0,game_size[1]))
    screen.blit(score_label, (100,game_size[1]))
    screen.blit(speed_label, (300,game_size[1]))
    snake.group.clear(screen, background)
    snake.group.update()
    snake.group.draw(screen)
    screen.blit(fruit.image, fruit.rect)
    
    #if the game is over, put the "game over" label on
    if not keep_going:
        pygame.mixer.music.stop()
        boo.play()
        game_over = label_font.render("Game Over!", True, (0,0,0))
        screen.blit(game_over, (game_size[0]/2-game_over.get_width()/2, game_size[1]/2-game_over.get_height()/2))
        
    pygame.display.flip()

#stall on the game over message, only if they actually lost
stall = True
while stall and not window_closed:
    for ev in pygame.event.get():
        if ev.type == pygame.QUIT:
            stall = False
    
