#!/usr/bin/python3
import gi, random
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GLib
import cairo

CELL = 20
COLS, ROWS = 25, 20

class Snake(Gtk.Window):
    def __init__(self):
        super().__init__(title='Snake')
        self.set_default_size(COLS*CELL, ROWS*CELL+40)
        self.set_resizable(False)
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.add(vbox)
        self.label = Gtk.Label(label='Score: 0  |  Press arrow key to start')
        vbox.pack_start(self.label, False, False, 4)
        self.da = Gtk.DrawingArea()
        self.da.set_size_request(COLS*CELL, ROWS*CELL)
        self.da.connect('draw', self.draw)
        vbox.pack_start(self.da, True, True, 0)
        self.connect('key-press-event', self.key)
        self.reset()
        GLib.timeout_add(150, self.tick)
    def reset(self):
        self.snake = [(COLS//2, ROWS//2)]
        self.direction = (1, 0)
        self.next_dir = (1, 0)
        self.score = 0
        self.alive = False
        self.food = self.new_food()
    def new_food(self):
        while True:
            f = (random.randint(0,COLS-1), random.randint(0,ROWS-1))
            if f not in self.snake: return f
    def key(self, w, e):
        kn = Gdk.keyval_name(e.keyval)
        dirs = {'Up':(0,-1),'Down':(0,1),'Left':(-1,0),'Right':(1,0)}
        if kn in dirs:
            nd = dirs[kn]
            if (nd[0]+self.direction[0], nd[1]+self.direction[1]) != (0,0):
                self.next_dir = nd
            self.alive = True
        if kn == 'r': self.reset(); self.alive = True
    def tick(self):
        if not self.alive: return True
        self.direction = self.next_dir
        hx, hy = self.snake[0]
        nx, ny = hx+self.direction[0], hy+self.direction[1]
        if nx<0 or nx>=COLS or ny<0 or ny>=ROWS or (nx,ny) in self.snake:
            self.alive = False
            self.label.set_text(f'GAME OVER! Score: {self.score}  |  Press R to restart')
            self.da.queue_draw(); return True
        self.snake.insert(0,(nx,ny))
        if (nx,ny) == self.food:
            self.score += 10
            self.food = self.new_food()
            self.label.set_text(f'Score: {self.score}')
        else:
            self.snake.pop()
        self.da.queue_draw()
        return True
    def draw(self, w, cr):
        cr.set_source_rgb(0.1,0.1,0.1)
        cr.paint()
        # food
        cr.set_source_rgb(1,0.2,0.2)
        cr.rectangle(self.food[0]*CELL+1, self.food[1]*CELL+1, CELL-2, CELL-2)
        cr.fill()
        # snake
        for i,(x,y) in enumerate(self.snake):
            g = 0.8 if i==0 else 0.5
            cr.set_source_rgb(0,g,0)
            cr.rectangle(x*CELL+1, y*CELL+1, CELL-2, CELL-2)
            cr.fill()

win = Snake()
win.connect('destroy', Gtk.main_quit)
win.show_all()
Gtk.main()
