Skip to content
Snippets Groups Projects
Commit 25b4df08 authored by Hozen's avatar Hozen
Browse files

git not ignore packages src py files

parent ecbd4626
No related branches found
No related tags found
No related merge requests found
...@@ -10,6 +10,12 @@ ...@@ -10,6 +10,12 @@
# not ignore all .py files (config files) # not ignore all .py files (config files)
!/src !/src
/src/* /src/*
!/src/langton
!/src/utils
!/src/buttons
/src/langton/*
/src/utils/*
/src/buttons/*
!/src/**/*.py !/src/**/*.py
# not ignore executable # not ignore executable
......
"""!
@brief Package corresponding to all the functions specific to buttons
@author Durel Enzo
@author Mallepeyre Nourrane
@version 1.0
"""
from .button import Button
from .check_box import CheckBox
from .input_box import InputBox
from .menu import Menu
"""!
@brief Button package
@author Durel Enzo
@author Mallepeyre Nourrane
@version 1.0
"""
import pygame
from utils import color
class Button:
"""!@brief Represent a Button"""
def __init__(self, pos, size, text='', fun=None):
"""!@brief Construct Button object
@param pos A tuple position of top left button corner
@param size A tuple represent the size of button (width, height)
@param text String affiliate to the button
@param fun Function reference for button event
"""
# RECTANGLE #
self.rect = pygame.Rect(pos, size) # rect collison button
# COLORS #
self.inactive_color = color.INACTIVE_BUTTON_COLOR # when button inactive
self.active_color = color.ACTIVE_BUTTON_COLOR # when button is clicked on
self.disable_color = color.DISABLE_BUTTON_COLOR
# self.disable_color = DISABLE_BUTTON_COLOR # when button disabled
self.color = color.INACTIVE_BUTTON_COLOR # current color
self.text_color = color.TEXT_BUTTON_COLOR # text inside color
self.hover_color = color.HOVER_BUTTON_COLOR # when mouse on the button
# TEXT #
self.text = text # string text
self.font = pygame.font.Font(None, 32) # font of the text
self.txt_surf = self.font.render(text, True, self.text_color) # surface txt
# STATE #
self.active = False # if button is active
self.b_disable = False
# FUNCTION #
self.fun = fun # fonction reference
# STYLE #
self.border_radius = 4 # round corners of the button
def enable(self):
"""!@brief Enable the button
This method enable the button (the user can click on it).
"""
if self.b_disable:
self.b_disable = False
self.color = self.inactive_color
def disable(self):
"""!@brief Disable the button
This method disable the button (the user can't click on it).
"""
if not self.b_disable:
self.b_disable = True
self.color = self.disable_color # disable color
def draw(self, screen):
"""!@brief Draw the button
This method draw the button rectangle with pyGame draw.rect function
and the text with screen.blit function.
@param screen Pygame screen object where the button with be draw
@exception Exception Used if pyGame is under update
"""
try:
pygame.draw.rect(screen,
self.color,
self.rect,
border_radius=self.border_radius)
except Exception:
print("Mettez a jour PyGame")
pygame.draw.rect(screen,
self.color,
self.rect)
text_w = self.txt_surf.get_width()
text_h = self.txt_surf.get_height()
screen.blit(self.txt_surf,
(self.rect.x+self.rect.w/2-text_w/2,
self.rect.y+self.rect.h/2-text_h/2))
def handle_event(self, event):
"""!@brief User input method
This method operate users input with event.type pyGame attributs
@param event Event user input
"""
if self.b_disable:
return;
if event.type == pygame.MOUSEBUTTONDOWN:
"""mouse click down"""
if self.rect.collidepoint(event.pos):
self.active = True
self.color = self.active_color
if self.fun is not None:
self.fun()
elif event.type == pygame.MOUSEBUTTONUP:
"""mouse click up"""
self.active = False
if self.rect.collidepoint(event.pos):
self.color = self.hover_color
else :
self.color = self.inactive_color
elif event.type == pygame.MOUSEMOTION:
"""mouse hover"""
if self.rect.collidepoint(event.pos):
if self.active:
self.color = self.active_color
else:
self.color = self.hover_color
else:
self.color = self.inactive_color
def get_pos(self):
"""!@brief Get the button top left position
@return A tuple of the position (x, y)
"""
return (self.rect.x, self.rect.y)
def get_size(self):
"""!@brief Get the button size
@return A tuple of the size (w, h)
"""
return (self.rect.w, self.rect.h)
"""!
@brief CheckBox package
@author Durel Enzo
@author Mallepeyre Nourrane
@version 1.0
"""
import pygame
import time
from utils import color
from buttons import Button
class CheckBox(Button):
"""!@brief Represent a CheckBox"""
def __init__(self, pos, size, text='', fun=None):
super().__init__(pos, size, text=text, fun=fun)
# TEXT #
# self.check_rect = pygame.Rect(pos[0], pos[1], 20, 20)
# FONT #
self.font = pygame.font.Font(None, size[1])
self.txt_surf = self.font.render(text, True, self.text_color) # surface txt
# COLORS #
self.color = color.INACTIVE_CB_COLOR
self.inactive_color = color.INACTIVE_CB_COLOR
self.active_color = color.ACTIVE_CB_COLOR
self.disable_color = color.DISABLE_CB_COLOR
self.disable_active_color = color.DISABLE_ACTIVE_CB_COLOR
self.text_color = color.TEXT_IB_COLOR
# TIME #
self.delay = 1_000_000 # en ns
self.active_time = time.time_ns()
def disable(self):
if not self.b_disable:
self.b_disable = True
if self.active:
self.color = self.disable_active_color
else:
self.color = self.disable_color
def handle_event(self, event):
if self.b_disable:
return;
if event.type == pygame.MOUSEBUTTONUP:
if self.rect.collidepoint(event.pos):
self.active = not self.active
self.color = self.active_color if self.active else self.inactive_color
if self.fun is not None:
self.fun()
else:
print("CheckBox has no function.")
def draw(self, screen):
try:
pygame.draw.rect(screen,
self.color,
self.rect,
border_radius=self.border_radius)
except Exception:
print("You need to update PyGame.")
pygame.draw.rect(screen,
self.color,
self.rect)
text_h = self.txt_surf.get_height()
screen.blit(self.txt_surf,
(self.rect.x+self.rect.w+10, self.rect.y+self.rect.h/2-text_h/2))
"""!
@brief InputBox package
@author Durel Enzo
@author Mallepeyre Nourrane
@version 1.0
"""
import pygame
from utils import color
from buttons import Button
class InputBox(Button):
"""!@brief Represent an InputBox"""
def __init__(self, pos, size, text='', fun=None, max_len=5):
super().__init__(pos, size, text=text, fun=fun)
# RECT #
self.int_rect = pygame.Rect(pos[0]+5, pos[1]+5, size[0]-10, size[1]-10)
# COLORS #
self.color = color.INACTIVE_IB_COLOR
self.inactive_color = color.INACTIVE_IB_COLOR
self.active_color = color.ACTIVE_IB_COLOR
self.disable_color = color.DISABLE_IB_COLOR
self.int_color = color.dic["white"]
self.text_color = color.TEXT_IB_COLOR
# TEXT #
self.max_len = max_len
def handle_event(self, event):
if self.b_disable:
return;
if event.type == pygame.MOUSEBUTTONUP:
if self.rect.collidepoint(event.pos):
self.active = not self.active
else:
self.active = False
self.color= self.active_color if self.active else self.inactive_color
if event.type == pygame.KEYDOWN:
if self.active:
if event.key == pygame.K_RETURN:
if self.fun is not None:
self.fun(self.text)
else:
print("Button has no function.")
self.text = ''
self.active = False
self.color = self.inactive_color
elif event.key == pygame.K_BACKSPACE:
self.text = self.text[:-1]
else:
self.text += event.unicode
if len(self.text) > self.max_len:
self.txt_surf = self.font.render("-" + self.text[len(self.text)-self.max_len+1:],
True,
self.text_color)
else:
self.txt_surf = self.font.render(self.text, True, self.text_color)
def draw(self, screen):
try:
pygame.draw.rect(screen,
self.color,
self.rect,
border_radius=self.border_radius)
pygame.draw.rect(screen,
self.int_color,
self.int_rect,
border_radius=self.border_radius)
except Exception:
print("You need to update PyGame.")
pygame.draw.rect(screen,
self.color,
self.rect)
pygame.draw.rect(screen,
self.int_color,
self.int_rect)
text_w = self.txt_surf.get_width()
text_h = self.txt_surf.get_height()
screen.blit(self.txt_surf,
(self.rect.x+self.rect.w/2-text_w/2, self.rect.y+self.rect.h/2-text_h/2))
"""!
@brief Menu package
@author Durel Enzo
@author Mallepeyre Nourrane
@version 1.0
"""
import pygame
from utils import color
class Menu:
"""!@brief Represent a Menu"""
def __init__(self, pos, size, btn_list=[], color=color.MENU_COLOR):
"""!@brief Construct a Menu
@param pos A tuple position of top left Menu corner
@param size A tuple represent the size of Menu (width, height)
@param btn_list A list of button in the Menu
@param color The Color of the Menu
"""
self.rect = pygame.Rect(pos, size)
self.color = color
self.btn_list = btn_list
def draw(self, screen):
"""!@brief Draw the Menu
@param screen Screen pyGame attributs
"""
pygame.draw.rect(screen, self.color, self.rect)
for x in self.btn_list:
x.draw(screen)
def disable(self, *args):
"""!@brief Disable some button of Menu
@param args variadic args which need to be disable
"""
if len(args) == 0:
args = self.btn_list
for button in args:
button.disable()
def enable(self, *args):
"""!@brief Enable some button of Menu
@param args variadic args which need to be enable
"""
if len(args) == 0:
args = self.btn_list
for button in args:
button.enable()
def handle_event(self, event, *args):
"""!@brief Enable some button of Menu
@param event User event
@param args variadic args which need to be handled
"""
if len(args) == 0:
args = self.btn_list
for button in args:
button.handle_event(event)
"""!
@brief Package corresponding to all the functions specific to Langton
@author Durel Enzo
@author Mallepeyre Nourrane
@version 1.0
"""
from .simulation import Simulation
from .fourmi import Fourmi
from .case import Case
from .plateau import Plateau
"""!
@brief langton.case package
@author Durel Enzo
@author Mallepeyre Nourrane
@version 1.0
"""
import pygame
from utils import color
class Case:
"""!@brief Represent a Case"""
def __init__(self, size=(1, 1), pos=(0, 0)):
"""!@brief Construct Case object
@param size Pixel size of the case (pygame)
@param pos Position of the case
"""
self.screen = pygame.display.get_surface()
self.cur_color = color.dic["white"]
self.w, self.h = size
self.x, self.y = pos
def set_color(self, colour):
"""!@brief Set a color the the Case
@param colour A tuple of int representing a rgb color
"""
self.cur_color = self.validate_color(colour)
def get_color(self):
"""!@brief get the Case color
@return the Case color
"""
return self.cur_color
def validate_color(self, colour):
"""!@brief Verify if it's a valid colour
@param colour A tuple of int representing a rgb colour
@return The valide colour
@exception Exception Not a valid colour
"""
if len(colour) == 3:
for i in colour:
if i < 0 or i > 255:
raise(Exception("Invalide element in colour argument"))
else:
raise(Exception("Invalide length of colour argument"))
return colour
def draw(self):
"""!@brief draw the Case"""
pygame.draw.rect(
self.screen,
self.get_color(),
pygame.Rect(self.x*self.w,
self.y*self.h,
self.w,
self.h))
"""!
@brief langton.fourmi package
@author Durel Enzo
@author Mallepeyre Nourrane
@version 1.0
"""
import pygame
from utils import color
class Fourmi :
"""!@brief Represent a Fourmi de Langton"""
def __init__(self, coords=(0, 0), taille=4, speed=1, direction=0,
color=[(255, 255, 255), (0, 0, 0)], behavior="LR"):
"""!@brief Constuct Fourmi object
This is the constructor of the Fourmi object.
@param coords coordinate where ant takes place (default (0, 0))
@param taille number of pixels represent an ant (default 4)
@param speed number of case ant moving (default 1)
@param direction index of first direction (default 0 ("up"))
@param color list of tuple represent the list of color used for
behavior (default: (255, ...), (0, ...))
@param behavior string representation of the ant behavior (default:
'LR')
"""
# Ant position #
self.x = int(coords[0]) # current position
self.y = int(coords[1])
self.begin_x = int(coords[0]) # save begin position
self.begin_y = int(coords[1])
# Ant movement #
self.speed = speed # ant speed (pixel per movement)
self.rotation = ['up', 'right', 'down', 'left'] # ant list rotation
self.nb_direction = len(self.rotation) # length of rotation available
self.begin_direction = direction%self.nb_direction #save init direction
self.index_direction = self.begin_direction #current index of direction
self.direction = self.rotation[self.index_direction]
# Graphics attributes #
self.screen = pygame.display.get_surface()
self.taille = taille
self.out = False
# Ant behavior #
self.color = color
self.behavior = behavior
def set_out(self):
"""!@brief Ant is out
This method makes the ant out. She can't do anything anymore.
"""
self.out = True
def is_out(self):
"""!@brief Ask if fourmi is out
This method return the out state of the ant.
@return boolean
"""
return self.out
def one_step(self, case):
"""!@brief An ant complete movement
This method make the ant follows a complete movement (rotate, change
color, move).
@param case Case where the ant begin its step
"""
self.rotate(case)
self.inverse_color_case(case)
self.conduct()
def reset(self):
"""!@brief Reset the Ant
This method hard reset the ant at its beginning direction, position.
"""
self.index_direction = self.begin_direction
self.x = self.begin_x
self.y = self.begin_y
self.direction = self.rotation[self.index_direction]
self.draw()
def inverse_color_case(self, case):
"""!@brief Inverse Case color
This method change the color of the case where the ant is.
@param case Case where the ant is
"""
index = self.color.index(case.get_color())
case.set_color(self.color[(index+1)%len(self.color)])
def rotate(self, case):
"""!@brief Rotation the ant
This method rotate the ant following the ant's behavior.
@param case Case where the ant is.
"""
index = self.color.index(case.get_color())
index_behavior = self.behavior[index]
if index_behavior == 'L':
self.rotate_left()
elif index_behavior == 'R':
self.rotate_right()
def conduct(self) :
"""!@brief Move the ant following its conduct
This method moves the ant compare to the conduct wanted. Here the ant
move in the direction where it watches.
"""
if self.direction == 'up' :
self.move_up()
elif self.direction == 'down' :
self.move_down()
elif self.direction == 'left' :
self.move_left()
elif self.direction == 'right' :
self.move_right()
def move(self, coords=(0, 0)):
"""!@brief Vectorial ant movement
This method reprensent primitive ant movement. It's update the x and y
of the ant.
@param coords A tuple represents a movement vector (default (0,0))
"""
self.x += int(coords[0])
self.y += int(coords[1])
def move_down(self):
"""!@brief Ant move down
This method calls move() with a down vector (0, y).
"""
self.move((0, self.speed))
def move_up(self):
"""!@brief Ant move up
This method calls move() with a up vector (0, -y).
"""
self.move((0, -self.speed))
def move_right(self):
"""!@brief Ant move right
This method calls move() with a right vector (x, 0).
"""
self.move((self.speed, 0))
def move_left(self):
"""!@brief Ant move left
This method calls move() with a left vector (-x, 0).
"""
self.move((-self.speed, 0))
def rotate_right(self):
"""!@brief Ant rotate left
This method rotate the ant in its right. It means the index of the
current rotation is increment by one in the list of rotation.
"""
self.direction = \
self.rotation[(self.index_direction+1)%self.nb_direction]
self.index_direction += 1
def rotate_left(self):
"""!@brief Ant rotate left
This method rotate the ant in its left. It means the index of the
current rotation is decrement by one in the list of rotation.
"""
self.direction = \
self.rotation[(self.index_direction-1)%self.nb_direction]
self.index_direction -= 1
def draw(self):
"""!@brief Ant draw
This method draw the ant with pyGame draw.rect function. Ant color is
red.
"""
pygame.draw.rect(self.screen, color.dic["red"], pygame.Rect(self.x,
self.y,
self.taille,
self.taille))
def __str__(self):
"""!@brief Ant string representation
This method redefine the ant's toString() representation
"""
return f"Fourmi a coord: {self.x}, {self.y}" \
+ f" rotation {self.direction}"
"""!
@brief langton.plateau
@author Durel Enzo
@author Mallepeyre Nourrane
@version 1.0
"""
import pygame
import random
# from multiprocessing import Process, cpu_count
from utils import color
from langton import Case
class Plateau :
"""!@brief Represent a Plateau"""
def __init__(self, behavior, color, taille=(1, 1), res=(4, 4)):
"""!@brief Construct Plateau object
@param behavior String representation of the Plateau behavior
@param color A tuple a int reprensent a rgb color
@param taille tuple represent number of Case (default (1, 1))
@param res Pixel representation of each Case (default (4, 4))
"""
self.w, self.h = taille
self.schema = [[Case(res, (j, i))
for j in range(self.w)]
for i in range(self.h)]
# SCREEN #
self.screen = pygame.display.get_surface()
# BEHAVIOR #
self.behavior = behavior
self.color = color
# # MULTIPROCESSING #
# self.cpu = cpu_count()
# self.ratio = int(self.w/self.cpu)
# self.intervalles = [([i*self.ratio, 0],
# [(i+1)*self.ratio, self.h])
# for i in range(self.cpu-1)]
# self.intervalles.append(([self.ratio*(self.cpu-1), 0],
# [self.w, self.h]))
# def multiprocessing(self, fun):
# """!@brief create a multiprocess
# @param fun function reference which call in process
# """
# process = [Process(target=fun,
# args=self.intervalles[i])
# for i in range(self.cpu)]
# for x in process: x.start()
# for x in process: x.join()
# def draw_mp(self):
# """!@brief draw multiprocessing
# """
# self.multiprocessing(self.draw)
def reset(self, start=[0, 0], end=[None, None]):
"""!@brief reset schema in white
@param start list of int index where start to draw (default (0, 0))
@param end list of int index where end to draw (default (None, None))
"""
start, end = self.valide_intervalle(start, end)
for i in range(start[1], end[1]):
for j in range(start[0], end[0]):
self.set_color_case((i, j), color.dic["white"])
# self.draw_mp()
self.draw()
def random(self, start=[0, 0], end=[None, None]):
"""!@brief random color schema
@param start list of int index where start to draw (default (0, 0))
@param end list of int index where end to draw (default (None, None))
"""
start, end = self.valide_intervalle(start, end)
for i in range(start[1], end[1]):
for j in range(start[0], end[0]):
r = random.choice(self.color)
self.set_color_case((i, j), r)
# self.draw_mp()
self.draw()
def set_color_case(self, pos, colour):
"""!@brief set color in a Case
@param pos tuple of position of the Case
@param colour colour to set in the Case
"""
x, y = pos
self.schema[x][y].set_color(colour)
def draw_case(self, pos):
"""!@brief draw a case in specific schema position
@param pos tuple of position of the Case
"""
x, y = pos
self.schema[x][y].draw()
def valide_intervalle(self, start, end):
"""!@brief valide start & end in schema
@param start list of int index where start to draw (default (0, 0))
@param end list of int index where end to draw (default (None, None))
@return a valid couple of start & end (valid index)
"""
if end[0] == None: # if end_x not setting in draw()
end[0] = self.w
if end[1] == None: # if end_y not setting in draw()
end[1] = self.h
else :
if start[0] < 0:
start[0] = start[0]%self.w
if start[1] < 0:
start[1] = start[1]%self.h
if end[0] > self.w:
end[0] = end[0]%self.w
if end[1] > self.h:
end[1] = end[1]%self.h
return start, end
def draw_ant(self, pos):
"""!@brief draw optimize cases near ant
@param pos postion of the ant
"""
y, x = pos
self.draw_case((x, y))
self.draw_case((x, (y+1)%self.w))
self.draw_case((x, (y-1)%self.w))
self.draw_case(((x+1)%self.h, y))
self.draw_case(((x-1)%self.h, y))
def draw(self, start=[0,0], end=[None, None]):
"""!@brief default color schema
@param start list of int index where start to draw (default (0, 0))
@param end list of int index where end to draw (default (None, None))
"""
start, end = self.valide_intervalle(start, end)
for i in range(start[1], end[1]):
for j in range(start[0], end[0]):
# self.draw_case((i, j))
self.schema[i][j].draw()
def get_case(self, x, y, res):
"""!@brief Get a Case in a position
@param x Horizontal position of the Case
@param y Vertical position of the Case
@param res Resolution of the Case
"""
case = self.schema[y//res][x//res]
return case
def set_behavior(self, color, behavior):
"""!@brief Modify grid color & behavior
@param color list of color
@param behavior string of the simulation behavior
"""
self.color = color
self.behavior = behavior
def __str__(self):
"""!@brief Redefine toString() Plateau method"""
s = ""
for i in self.schema:
for j in i:
s += f"{j.cur_color} "
s += f"\n"
return s
"""!
@brief Simulation package
@author Durel Enzo
@author Mallepeyre Nourrane
@version 1.0
"""
import pygame
import random
import langton as lgt
from buttons import Button, Menu, CheckBox, InputBox
from utils import color, const
class Simulation:
"""!@brief Represent a Simulation"""
def __init__(self,
size_screen=const.DEFAULT_SCREEN_SIZE,
size_plateau=const.DEFAULT_PLATEAU_SIZE,
res=const.DEFAULT_RESOLUTION):
"""!@brief Construct Simulation object
@param size_screen Size of the window
@param size_plateau Size of the grid where stand ants
@param res Number of pixel define size of Case and Fourmi
"""
self.size_screen = size_screen # size of the screen
self.size_plateau = size_plateau # size of the plateau
self.res = res # resolution of a case / fourmi
# PYGAME #
self.screen = pygame.display.set_mode(size_screen, pygame.DOUBLEBUF)
pygame.display.set_caption("Fourmi de Langton") # title set
self.clock = pygame.time.Clock() # clock to control the framerate
# STATES #
self.end = False # if simulation end
self.run = False # simulation loop
self.done = False
# DEBUG #
self.debug = False
self.iteration = 0
# BEHAVIOR #
self.behavior = ""
self.color = []
# PLATEAU INIT #
self.plateau = lgt.Plateau(self.behavior,
self.color,
taille=(self.size_plateau[0]//self.res,
self.size_plateau[1]//self.res),
res=(self.res, self.res))
self.set_behavior("LR")
# Fourmi(s) Init #
self.nb_fourmi = 0
self.fourmi_list = []
# Button #
self.btn_debug = Button((self.size_screen[0]-260, 20),
const.BUTTON_SIZE,
text="Debug",
fun=self.active_debug)
self.btn_play = Button((self.size_screen[0]-260,
self.size_plateau[1]-70),
const.BUTTON_SIZE,
text="Play",
fun=self.play)
self.btn_stop = Button((self.size_screen[0]-120,
self.size_plateau[1]-70),
const.BUTTON_SIZE,
text="Stop",
fun=self.stop)
self.btn_reset = Button((self.size_screen[0]-260, 90),
const.BUTTON_SIZE,
text="Reset",
fun=self.reset)
self.btn_next = Button((self.size_screen[0]-260,
self.size_plateau[1]-140),
const.BUTTON_SIZE,
text="Next",
fun=self.next_step)
self.btn_add_f = Button((self.size_screen[0]-260,
self.size_plateau[1]-210),
const.BUTTON_SIZE,
text="Add",
fun=self.add_fourmi)
# InputBox #
self.ib_next = InputBox((self.size_screen[0]-120,
self.size_plateau[1]-140),
const.BUTTON_SIZE,
fun=self.set_next)
self.ib_behavior = InputBox((self.size_screen[0]-260, 160),
(240, 50),
fun=self.set_behavior,
max_len=12)
# CheckBox #
self.cb_infinite = CheckBox((self.size_screen[0]-260, 230),
(20, 20),
text="Infinite",
fun=self.infinite)
self.cb_random_grid = CheckBox((self.size_screen[0]-260, 270),
(20, 20),
text="Random Grid",
fun=self.set_random_grid)
self.infinite_ant = False
self.random_grid = False
# Menu #
self.menu = Menu((size_plateau[0], 0),
(size_screen[0]-size_plateau[0], size_screen[1]),
btn_list=[self.btn_debug, self.btn_play,
self.btn_stop, self.btn_reset,
self.btn_next, self.btn_add_f,
self.ib_next, self.ib_behavior,
self.cb_infinite, self.cb_random_grid])
# Simulation #
self.it = self.__iter__()
self.next_time = 1
def start(self):
"""!@brief Global start, here when ants aren't running"""
self.plateau.reset()
self.menu.draw(self.screen)
# self.plateau.compare_fun(self.plateau.draw, self.plateau.draw_mp)
while not self.done:
self.menu.enable() # enable all buttons in the menu
if self.nb_fourmi <= 0:
self.menu.disable(self.btn_play,
self.btn_next,
self.ib_next,
self.btn_stop,
self.btn_debug)
if self.nb_fourmi > 0:
self.menu.disable(self.ib_behavior)
self.handle_event()
pygame.display.update() # update the screen
self.clock.tick(30) # control the max framerate
def stop(self):
"""!@brief Stop the game by set self.run to false"""
self.run = False
def add_fourmi(self):
"""!@brief Add an ant on the grid"""
if not self.run :
not_click = True
while not_click:
self.clock.tick(30) # control the max framerate
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
not_click = False
if event.pos[0] >= 0 \
and event.pos[0] < self.size_plateau[0] \
and event.pos[1] >= 0 \
and event.pos[1] < self.size_plateau[1] :
e_x, e_y = event.pos
f_x = (e_x//self.res)*self.res
f_y = (e_y//self.res)*self.res
f_new = lgt.Fourmi(coords=(f_x, f_y),
taille=self.res,
speed=self.res,
direction=0,
behavior=self.behavior,
color=self.color)
self.fourmi_list.append(f_new)
self.nb_fourmi += 1
f_new.draw()
else:
print("Can't create an ant here.")
else:
print("Can't add an ant when simulation is running..")
def reset(self):
"""!@brief Reset the simulation"""
if not self.run :
if self.random_grid:
self.plateau.random()
else :
self.plateau.reset()
self.fourmi_list = [].copy()
self.nb_fourmi = 0
self.iteration = 0
self.end = False
self.menu.draw(self.screen)
else :
print("Can't reset when simulation is running")
def next_step(self):
"""!@brief Play simulation iterator next_number times, (default 1)
@exception StopIteration If Simulation ended
@exception Exception If Simulation already run
"""
try:
if not self.end and not self.run:
for _ in range(self.next_time):
next(self.it)
except StopIteration:
print("Simulation ended")
except Exception:
print("Already in function")
def play(self):
"""!@brief Play Simulation loop"""
try:
if not self.run:
if not self.end:
self.run = True
while self.run:
next(self.it)
if self.end :
print("Simulation ended.")
except Exception:
print("Already playing")
raise(Exception)
def __iter__(self):
"""!@brief Simulation iterator"""
while True:
self.iteration += 1
self.handle_event()
self.fourmi_step()
self.fourmi_out()
self.draw()
pygame.display.update() # update the screen
# self.clock.tick(60) # control the max framerate
yield;
def draw(self):
"""!@brief Draw the map and ants"""
for f in self.fourmi_list:
if not self.end:
self.plateau.draw_ant((f.x//self.res, f.y//self.res))
f.draw()
def fourmi_out(self):
"""!@brief Check if an ant is out of index of the grid"""
for f in self.fourmi_list:
if f.x == self.size_plateau[0] \
or f.y == self.size_plateau[1] \
or f.x < 0 or f.y < 0:
if self.infinite_ant:
f.x = f.x%self.size_plateau[0]
f.y = f.y%self.size_plateau[1]
else:
self.run = False
self.end = True
def fourmi_step(self):
"""!@brief Move all ants once"""
for f in self.fourmi_list:
case = self.plateau.get_case(f.x, f.y, self.res)
f.one_step(case)
def handle_event(self):
"""!@brief Event listener user interactions: Button & Keyboard"""
for event in pygame.event.get():
self.menu.handle_event(event,
self.btn_debug,
self.btn_play,
self.btn_stop,
self.cb_infinite,
self.cb_random_grid)
if not self.run:
self.menu.handle_event(event,
self.btn_next,
self.ib_next,
self.btn_reset,
self.btn_add_f,
self.ib_behavior)
else:
self.menu.disable(self.btn_next,
self.ib_next,
self.btn_reset,
self.btn_add_f)
if event.type == pygame.QUIT:
self.run = False
self.end = True
self.done = True
self.menu.draw(self.screen)
if self.debug:
self.debuging()
def init_color(self):
"""!@brief Init random color from simulation behavior"""
color_list = []
color_tuple = []
color_list.append(color.dic["white"])
for _ in range(len(self.behavior)-1):
for _ in range(3):
color_tuple.append(random.randint(0, 255))
color_list.append(tuple(color_tuple.copy()))
color_tuple = [].copy()
self.color = color_list.copy()
def active_debug(self):
"""!@brief Change boolean value for debug option button"""
self.debug = not self.debug
def debuging(self):
"""!@brief Print the total of iteration since the simulation is
running"""
# print(f"Iteration : {self.iteration}")
txt_surf = self.btn_debug.font.render(f"{self.iteration}",
True,
color.dic["white"])
pos = list(self.btn_debug.get_pos())
size = list(self.btn_debug.get_size())
text_w = txt_surf.get_width()
text_h = txt_surf.get_height()
pos = (self.size_screen[0]-70-text_w//2,
20 + size[1]//2 - text_h//2),
self.screen.blit(txt_surf, tuple(pos))
def set_next(self, text):
"""!@brief Set the step for next function"""
try:
if int(text) < 500:
self.next_time = int(text)
print(f"Set next step to {self.next_time}")
else:
print("Le nombre de pas en 1 fois doit être < 500")
except Exception:
print("Invalide next value.")
def set_behavior(self, text):
"""!@brief Set the behavior before add ants and game start"""
for letter in text:
if letter != "R" and letter != "L":
print("Invalide behavior, must be a text of 'R' and 'L'.")
return;
self.behavior = text
self.init_color()
self.plateau.set_behavior(self.color, self.behavior)
print(f"Set simulation behavior to {self.behavior}")
def infinite(self):
"""!@brief Define if ants are in an infinite place"""
self.infinite_ant = not self.infinite_ant
if self.infinite_ant and self.end :
self.end = False
for f in self.fourmi_list:
f.x %= self.size_plateau[0]
f.y %= self.size_plateau[1]
print(f"Set infinite board to {self.infinite_ant}")
def set_random_grid(self):
"""!@brief Random Grid CheckBox function"""
self.random_grid = not self.random_grid
print(f"Set random grid to {self.random_grid}")
"""!
@brief Package corresponding to all the const need for the program
@author Durel Enzo
@author Mallepeyre Nourrane
@version 1.0
"""
from .color import *
from .const import *
"""!
@brief Package of all colors used in the program
@author Durel Enzo
@author Mallepeyre Nourrane
@version 1.0
"""
# color dictionnary (basic color) #
dic = dict()
dic["white"] = (255, 255, 255)
dic["black"] = (0, 0, 0)
dic["red"] = (255, 0, 0)
dic["green"] = (0, 255, 0)
# Button special colors #
INACTIVE_BUTTON_COLOR = (46, 107, 81)
ACTIVE_BUTTON_COLOR = (69, 153, 125)
HOVER_BUTTON_COLOR = (49, 122, 110)
DISABLE_BUTTON_COLOR = (55, 64, 60)
TEXT_BUTTON_COLOR = dic["white"]
# Input Box special colors #
INACTIVE_IB_COLOR = (46, 107, 81)
ACTIVE_IB_COLOR = (186, 191, 119)
DISABLE_IB_COLOR = (55, 64, 60)
TEXT_IB_COLOR = dic["black"]
# Check Box special colors #
INACTIVE_CB_COLOR = (46, 107, 81)
ACTIVE_CB_COLOR = (186, 191, 119)
DISABLE_CB_COLOR = (55, 64, 60)
DISABLE_ACTIVE_CB_COLOR = (87, 56, 53)
TEXT_CB_COLOR = dic["black"]
# Menu colors #
MENU_COLOR = (103, 168, 120)
"""!
@brief Package of all constants used in the program
@author Durel Enzo
@author Mallepeyre Nourrane
@version 1.0
"""
# Game constantes #
DEFAULT_SCREEN_SIZE = (1280, 720)
DEFAULT_PLATEAU_SIZE = (1000, 720)
DEFAULT_RESOLUTION = 4
# Button constantes #
BUTTON_SIZE = (100, 50)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment