From 439cf44d70b6854e80b6821024f05930ffabb91a Mon Sep 17 00:00:00 2001 From: Simon Pirkelmann Date: Fri, 3 Sep 2021 21:38:30 +0200 Subject: [PATCH] implemented core game logic and display --- gauss-turing/webserver/gauss_turing.py | 237 +++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 gauss-turing/webserver/gauss_turing.py diff --git a/gauss-turing/webserver/gauss_turing.py b/gauss-turing/webserver/gauss_turing.py new file mode 100644 index 0000000..b8c7254 --- /dev/null +++ b/gauss-turing/webserver/gauss_turing.py @@ -0,0 +1,237 @@ +import numpy as np +import random +import pygame +import time +pygame.init() + +pygame.font.init() # you have to call this at the start, + # if you want to use this module. +myfont = pygame.font.SysFont('Comic Sans MS', 55) +P0_text = myfont.render('P0', False, (0, 0, 0)) +game_over_text = myfont.render('GAME OVER', False, (255, 0, 0)) + +random.seed(0) + +dimx = 5 +dimy = 10 + +scale_fac = 50 +screen = pygame.display.set_mode((dimx*scale_fac+100,dimy*scale_fac+200)) + +tiledt = np.dtype([('x', np.uint8), ('y', np.uint8), ('color', np.uint8, 3), ('star', np.bool)]) + +BLACK = np.array([0, 0, 0], dtype=np.uint8) +WHITE = np.array([255, 255, 255], dtype=np.uint8) +RED = np.array([255, 0, 0], dtype=np.uint8) +BLUE = np.array([0, 0, 255], dtype=np.uint8) +YELLOW = np.array([255, 255, 0], dtype=np.uint8) +GREEN = np.array([0, 255, 0], dtype=np.uint8) + + + +class Board: + valid_colors = [WHITE, RED, BLUE] + + def __init__(self, dim_x, dim_y, robot): + self.tiles = np.zeros((dim_y, dim_x), dtype=tiledt) + for x in range(dim_x): + for y in range(dim_y): + self.tiles[y, x]['x'] = x + self.tiles[y, x]['y'] = y + self.tiles[y, x]['color'] = random.choice(Board.valid_colors) + self.robot = robot + + def render(self): + board_surf = pygame.Surface((dimx * scale_fac, dimy * scale_fac)) + robot_surf = pygame.Surface((scale_fac, scale_fac), pygame.SRCALPHA) + # Use the local coordinate system of the surface to draw the lines. + pygame.draw.lines(robot_surf, (0, 0, 0), True, [(0.75 * scale_fac, 0.5 * scale_fac), + (0.25 * scale_fac, 0.25 * scale_fac), + (0.25 * scale_fac, 0.75 * scale_fac)], 3) + # I rotate it so that the arrow is pointing to the right (0° is right). + robot_surf = pygame.transform.rotate(robot_surf, self.robot.get_angle()) + + star_surf = pygame.Surface((scale_fac, scale_fac), pygame.SRCALPHA) + pygame.draw.circle(star_surf, YELLOW, (int(0.5 * scale_fac), int(0.5 * scale_fac)), int(0.25 * scale_fac)) + + for y in range(self.tiles.shape[0]): + for x in range(self.tiles.shape[1]): + pygame.draw.rect(board_surf, tuple(self.tiles[y, x]['color']), + (x * scale_fac, y * scale_fac, scale_fac, scale_fac), 0) + pygame.draw.rect(board_surf, (0, 0, 0), + (x * scale_fac, y * scale_fac, scale_fac, scale_fac), 1) + if self.tiles[y, x]['star']: + board_surf.blit(star_surf, (x * scale_fac, y * scale_fac, scale_fac, scale_fac)) + if (x, y) == (self.robot.x, self.robot.y): + board_surf.blit(robot_surf, (x * scale_fac, y * scale_fac, scale_fac, scale_fac)) + + return board_surf + + def __repr__(self): + s = '' + for y in range(self.tiles.shape[0]): + for x in range(self.tiles.shape[1]): + if (x,y) == (self.robot.x, self.robot.y): + s += self.robot.orientation + else: + s += '.' + s += '\n' + return s + + +class Robot: + orientations = ['^', 'left', 'down', 'right'] + resulting_orientation = { + '^': {'left': '<', 'right': '>'}, + '>': {'left': '^', 'right': 'v'}, + 'v': {'left': '>', 'right': '<'}, + '<': {'left': 'v', 'right': '^'}, + } + + + def __init__(self, x, y, orientation): + self.x = x + self.y = y + self.orientation = orientation + + def get_forward_coordinates(self): + # get the coordinates of the neighboring tile in the given direction + if self.orientation == '^': + return self.y - 1, self.x + elif self.orientation == '>': + return self.y, self.x + 1 + elif self.orientation == 'v': + return self.y + 1, self.x + elif self.orientation == '<': + return self.y, self.x - 1 + else: + raise Exception("error: undefined direction") + + def get_angle(self): + angle = {'>': 0, '^': np.pi/2, '<': np.pi, 'v': 3*np.pi/2}[self.orientation] + return np.rad2deg(angle) + + def __repr__(self): + return f"({self.y}, {self.x}) - {self.orientation}" + + +class Command: + valid_actions = {'forward', 'left', 'right', 'P0', '-'} + + def __init__(self, action=None, color=WHITE): + if not (action in Command.valid_actions and any([np.all(color == c) for c in Board.valid_colors])): + raise ValueError("invalid values for command") + self.action = action + self.color = color + + def __repr__(self): + return f"{self.action}: {self.color}" + + def render(self): + cmd_surf = pygame.Surface((scale_fac, scale_fac)) + cmd_surf.fill(tuple(self.color)) + + arrow_surf = pygame.Surface((300, 300), pygame.SRCALPHA) + #arrow_surf.fill(tuple(WHITE)) + pygame.draw.polygon(arrow_surf, (0, 0, 0), + ((0, 100), (0, 200), (200, 200), (200, 300), (300, 150), (200, 0), (200, 100))) + arrow_surf = pygame.transform.scale(arrow_surf, (int(0.9*scale_fac), int(0.9*scale_fac))) + + if self.action == 'forward': + arrow_surf = pygame.transform.rotate(arrow_surf, 90) + elif self.action == 'left': + arrow_surf = pygame.transform.rotate(arrow_surf, 180) + + if self.action in {'left', 'forward', 'right'}: + cmd_surf.blit(arrow_surf, (0.05*scale_fac,0.05*scale_fac,0.95*scale_fac,0.95*scale_fac)) + elif self.action == 'P0': + cmd_surf.blit(P0_text, (0.05*scale_fac,0.05*scale_fac,0.95*scale_fac,0.95*scale_fac)) + + return cmd_surf + +class Program: + def __init__(self, robot, board, cmds): + self.cmds = cmds + self.robot = robot + self.board = board + + def input_program(self): + self.render() + pass + + def run(self): + running = True + prg_counter = 0 + + self.render(prg_counter) + + while running: + cmd = self.cmds[prg_counter] + prg_counter += 1 + + # current position + x = self.robot.x + y = self.robot.y + + # current tile the robot is on + tile = self.board.tiles[y, x] + + if np.all(cmd.color == WHITE) or np.all(cmd.color == tile['color']): + # matching color -> execute command + if cmd.action == 'forward': + ynew, xnew = r.get_forward_coordinates() + r.x = xnew + r.y = ynew + elif cmd.action in {'left', 'right'}: + r.orientation = Robot.resulting_orientation[self.robot.orientation][cmd.action] + elif cmd.action == 'P0': + prg_counter = 0 + else: + print("color not matching -> skipping command") + + self.render(prg_counter) + + if (not (0 <= r.x < self.board.tiles.shape[1])) or not (0 <= r.y < self.board.tiles.shape[0]): + print("GAME OVER") + screen.blit(game_over_text, (50, 00)) + pygame.display.update() + running = False + + time.sleep(0.1) + + + + def render(self, prg_counter=None): + dx = 50 + dy = 50 + screen.fill(tuple(BLACK)) + board_surf = self.board.render() + screen.blit(board_surf, (dx, dy, dx + dimx * scale_fac, dy + dimy * scale_fac)) + + prg_surf = self.render_prg(prg_counter) + screen.blit(prg_surf, (dx, board_surf.get_height()+2*dy, prg_surf.get_width(), prg_surf.get_height())) + + pygame.display.update() + + def render_prg(self, prg_counter=None): + prg_surf = pygame.Surface((5 * scale_fac, 1 * scale_fac)) + prg_surf.fill(WHITE) + for i in range(5): + if i < len(self.cmds): + cmd = self.cmds[i] + cmd_surf = cmd.render() + if prg_counter is not None and i == prg_counter: + pygame.draw.rect(cmd_surf, tuple(GREEN), (0,0,scale_fac,scale_fac), 5) + prg_surf.blit(cmd_surf, (i * scale_fac, 0, scale_fac, scale_fac)) + return prg_surf + +r = Robot(x=1, y=1, orientation='v') +b = Board(dimx,dimy, r) +b.tiles[3,4]['star'] = True +print(b) + +cmds = [Command('forward'), Command('left', color=RED), Command('left', color=BLUE), Command('P0')] + +prg = Program(r, b, cmds) +prg.input_program() +prg.run()