init - add more spaceships and start with doku

This commit is contained in:
qvalentin 2022-04-02 16:54:46 +02:00
parent bcb8de9a9c
commit 7f6b53b549
Signed by: qvalentin
GPG Key ID: C979FA1EAFCABF1C
8 changed files with 109 additions and 27 deletions

View File

@ -11,11 +11,22 @@ class Field:
self.width = GeneralConfig.fields_amount_x + 2 self.width = GeneralConfig.fields_amount_x + 2
self.height = GeneralConfig.fields_amount_y + 2 self.height = GeneralConfig.fields_amount_y + 2
self.field_shift = -10 self.field_shift = -10
self.shapes = Shapes()
self.squares = self._creat_squares() self.squares = self._creat_squares()
self.shapes = {Shape.VERTICAL_GLIDER: Shapes().creat_vertical_glieder}
def get_square_on_click_pos(self, mousclick_pos):
index_x = 0
index_y = 0
for line in self.squares:
index_y += 1
index_x = 0
for square in line:
index_x += 1
if square.rect.collidepoint(mousclick_pos):
return (index_y, index_x)
def create_shape(self, shape: Shape, start_square_pos): def create_shape(self, shape: Shape, start_square_pos):
self.squares = self.shapes[shape](start_square_pos, self.squares) self.squares = self.shapes.create_shape(start_square_pos,self.squares, shape)
def _creat_squares(self): def _creat_squares(self):
squares = [ squares = [

View File

@ -33,18 +33,23 @@ class GameState:
self.is_evolving = not self.is_evolving self.is_evolving = not self.is_evolving
self.neighbours.toggle_pause(self.is_evolving) self.neighbours.toggle_pause(self.is_evolving)
if event.key == pygame.K_v: if event.key == pygame.K_v:
index_x = 0 self.field.create_shape(Shape.VERTICAL_GLIDER_LEFT,
index_y = 0 self.field.get_square_on_click_pos(pygame.mouse.get_pos()))
if event.key == pygame.K_b:
for line in self.field.squares: self.field.create_shape(Shape.VERTICAL_GLIDER_RIGHT,
index_y += 1 self.field.get_square_on_click_pos(pygame.mouse.get_pos()))
index_x = 0 if event.key == pygame.K_n:
for square in line: self.field.create_shape(Shape.GLIDER_LEFT_DOWN,
index_x += 1 self.field.get_square_on_click_pos(pygame.mouse.get_pos()))
if square.rect.collidepoint(pygame.mouse.get_pos()): if event.key == pygame.K_m:
self.field.create_shape(Shape.VERTICAL_GLIDER, self.field.create_shape(Shape.GLIDER_RIGHT,
(int(index_y ), self.field.get_square_on_click_pos(pygame.mouse.get_pos()))
int(index_x ))) if event.key == pygame.K_y:
self.field.create_shape(Shape.VERTICAL_GLIDER_RIGHT,
self.field.get_square_on_click_pos(pygame.mouse.get_pos()))
if event.key == pygame.K_x:
self.field.create_shape(Shape.VERTICAL_GLIDER_LEFT,
self.field.get_square_on_click_pos(pygame.mouse.get_pos()))
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:
@ -91,7 +96,7 @@ def run_game(game_state: GameState):
time_elapsed_since_last_action += clock.get_time() time_elapsed_since_last_action += clock.get_time()
if game_state.is_evolving: if game_state.is_evolving:
if time_elapsed_since_last_action > 100: if time_elapsed_since_last_action > 10:
# start = ti.time() # start = ti.time()
game_state.update_borders() game_state.update_borders()
game_state.evolve() game_state.evolve()

View File

@ -2,4 +2,11 @@ from enum import Enum
class Shape(Enum): class Shape(Enum):
VERTICAL_GLIDER = 1 HORIZONTAL_GLIDER_LEFT = 1
HORIZONTAL_GLIDER_RIGHT=2
GLIDER_LEFT_DOWN = 3
GLIDER_RIGHT=4
VERTICAL_GLIDER_RIGHT=5
VERTICAL_GLIDER_LEFT=6

View File

@ -1,23 +1,40 @@
from operator import itemgetter
from Code import Config from Code import Config
from Code.UI.Shape import Shape
class Shapes: 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): def create_shape(self, start_square_pos: tuple, squares, type):
return self._create_shape(start_square_pos, squares, Structures.shapes[type])
def _get_size(self, points):
x = max(max(points, key=itemgetter(0)))
y = max(max(points, key=itemgetter(1)))
return (x, y)
def _create_shape(self, start_square_pos: tuple, squares, points):
if self._check_bounderies(self._get_size(points), start_square_pos, squares):
for point in points: for point in points:
squares[start_square_pos[0]+point[1]][start_square_pos[1]+point[0]].active = True squares[start_square_pos[0] + point[1]][start_square_pos[1] + point[0]].active = True
return squares return squares
def _creat_shape(self,start_square_pos: tuple, squares):
def _check_bounderies(self, bounderies, start_square_pos: tuple, field): def _check_bounderies(self, bounderies, start_square_pos: tuple, field):
x_valid = (Config.GeneralConfig.fields_amount_x-2 - start_square_pos[1]) > bounderies[0] print(bounderies)
y_valid = (Config.GeneralConfig.fields_amount_y-2 - start_square_pos[1]) > bounderies[1] delta_start_pos_x = start_square_pos[0]
delta_start_pos_y = start_square_pos[1]
x_valid = (Config.GeneralConfig.fields_amount_x - 2 - int(delta_start_pos_x)) > bounderies[0]
y_valid = (Config.GeneralConfig.fields_amount_y - 2 - int(delta_start_pos_y)) > bounderies[1]
return x_valid and y_valid return x_valid and y_valid
class Structures:
shapes = {Shape.GLIDER_LEFT_DOWN: [(0, 0), (1, 0), (2, 0), (2, 1), (1, 2)],
Shape.HORIZONTAL_GLIDER_LEFT: [(0, 0), (1, 0), (2, 0), (3, 0), (4, 1), (4, 3), (0, 1), (0, 2), (1, 3)],
Shape.HORIZONTAL_GLIDER_RIGHT: [(0, 1), (0, 3), (1, 0), (3, 0), (2, 0), (4, 0), (4, 1), (4, 2), (3, 3)],
Shape.GLIDER_RIGHT: [(0, 2), (1, 0), (1, 2), (2, 1), (2, 2)],
Shape.VERTICAL_GLIDER_RIGHT: [(1, 0), (3, 0), (0, 1), (0, 3), (0, 2), (0, 4), (1, 4), (2, 4), (3, 3)],
Shape.VERTICAL_GLIDER_LEFT: [(0, 0), (0, 1), (0, 2), (0, 3), (1, 4), (3, 4), (1, 0), (2, 0), (3, 1)]
}

37
README.md Normal file
View File

@ -0,0 +1,37 @@
# Game of Life über mehrere Monitore
Implementierung des berühmten [Conway's Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) als verteiltes System.
Jeder Teilnehmer hat einen Bereich in dem er Game of Life berechnet und seine Kanten mit den andren Teilnehmer austauscht.
Die gesamte Koordination erfolgt dezentral, Kommunikation ist immer p2p-basiert.
## Einstieg
Um an dem Spiel teilzunehmen, muss jeder Teilnehmer (außer der erste) beim Starten der Anwendung die IP-Adresse und den
Port eines anderen Teilnehmers angeben, mit dem er sich verbinden will.
Zusätzlich muss die Richtung der Kante, mit welcher er sich mit diesem verbinden will, angegeben werden.
Da jeder Teilnehmer an jeder seiner Kanten maximal mit einem anderen Teilnehmer verbunden sein kann, ist es möglich,
dass die Kante, die beim Einstieg gewählt wird, bereits besetzt ist.
Ist dies der Fall, wird der Anfragende automatisch an denjenigen weitergeleitet, der diese Kante besetzt.
Dies passiert so lange bis eine freie Kante gefunden wird und sich somit zwei Teilnehmer verbinden.
Wenn man sich also **rechts** von Teilnehmer 1 verbinden will, ist es nicht garantiert, dass man direkt mit Teilnehmer 1
verbunden wird, sondern nur, dass man räumlich **rechts** von Teilnehmer 1 liegt.
![Schema Verbindungsaufbau](./images/Verbindungsaufbau.drawio.svg)
## Suche
Die Suche ist recht simpel.
Jeder Teilnehmer kennt nur die Knoten, welche die für ihn relevanten Informationen haben und diese verändern sich im Laufe
der Zeit auch nicht.
## Verbreitung
Eine relevante Information, die an das gesamte Netz verbreitet werden muss, ist eine Zustandsänderung bezüglich der
Pausierung der Simulation.
Hierfür wird einfaches Flooding verwendet.
D.h. jeder Teilnehmer schickt den neuen Zustand an alle seine Nachbarn und diese senden ihn wiederum an ihre Nachbarn.
Da es nur zwei mögliche Zustände für den Pause-Zustand geben kann, ist Flooding ausreichend effizient, zyklische Nachrichten
werden vermieden, indem ein Teilnehmer die Information nicht mehr weiterleitet, wenn er sie bereits bekommen hat, sich also
schon im richtigen Zustand befindet.
## Zeitliche Synchronisation
Um sicherzustellen, dass alle Teilnehmer gleichzeitig den Entwicklungsschritt durchführen und somit der Randaustausch auch
korrekt funktioniert.

1
images/Verbindungsaufbau Normal file
View File

@ -0,0 +1 @@
<mxfile host="Electron" modified="2022-04-02T13:38:57.784Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/17.2.4 Chrome/96.0.4664.174 Electron/16.1.0 Safari/537.36" etag="XY84_pTroYphd-JZhxR3" version="17.2.4" type="device"><diagram id="AHhDoPRp-INCStSoD3Vf" name="Page-1">1VjbcpswEP0aP9bDHecxdtJ20stkJmmTPnUUWECtQFTINs7XV4AEyCS+pGlIXhLt0e4i7e5Z1kzsRVp+YChPvtAQyMQywnJin00syzT9mfhXIZsG8U2jAWKGQ6nUAVf4HiSo1JY4hEJT5JQSjnMdDGiWQcA1DDFG17paRIn+1BzFMACuAkSG6A0OedKgM9fo8I+A40Q92TTkToqUsgSKBIV03YPs84m9YJTyZpWWCyBV8FRcGrv3j+y2B2OQ8UMM6EXp399/Kv6cej/n32buBY/Sd7Y8G9+oC0Mo7i9FynhCY5ohct6hc0aXWQiVV0NInc5nSnMBmgL8BZxvZDLRklMBJTwlchdKzG976x+Vq6nlSvGslK5rYaOEjLPNbV/om1VyZ1dLyrC5YXWtRwMnoYIuWQA7oqUKELEY+A49q02v4AXQFMR5hB0Dgjhe6edAskDjVq/LoVjINB6RUul3hchSPulaQB5KRXLm2V2RtzHpZX2dYA5XOaqvvxZU1jOGirwhV4TLKvPSwQoYh3J3WIdhUAa+JIbsDJYn5XWPZxJKehRT2LMHzhmTC4bGBf9ALpg6F/wX5IJ1IBceKYIX4sKQDF9BrCyPiDPP75hYxdXqO7A7nIXLLH57DdGcGqajF4I3O9lTCbV0CQyLQAOTYIQJWVBCWX1z2zPQiekLvOCM/obejnXme8ZIBeX9Y0HVpqeMoU1PIac440XP82UFdM3Ksbaa1WzrZbtH3xXJ1Iu5OUFX2u1Vnl7t1rDzW6+h09vGK+v0/iBQHf8LlEWsGgoHPYJBkFQ1so2P+tqYuv2eceAENXX77cLc0yqekePem3hpGGNm9InvgCMHgVE7/aFVMOoY7T04ObAh/a8BkwyStNobv9duT9WOP3KvnQ3ieAMiKoxUf7NByIIlW9U0aio6PK1+wwsxIKgocKAHUCfd/+9vT61YmRtj6jjGiZYe2x1kx30gOwo7bsgZTCXtVxX1dGcr6w11pdWu8WafoyZSA0fHjl1tWapqNrSxSx+jOmvlnkZRAXyyXcI7Ry0hdt9kGvXuy5Z9/hc=</diagram></mxfile>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB