import tkinter as tk import tetromino as tetr import copy, random import time as tim from time import sleep #random.seed(10430) class Tetromino: def __init__(self, shape_id, direction):#IJLOSTZ self.shape_id = shape_id self.array = tetr.data[shape_id][direction] self.direction = direction def __str__(self): return stringify(self.array) class Grid: def __init__(self, width, height, display): self.array = [[0 for j in range(0, width)] for i in range(0, height)] self.width = width self.height = height self.display = display def __str__(self): return stringify(self.array) def copy(self): new = Grid(self.width, self.height, self.display) new.array = copyx(self.array) return new def add(self, obj, row, column, simulate=False): array = copyx(self.array) if type(obj) != type([]): obj = obj.array for r in range(0, len(obj)): for c in range(0, len(obj[r])): if obj[r][c] > 0: if 0 <= row+r <= self.height - 1 and 0 <= column+c <= self.width - 1: if array[row+r][column+c] > 0: return False array[row+r][column+c] = obj[r][c] else: return False if simulate: return array self.array = array return True def fitness(self, lines): global modes weights = [-0.510066, 0.76066, -0.35663, -0.184483] # Aggregrate Lines Hole Bumpiness aggregrate = 0 for c in range(0, self.width): for r in range(0, self.height): if self.array[r][c]: aggregrate += self.height - r break hole = 0 for c in range(0, self.width): covered = False for r in range(0, self.height): if (not covered) and self.array[r][c] > 0: covered = True if self.array[r][c] == 0 and covered: hole += 1 bumpiness = 0 for r in range(0, self.height): if self.array[r][0]: height = self.height - r break else: height = 0 last = height for c in range(1, self.width): for r in range(0, self.height): if self.array[r][c]: height = self.height - r break else: height = 0 delta = abs(last - height) bumpiness += delta last = height f = weights[0] * aggregrate + weights[1] * lines + weights[2] * hole + weights[3] * bumpiness if modes == 3: print(aggregrate, lines, hole, bumpiness, f) return f def simulate_peice(self, peice_id, direction, column): global modes simulation = self.copy() lines = 0 empty_line = [0 for i in range(0, self.width)] if not simulation.add(Tetromino(peice_id, direction), 0, column, True): return False row = 0 while simulation.add(Tetromino(peice_id, direction), row, column, True): row += 1 row -= 1 simulation.add(Tetromino(peice_id, direction), row, column) for row_id in range(0, self.height): if complete_line(simulation.array[row_id]): for mov_row_id in range(row_id, -1, -1): simulation.array[mov_row_id] = simulation.array[mov_row_id-1][:] simulation.array[0] = empty_line[:] lines += 1 if modes == 3: print(direction, column, lines, end=' ') return (simulation, lines) def display_simulation(self, peice_id, direction, column, time): global next_peice simulation = self.copy() lines = 0 empty_line = [0 for i in range(0, self.width)] if not simulation.add(Tetromino(peice_id, direction), 0, column, True): return row = 0 step = True while step: step = simulation.add(Tetromino(peice_id, direction), row, column, True) if step: #print(Tetromino(next_peice, 0), '\nScore:', score, '\n', stringify(step), sep='') self.display.display(step, Tetromino(next_peice, 0), score) self.display.master.update() sleep(time) row += 1 row -= 1 simulation.add(Tetromino(peice_id, direction), row, column) for row_id in range(0, self.height): if complete_line(simulation.array[row_id]): for mov_row_id in range(row_id, -1, -1): simulation.array[mov_row_id] = simulation.array[mov_row_id-1][:] simulation.array[0] = empty_line[:] lines += 1 #print(Tetromino(next_peice, 0), '\nScore:', score, '\n', simulation, sep='') self.display.display(simulation.array, Tetromino(next_peice, 0), score) self.display.master.update() class Display(tk.Frame): def __init__(self, master, width, height, squareSize, cut=1): tk.Frame.__init__(self, master) self.master = master self.mode = '' self.framerate = 0 self.lookahead = None self.frame = 0 self.cut = cut self.colors = ['white', 'red', 'orange', 'yellow', 'green', 'blue', 'purple', 'black'] self.master.title('Tetris AI') self.info = tk.Label(self.master, text='') self.info.pack() self.startup() if self.mode != 'Points only': self.width = width self.height = height self.squareSize = squareSize self.next = tk.Canvas(self.master, width=4*squareSize, height=4*squareSize) self.next.pack() self.nextSquares = [] for row in range(4): self.nextSquares.append([]) for column in range(4): x1 = column*self.squareSize y1 = row*self.squareSize x2 = x1 + self.squareSize y2 = y1 + self.squareSize self.nextSquares[row].append(self.next.create_rectangle(x1, y1, x2, y2, fill='white', width=0)) self.canvas = tk.Canvas(self.master, width=width*squareSize, height=height*squareSize) self.canvas.pack() self.squares = [] for row in range(self.height): self.squares.append([]) for column in range(self.width): x1 = column*self.squareSize y1 = row*self.squareSize x2 = x1 + self.squareSize y2 = y1 + self.squareSize self.squares[row].append(self.canvas.create_rectangle(x1, y1, x2, y2, fill='white', width=0)) self.master.update() def startup(self): text = ['Points only', 'Peice by peice', 'Full animation', 'Debug'] buttons = [] self.info['text'] = 'Display mode:' for i in text: button = tk.Button(self.master, text=i, command=self.selected(i)) button.pack() buttons.append(button) while self.mode == '': self.master.update() for button in buttons: button.destroy() if self.mode == 'Full animation': self.info['text'] = 'Framerate (fps):' self.enter = tk.Entry(self.master) self.enter.pack() button = tk.Button(self.master, text='Submit', command=self.fs) button.pack() while self.framerate == 0: self.master.update() self.enter.destroy() button.destroy() self.info['text'] = '' true = tk.Button(self.master, text='Lookahead', command=self.lt) true.pack() false = tk.Button(self.master, text='No lookahead', command=self.lf) false.pack() while self.lookahead == None: self.master.update() true.destroy() false.destroy() self.master.update() def selected(self, i): def func(): self.mode = i return func def fs(self): self.framerate = 1/int(self.enter.get()) def lt(self): self.lookahead = True def lf(self): self.lookahead = False def update(self): self.master.update() def display(self, array, nextPeice, score): if self.frame%self.cut == 0: self.info['text'] = 'Score: '+str(score)+'\nNext peice:' for row in range(len(nextPeice.array)): for column in range(len(nextPeice.array[0])): self.next.itemconfig(self.nextSquares[row][column], fill=self.colors[nextPeice.array[row][column]]) for row in range(self.height): for column in range(self.width): self.canvas.itemconfig(self.squares[row][column], fill=self.colors[array[row][column]]) self.frame += 1 def stringify(array): s = '' for row in array: for cell in row: s += str(cell) s += '\n' return s def copyx(array): result = [] for row in array: result.append(row[:]) return result def complete_line(line): for cell in line: if cell < 1: return False return True bag = [] def random_peice(): global bag if len(bag) == 0: bag = [0,1,2,3,4,5,6] random.shuffle(bag) return bag.pop() board = Grid(10, 22, None) root = tk.Tk() display = Display(root, board.width, board.height, 25) mode = not display.lookahead modes = ['Points only', 'Peice by peice', 'Full animation', 'Debug'].index(display.mode) time = display.framerate board.display = display ############### #root.mainloop() #raise SystemExit ############### score = 0 peice_id = random_peice() next_peice = random_peice() itr = 0 while True: display.update() last = board.copy() best = [-10000, 0, 5, '', 0]#fitness, rotation, column, simulation for column in range(-2, board.width): for rotation in [0,1,2,3]: result = board.simulate_peice(peice_id, rotation, column) if result: if mode: fitness = result[0].fitness(result[1]) if not mode: for Column in range(-2, board.width): for Rotation in [0,1,2,3]: resultb = result[0].simulate_peice(next_peice, Rotation, Column) if resultb: fitness = resultb[0].fitness(resultb[1]) if fitness > best[0]: best = [fitness, rotation, column, result[0].copy(), result[1] + resultb[1]] if fitness > best[0] and mode: best = [fitness, rotation, column, result[0].copy(), result[1]] board = best[3] if board == '': print(''' █████ █ █ █ ███████ █ █ █ █ ██ ██ █ █ █ █ █ █ █ █ █ █ ████ █ █ █ █ █ █████ █ █ ███████ █ █ █ █ █ █ █ █ █ █ █████ █ █ █ █ ███████ ███████ █ █ ███████ ██████ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █████ ██████ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ███████ █ ███████ █ █ ''') break if modes > 1: last.display_simulation(peice_id, best[1], best[2], time) if modes == 1: display.display(board.array, Tetromino(next_peice, 0), score) peice_id = next_peice next_peice = random_peice() score += 10*best[4] itr += 1 if modes == 0: display.info['text'] = 'Score: '+str(score) file = open('tetris scores.txt', 'a') print(tim.ctime(), itr, score, sep='\t', file=file) print('\n', board, '\n') file.close() input('')