init - add sync and spawning of gliders

This commit is contained in:
qvalentin 2022-04-02 13:04:51 +02:00
parent 331e463592
commit bcb8de9a9c
Signed by: qvalentin
GPG Key ID: C979FA1EAFCABF1C
12 changed files with 135 additions and 30 deletions

View File

@ -14,8 +14,10 @@ class APIRequests:
jsonValue = response.json() jsonValue = response.json()
return Member(jsonValue["ip"], jsonValue["port"]) return Member(jsonValue["ip"], jsonValue["port"])
def get_edge(self, target: Member, direction: Direction): def get_edge(self, target: Member, direction: Direction,counter:int):
response = requests.get(f"http://{target.ip}:{target.port}/border/{direction.name}") print(f"Getting {direction} edge from {target} with url http://{target.ip}:{target.port}/border/{direction.name}")
response = requests.get(f"http://{target.ip}:{target.port}/border/{direction.name}?counter={counter}")
print(f"Got {direction} edge from {target}")
return response.json() return response.json()
def toggle_pause(self, neighbour: Member, new_state: bool): def toggle_pause(self, neighbour: Member, new_state: bool):

View File

@ -0,0 +1,28 @@
from Code.Communication.Direction import Direction
class EdgeSync:
def __init__(self, current_edges: dict, counter: int):
self.old_edges = {}
self.current_edges = current_edges
self.counter = counter
self.counter_old = counter - 1
def get_edge(self, edg_pos: Direction, counter: int) -> list:
while counter == self.counter + 1:
pass
if counter == self.counter:
return self.current_edges[edg_pos]
elif counter == self.counter_old:
return self.old_edges[edg_pos]
else:
raise ValueError(f"Requested edge for counter {counter}, but having counter {self.counter} ")
def update_edges(self, new_edges, counter: int):
self.counter_old = self.counter
self.counter = counter
self.old_edges = self.current_edges
self.current_edges = new_edges

View File

@ -25,10 +25,9 @@ class Neighbours:
self.neighbours[direction] = member self.neighbours[direction] = member
return self.own_process, True return self.own_process, True
def get_edge(self, direction: Direction): def get_edge(self, direction: Direction,counter:int):
if direction in self.neighbours: if direction in self.neighbours:
print(f"Getting ghost edge from {self.neighbours[direction]}") return self.api.get_edge(self.neighbours[direction], mirror(direction),counter)
return self.api.get_edge(self.neighbours[direction], mirror(direction))
elif direction == Direction.RIGHT or direction.LEFT: elif direction == Direction.RIGHT or direction.LEFT:
return [False] * GeneralConfig.fields_amount_y return [False] * GeneralConfig.fields_amount_y

View File

@ -1,5 +1,6 @@
import json import json
import re import re
import urllib.parse
from dataclasses import asdict from dataclasses import asdict
from http.server import BaseHTTPRequestHandler from http.server import BaseHTTPRequestHandler
@ -16,19 +17,25 @@ class RequestHandler(BaseHTTPRequestHandler):
print("got Get request") print("got Get request")
if self.path == "/": if self.path == "/":
self.send_response(200, "running") self.send_response(200, "running")
self.end_headers()
return
elif self.path.startswith("/border/"): elif self.path.startswith("/border/"):
direction = re.findall("/border/(left|right)", self.path, flags=re.IGNORECASE)[0] direction = re.findall("/border/(left|right).*", self.path, flags=re.IGNORECASE)[0]
cells = self.game_state.field.get_edge(Direction[direction.upper()]) params = urllib.parse.parse_qs(self.path)
counter = int(params[list(params.keys())[0]][0])
print(f"Getting {direction} edge for counter {counter}")
cells = self.game_state.edge_sync.get_edge(Direction[direction.upper()], counter)
print(f"Serving {direction} edge")
self.send_response(200) self.send_response(200)
self.send_header('Content-Type', 'application/json') self.send_header('Content-Type', 'application/json')
self.end_headers() self.end_headers()
self.wfile.write(json.dumps(cells).encode('utf8')) self.wfile.write(json.dumps(cells).encode('utf8'))
return
else: else:
self.send_response(404) self.send_response(404)
self.end_headers() self.end_headers()
return
""" """
/connect/right /connect/right
@ -53,25 +60,30 @@ class RequestHandler(BaseHTTPRequestHandler):
self.send_header('Content-Type', 'application/json') self.send_header('Content-Type', 'application/json')
self.end_headers() self.end_headers()
self.wfile.write(json.dumps(asdict(neighbour)).encode('utf8')) self.wfile.write(json.dumps(asdict(neighbour)).encode('utf8'))
return
else: else:
self.send_response(307) self.send_response(307)
self.send_header('Location', f"http://{neighbour.ip}:{neighbour.port}{self.path}") self.send_header('Location', f"http://{neighbour.ip}:{neighbour.port}{self.path}")
self.end_headers() self.end_headers()
return
elif self.path.startswith("/pause/"): elif self.path.startswith("/pause/"):
new_state = re.findall("/pause/(stop|start)", self.path, flags=re.IGNORECASE)[0] == "start" new_state = re.findall("/pause/(stop|start)", self.path, flags=re.IGNORECASE)[0] == "start"
print(f"pause endpoint {new_state} old state {self.game_state.pause_for_input}") print(f"pause endpoint {new_state} old state {self.game_state.is_evolving}")
if new_state == self.game_state.pause_for_input: if new_state == self.game_state.is_evolving:
print("got pause signal but already in the correct state") print("got pause signal but already in the correct state")
self.send_response(200) self.send_response(200)
self.end_headers() self.end_headers()
return
else: else:
self.send_response(200) self.send_response(200)
self.game_state.pause_for_input = new_state self.game_state.is_evolving = new_state
self.neighbours.toggle_pause(new_state) self.neighbours.toggle_pause(new_state)
self.end_headers() self.end_headers()
return
else: else:
self.send_response(404) self.send_response(404)
self.end_headers() self.end_headers()
return

View File

@ -1,10 +1,16 @@
from http.server import HTTPServer from http.server import HTTPServer
from socketserver import ThreadingMixIn
from Code.Communication.Neighbours import Neighbours from Code.Communication.Neighbours import Neighbours
from Code.Communication.RequestHandler import RequestHandler from Code.Communication.RequestHandler import RequestHandler
from Code.UI.PlayingField import GameState from Code.UI.PlayingField import GameState
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
""" This class allows to handle requests in separated threads.
No further content needed, don't touch this. """
class Server: class Server:
def __init__(self, neighbours: Neighbours,game_state:GameState): def __init__(self, neighbours: Neighbours,game_state:GameState):
self.server = None self.server = None
@ -21,6 +27,6 @@ class Server:
RequestHandler.neighbours = self.neighbours RequestHandler.neighbours = self.neighbours
RequestHandler.game_state = self.game_state RequestHandler.game_state = self.game_state
print(f"HTTP Server Running on {self.ip}: {self.port}") print(f"HTTP Server Running on {self.ip}: {self.port}")
self.server = HTTPServer((self.ip, self.port), RequestHandler) self.server = ThreadedHTTPServer((self.ip, self.port), RequestHandler)
self.server.serve_forever() self.server.serve_forever()
print("Stopped server") print("Stopped server")

View File

@ -11,10 +11,11 @@ class Colors:
WHITE = (255, 255, 255) WHITE = (255, 255, 255)
GREY = (84, 84, 84) GREY = (84, 84, 84)
class Fonts: class Fonts:
pygame.init() pygame.init()
monospace_20 = pygame.font.SysFont("monospace", 20) monospace_20 = pygame.font.SysFont("monospace", 20)
monospace_80 = pygame.font.SysFont("monospace", 80) monospace_80 = pygame.font.SysFont("monospace", 80)
class SquareConfig: class SquareConfig:
@ -32,4 +33,4 @@ class GeneralConfig:
fields_amount_y = math.trunc(height / SquareConfig.height) fields_amount_y = math.trunc(height / SquareConfig.height)
fps = 150 fps = 150
window_caption = "GOL" window_caption = "GOL"
evolve_speed = 360 # ziemlich slow das updated abhänig davon wie viele mill sec das game seit dem eltzten mal gelaufen ist im schnit sind das so 60 evolve_speed = 360 # ziemlich slow das updated abhängig davon wie viele mill sec das game seit dem letzten mal gelaufen ist im schnitt sind das so 60

View File

@ -1,6 +1,8 @@
from Code.Communication.Direction import Direction from Code.Communication.Direction import Direction
from Code.Config import GeneralConfig, SquareConfig from Code.Config import GeneralConfig, SquareConfig
from Code.UI import Square from Code.UI import Square
from Code.UI.Shape import Shape
from Code.UI.Shapes import Shapes
from Code.UI.Square import Square from Code.UI.Square import Square
@ -10,6 +12,10 @@ class Field:
self.height = GeneralConfig.fields_amount_y + 2 self.height = GeneralConfig.fields_amount_y + 2
self.field_shift = -10 self.field_shift = -10
self.squares = self._creat_squares() self.squares = self._creat_squares()
self.shapes = {Shape.VERTICAL_GLIDER: Shapes().creat_vertical_glieder}
def create_shape(self, shape: Shape, start_square_pos):
self.squares = self.shapes[shape](start_square_pos, self.squares)
def _creat_squares(self): def _creat_squares(self):
squares = [ squares = [
@ -27,10 +33,12 @@ class Field:
for y in x: for y in x:
y.draw(window) y.draw(window)
def get_edge(self, edg_pos: Direction) -> list: def get_edges(self) -> dict:
edge = {Direction.LEFT: self.get_left_edge(), Direction.RIGHT: self.get_right_edge(), return {Direction.LEFT: self.get_left_edge(), Direction.RIGHT: self.get_right_edge(),
Direction.TOP: self.get_top(), Direction.BOTTOM: self.get_bottom_edge()} Direction.TOP: self.get_top(), Direction.BOTTOM: self.get_bottom_edge()}
return edge[edg_pos]
def get_edge(self, edg_pos: Direction) -> list:
return self.get_edges()[edg_pos]
def get_top(self): def get_top(self):
top_squares = [] top_squares = []

View File

@ -1,19 +1,24 @@
import pygame as pygame import pygame as pygame
from Code.Communication.Direction import Direction from Code.Communication.Direction import Direction
from Code.Communication.EdgeSync import EdgeSync
from Code.Communication.Neighbours import Neighbours from Code.Communication.Neighbours import Neighbours
from Code.Config import Fonts from Code.Config import Fonts
from Code.Config import GeneralConfig, Colors from Code.Config import GeneralConfig, Colors
from Code.GameLogic.Rules import Rules from Code.GameLogic.Rules import Rules
from Code.UI.Field import Field from Code.UI.Field import Field
from Code.UI.Shape import Shape
class GameState: class GameState:
def __init__(self, neighbours: Neighbours): def __init__(self, neighbours: Neighbours):
self.neighbours = neighbours self.neighbours = neighbours
self.counter = 0
self.run = True self.run = True
self.pause_for_input = False self.is_evolving = False
self.field = Field() self.field = Field()
self.edge_sync = EdgeSync(self.field.get_edges(), self.counter)
self.update_field_events = [] self.update_field_events = []
def event_handler(self): def event_handler(self):
@ -24,8 +29,22 @@ class GameState:
self.update_field_events.append(event) self.update_field_events.append(event)
if event.type == pygame.KEYDOWN: if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE: if event.key == pygame.K_SPACE:
self.pause_for_input = not self.pause_for_input print(f"Gamestate: set evolving to {not self.is_evolving}")
self.neighbours.toggle_pause(self.pause_for_input) self.is_evolving = not self.is_evolving
self.neighbours.toggle_pause(self.is_evolving)
if event.key == pygame.K_v:
index_x = 0
index_y = 0
for line in self.field.squares:
index_y += 1
index_x = 0
for square in line:
index_x += 1
if square.rect.collidepoint(pygame.mouse.get_pos()):
self.field.create_shape(Shape.VERTICAL_GLIDER,
(int(index_y ),
int(index_x )))
def update_field_with_input(self, event): def update_field_with_input(self, event):
for line in self.field.squares: for line in self.field.squares:
@ -40,15 +59,15 @@ class GameState:
def redraw_field(self, window): def redraw_field(self, window):
window.fill(Colors.BLACK) window.fill(Colors.BLACK)
self.field.draw_squares(window) self.field.draw_squares(window)
if not self.pause_for_input: if not self.is_evolving:
label_font = Fonts.monospace_80 label_font = Fonts.monospace_80
label = label_font.render("Pause", 1, Colors.ORANGE) label = label_font.render("Pause", 1, Colors.ORANGE)
window.blit(label, (100, 100)) window.blit(label, (100, 100))
def update_borders(self): def update_borders(self):
self.field.fill_right_ghost_edge(self.neighbours.get_edge(Direction.RIGHT)) self.field.fill_right_ghost_edge(self.neighbours.get_edge(Direction.RIGHT, self.counter))
self.field.fill_left_ghost_edge(self.neighbours.get_edge(Direction.LEFT)) self.field.fill_left_ghost_edge(self.neighbours.get_edge(Direction.LEFT, self.counter))
self.counter_old = self.counter
def run_game(game_state: GameState): def run_game(game_state: GameState):
@ -60,8 +79,9 @@ def run_game(game_state: GameState):
time_elapsed_since_last_action = 0 time_elapsed_since_last_action = 0
while game_state.run: while game_state.run:
print(f"running {game_state.pause_for_input}")
game_state.event_handler() game_state.event_handler()
print(f"running {game_state.is_evolving}")
for event in game_state.update_field_events: for event in game_state.update_field_events:
game_state.update_field_with_input(event) game_state.update_field_with_input(event)
@ -70,12 +90,13 @@ def run_game(game_state: GameState):
clock.tick(GeneralConfig.fps) clock.tick(GeneralConfig.fps)
time_elapsed_since_last_action += clock.get_time() time_elapsed_since_last_action += clock.get_time()
if game_state.pause_for_input: if game_state.is_evolving:
if time_elapsed_since_last_action > 100: if time_elapsed_since_last_action > 100:
# start = ti.time() # start = ti.time()
game_state.update_borders() game_state.update_borders()
game_state.evolve() game_state.evolve()
game_state.counter = game_state.counter + 1
game_state.edge_sync.update_edges(game_state.field.get_edges(), game_state.counter)
# end = ti.time() # end = ti.time()
# print(end - start) # print(end - start)
time_elapsed_since_last_action = 0 # reset it to 0 so you can count again time_elapsed_since_last_action = 0 # reset it to 0 so you can count again

5
Code/UI/Shape.py Normal file
View File

@ -0,0 +1,5 @@
from enum import Enum
class Shape(Enum):
VERTICAL_GLIDER = 1

23
Code/UI/Shapes.py Normal file
View File

@ -0,0 +1,23 @@
from Code import Config
class Shapes:
def creat_vertical_glieder(self, start_square_pos: tuple, squares):
points =[(0,0),(1,0),(2,0),(2,1),(1,2)]
if self._check_bounderies((6, 6), start_square_pos, squares):
for point in points:
squares[start_square_pos[0]+point[1]][start_square_pos[1]+point[0]].active = True
return squares
def _creat_shape(self,start_square_pos: tuple, squares):
def _check_bounderies(self, bounderies, start_square_pos: tuple, field):
x_valid = (Config.GeneralConfig.fields_amount_x-2 - start_square_pos[1]) > bounderies[0]
y_valid = (Config.GeneralConfig.fields_amount_y-2 - start_square_pos[1]) > bounderies[1]
return x_valid and y_valid

0
Code/UI/__init__.py Normal file
View File

0
Code/__init__.py Normal file
View File