From 3181e2885f8841e68dec9ef809c7714d36212135 Mon Sep 17 00:00:00 2001 From: LL_Mehdi Date: Wed, 1 Dec 2021 17:40:08 +0100 Subject: [PATCH 01/11] Defined cell.py --- cell.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 cell.py diff --git a/cell.py b/cell.py new file mode 100644 index 0000000..8c626f9 --- /dev/null +++ b/cell.py @@ -0,0 +1,43 @@ +import pygame +from pygame.locals import Rect + +INACTIVE_COLOR = "#16302B" +ACTIVE_COLOR = "#C0E5C8" + + +class Cell: + def __init__(self, pos: tuple, dimensions: tuple, alive=False): + self.active = alive + self.future_state = None + self.rectangle = Rect(pos[0], pos[1], dimensions[0], dimensions[1]) + + def draw(self, surface): + """ + This method checks what state the cell is in, and draws it in the appropriate color on the provided surface + """ + color = ACTIVE_COLOR if self.active else INACTIVE_COLOR + return pygame.draw.rect(surface, color, self.rectangle) + + def __str__(self): + return "X" if self.active else "_" + + def flip(self): + self.active = not self.active + + def set_active(self): + self.active = True + + def set_inactive(self): + self.active = False + + def set_future_state(self, living_neighbors: int): + if self.active and (living_neighbors == 2 or living_neighbors == 3): + self.future_state = True + elif not self.active and living_neighbors == 3: + self.future_state = True + else: + self.future_state = False + + def update(self): + self.active = self.future_state + self.future_state = None From 4c50a48fff8a0436b14e0e3caa61ddf6e0a1567b Mon Sep 17 00:00:00 2001 From: LL_Mehdi Date: Wed, 1 Dec 2021 17:41:01 +0100 Subject: [PATCH 02/11] Defining grid.py --- grid.py | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 grid.py diff --git a/grid.py b/grid.py new file mode 100644 index 0000000..f2fd1d9 --- /dev/null +++ b/grid.py @@ -0,0 +1,104 @@ +from cell import Cell + +CELL_OFFSET = 2 +PADDING = 7 + + +class Grid: + def __init__(self, screen_dimensions: tuple, surface, width: int, height: int): + self.width = width + self.height = height + + screen_width, screen_height = screen_dimensions + effective_width, effective_height = screen_width - 2 * PADDING - (CELL_OFFSET * (width - 1)), screen_height - 2 * PADDING - (CELL_OFFSET * (height - 1)) + + cell_width, cell_height = (effective_width / width, effective_height / height) + self.cells = [ + [Cell((PADDING + x * (cell_width + CELL_OFFSET), PADDING + y * (cell_height + CELL_OFFSET)), (cell_width, cell_height)) for x in range(width)] for y in + range(height)] + self.rects = [] + + def __str__(self): + output = "" + for row in self.cells: + for cell in row: + output += str(cell) + output += "\n" + return output + + def flip(self, col: int, row: int): + if col < 0 or col >= self.width: + raise RuntimeError( + f"error updating cell at column {col}: expected column number between 0 and {self.width - 1}") + if row < 0 or row >= self.height: + raise RuntimeError( + f"error updating cell at row {row}: expected column number between 0 and {self.height - 1}") + + self.cells[row][col].flip() + + def __compute_future_states(self): + # navigate through the grid, for each cell find its valid neighbors + for row_index, row in enumerate(self.cells): + for col_index, cell in enumerate(row): + cell.set_future_state(self.__count_living_neighbors(col_index, row_index)) + + def update(self): + self.__compute_future_states() + for row in self.cells: + for cell in row: + cell.update() + + def draw(self, surface): + self.rects = [] + for row in self.cells: + self.rects.append([cell.draw(surface) for cell in row]) + + def check_clicks(self, pos): + for i, row in enumerate(self.rects): + for j, rect in enumerate(row): + if rect.collidepoint(pos): + print(f'collided with {rect} at pos {i}, {j}') + self.cells[i][j].flip() + + def reset(self): + for row in self.cells: + for cell in row: + cell.set_inactive() + + # cells have up to 8 neighbours, except cells in the boundary rows and columns. + # this iterator yields a given position's neighbors + def __count_living_neighbors(self, col: int, row: int): + if col < 0 or col >= self.width: + raise RuntimeError( + f"error updating cell at column {col}: expected column number between 0 and {self.width - 1}") + if row < 0 or row >= self.height: + raise RuntimeError( + f"error updating cell at row {row}: expected column number between 0 and {self.height - 1}") + + count = 0 + # top left + if row > 0 and col > 0 and self.cells[row - 1][col - 1].active: + count += 1 + # top + if row > 0 and self.cells[row - 1][col].active: + count += 1 + # top right + if row > 0 and col < self.width - 1 and self.cells[row - 1][col + 1].active: + count += 1 + # right + if col < self.width - 1 and self.cells[row][col + 1].active: + count += 1 + # bottom right + if row < self.height - 1 and col < self.width - 1 and self.cells[row + 1][col + 1].active: + count += 1 + # bottom + if row < self.height - 1 and col < self.width - 1 and self.cells[row + 1][col].active: + count += 1 + # bottom left + if row < self.height - 1 and col < self.width - 1 and self.cells[row + 1][col - 1].active: + count += 1 + # left + if col < self.width - 1 and self.cells[row][col - 1].active: + count += 1 + + return count From 43da80416c278eda32c8e09f8aac31eae1ff9c96 Mon Sep 17 00:00:00 2001 From: LL_Mehdi Date: Wed, 1 Dec 2021 17:43:09 +0100 Subject: [PATCH 03/11] added controller.py and game.py, removed some debug statements --- controller.py | 53 ++++++++++++++++++++++++++++ game.py | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++ grid.py | 1 - 3 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 controller.py create mode 100644 game.py diff --git a/controller.py b/controller.py new file mode 100644 index 0000000..1407146 --- /dev/null +++ b/controller.py @@ -0,0 +1,53 @@ +import pygame +import pygame_gui + + +class EventController: + def register_ui_element(self, name, element_reference): + setattr(self, name, element_reference) + + def assess(self, event, state): + if event.type == pygame.QUIT: + return handle_quit(state) + + if event.type == pygame.USEREVENT and event.user_type == pygame_gui.UI_BUTTON_PRESSED: + if event.ui_element == self.__getattribute__('start'): + return handle_start_pause(state, event.ui_element) + if event.ui_element == self.__getattribute__('reset'): + return handle_reset(state) + if event.ui_element == self.__getattribute__('next'): + return handle_next(state) + else: + return {} + + if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: + return handle_grid_click(state) + + return {} + + +def handle_quit(state): + state['is_running'] = False + return state + + +def handle_reset(state): + state['grid'].reset() + return state + + +def handle_start_pause(state, button): + state['animation_running'] = not state['animation_running'] + button.set_text('Pause') if state['animation_running'] else button.set_text('Start') + return state + + +def handle_grid_click(state): + pos = pygame.mouse.get_pos() + state['grid'].check_clicks(pos) + return {} + + +def handle_next(state): + state['grid'].update() + return {} \ No newline at end of file diff --git a/game.py b/game.py new file mode 100644 index 0000000..d24ac3d --- /dev/null +++ b/game.py @@ -0,0 +1,95 @@ +import pygame +import pygame_gui + +from grid import Grid +from controller import EventController + +GAME_BACKGROUND_COLOR = '#0F0F00' +UI_BACKGROUND_COLOR = '#FFFFFF' + +pygame.init() +WINDOW_WIDTH = 1000 +WINDOW_HEIGHT = 600 +UI_HEIGHT = 100 + +GAME_HEIGHT = WINDOW_HEIGHT - UI_HEIGHT + +BUTTON_WIDTH = 100 +BUTTON_HEIGHT = 40 + +GAME_BACKGROUND_COLOR = '#000000' +UI_BACKGROUND_COLOR = '#000000' + +pygame.display.set_caption('Quick Start') +window_surface = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT)) + +game_background = pygame.Surface((WINDOW_WIDTH, GAME_HEIGHT)) +game_background.fill(pygame.Color(GAME_BACKGROUND_COLOR)) + +ui_background = pygame.Surface((WINDOW_WIDTH, UI_HEIGHT)) +ui_background.fill(pygame.Color(UI_BACKGROUND_COLOR)) + +manager = pygame_gui.UIManager((WINDOW_WIDTH, WINDOW_HEIGHT)) + +start_button = pygame_gui.elements.UIButton( + relative_rect=pygame.Rect((70, GAME_HEIGHT + 30), (BUTTON_WIDTH, BUTTON_HEIGHT)), + text='Start', + manager=manager) + +reset_button = pygame_gui.elements.UIButton( + relative_rect=pygame.Rect((2*70 + BUTTON_WIDTH, GAME_HEIGHT + 30), (BUTTON_WIDTH, BUTTON_HEIGHT)), + text='Reset', + manager=manager) + +next_button = pygame_gui.elements.UIButton( + relative_rect=pygame.Rect((3*70 + 2*BUTTON_WIDTH, GAME_HEIGHT + 30),(BUTTON_WIDTH, BUTTON_HEIGHT)), + text='Next', + manager=manager) + +rules_button = pygame_gui.elements.UIButton( + relative_rect=pygame.Rect((4*70 + 3*BUTTON_WIDTH, GAME_HEIGHT + 30),(BUTTON_WIDTH, BUTTON_HEIGHT)), + text='Rules', + manager=manager) + +g = Grid((WINDOW_WIDTH, GAME_HEIGHT), window_surface, 15, 15) +g.flip(2, 1) +g.flip(3, 2) +g.flip(1, 3) +g.flip(2, 3) +g.flip(3, 3) + +clock = pygame.time.Clock() + +game_state = {'is_running': True, 'animation_running': False, 'grid': g} +controller = EventController() +controller.register_ui_element('start', start_button) +controller.register_ui_element('reset', reset_button) +controller.register_ui_element('next', next_button) +controller.register_ui_element('info', rules_button) + +def display(game_state): + window_surface.blit(game_background, (0, 0)) + window_surface.blit(ui_background, (0, GAME_HEIGHT)) + manager.draw_ui(window_surface) + + if game_state['animation_running']: + game_state['grid'].update() + + game_state['grid'].draw(window_surface) + pygame.display.update() + +while game_state['is_running']: + current_grid = game_state['grid'] + time_delta = clock.tick(5) / 1000.0 + for event in pygame.event.get(): + # pass the event and the game state to the controller + # controller figures out what kind of event to address + # updates the game state accordingly + updated_state = controller.assess(event, game_state) + game_state.update(updated_state) + + manager.process_events(event) + + manager.update(time_delta) + display(game_state) + diff --git a/grid.py b/grid.py index f2fd1d9..fbd8b45 100644 --- a/grid.py +++ b/grid.py @@ -57,7 +57,6 @@ def check_clicks(self, pos): for i, row in enumerate(self.rects): for j, rect in enumerate(row): if rect.collidepoint(pos): - print(f'collided with {rect} at pos {i}, {j}') self.cells[i][j].flip() def reset(self): From 468a37551003589aa726a0fef4570b7975338ddc Mon Sep 17 00:00:00 2001 From: LL_Mehdi Date: Wed, 1 Dec 2021 18:05:57 +0100 Subject: [PATCH 04/11] Added rules on hover to the rules button --- game.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/game.py b/game.py index d24ac3d..23f1337 100644 --- a/game.py +++ b/game.py @@ -31,6 +31,8 @@ manager = pygame_gui.UIManager((WINDOW_WIDTH, WINDOW_HEIGHT)) +manager.preload_fonts([{'name': 'fira_code', 'point_size': 14, 'style': 'bold'}]) + start_button = pygame_gui.elements.UIButton( relative_rect=pygame.Rect((70, GAME_HEIGHT + 30), (BUTTON_WIDTH, BUTTON_HEIGHT)), text='Start', @@ -47,8 +49,10 @@ manager=manager) rules_button = pygame_gui.elements.UIButton( - relative_rect=pygame.Rect((4*70 + 3*BUTTON_WIDTH, GAME_HEIGHT + 30),(BUTTON_WIDTH, BUTTON_HEIGHT)), + relative_rect=pygame.Rect((4*70 + 3*BUTTON_WIDTH, GAME_HEIGHT + 30), (BUTTON_WIDTH, BUTTON_HEIGHT)), text='Rules', + tool_tip_text='Rule 1: Any active cell with two or three live neighbours survives.
Rule 2: Any inactive cell with three live neighbours becomes active.
Rule 3: All other active cells die in the next generation.', + starting_height=7, manager=manager) g = Grid((WINDOW_WIDTH, GAME_HEIGHT), window_surface, 15, 15) @@ -67,17 +71,19 @@ controller.register_ui_element('next', next_button) controller.register_ui_element('info', rules_button) -def display(game_state): + +def display(state): window_surface.blit(game_background, (0, 0)) window_surface.blit(ui_background, (0, GAME_HEIGHT)) - manager.draw_ui(window_surface) - if game_state['animation_running']: - game_state['grid'].update() + if state['animation_running']: + state['grid'].update() - game_state['grid'].draw(window_surface) + state['grid'].draw(window_surface) + manager.draw_ui(window_surface) pygame.display.update() + while game_state['is_running']: current_grid = game_state['grid'] time_delta = clock.tick(5) / 1000.0 From 0a5dd75a692ead33b32008e08ac942caf8594f59 Mon Sep 17 00:00:00 2001 From: LL_Mehdi Date: Wed, 1 Dec 2021 18:15:44 +0100 Subject: [PATCH 05/11] cleaned up controller code. Hitting next now pauses the animation --- controller.py | 20 ++++++++++++-------- game.py | 8 ++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/controller.py b/controller.py index 1407146..2fd67e1 100644 --- a/controller.py +++ b/controller.py @@ -3,20 +3,22 @@ class EventController: - def register_ui_element(self, name, element_reference): - setattr(self, name, element_reference) + def __init__(self, start: pygame_gui.elements.UIButton, next: pygame_gui.elements.UIButton, reset: pygame_gui.elements.UIButton): + self.start_button = start + self.next_button = next + self.reset_button = reset def assess(self, event, state): if event.type == pygame.QUIT: return handle_quit(state) if event.type == pygame.USEREVENT and event.user_type == pygame_gui.UI_BUTTON_PRESSED: - if event.ui_element == self.__getattribute__('start'): + if event.ui_element == self.start_button: return handle_start_pause(state, event.ui_element) - if event.ui_element == self.__getattribute__('reset'): + if event.ui_element == self.reset_button: return handle_reset(state) - if event.ui_element == self.__getattribute__('next'): - return handle_next(state) + if event.ui_element == self.next_button: + return handle_next(state, self.start_button) else: return {} @@ -48,6 +50,8 @@ def handle_grid_click(state): return {} -def handle_next(state): +def handle_next(state, start_button): state['grid'].update() - return {} \ No newline at end of file + state['animation_running'] = False + start_button.set_text('Start') + return {} diff --git a/game.py b/game.py index 23f1337..29fab44 100644 --- a/game.py +++ b/game.py @@ -65,11 +65,7 @@ clock = pygame.time.Clock() game_state = {'is_running': True, 'animation_running': False, 'grid': g} -controller = EventController() -controller.register_ui_element('start', start_button) -controller.register_ui_element('reset', reset_button) -controller.register_ui_element('next', next_button) -controller.register_ui_element('info', rules_button) +controller = EventController(start=start_button, next=next_button, reset=reset_button) def display(state): @@ -86,7 +82,7 @@ def display(state): while game_state['is_running']: current_grid = game_state['grid'] - time_delta = clock.tick(5) / 1000.0 + time_delta = clock.tick(50) / 1000.0 for event in pygame.event.get(): # pass the event and the game state to the controller # controller figures out what kind of event to address From 1b71493c495aaa6032b22d140dd6412f256d6d14 Mon Sep 17 00:00:00 2001 From: LL_Mehdi Date: Wed, 1 Dec 2021 18:21:08 +0100 Subject: [PATCH 06/11] refactored cell so that it is a child class of pygame.locals.Rect, making click checks simpler --- cell.py | 11 ++++++----- grid.py | 13 ++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cell.py b/cell.py index 8c626f9..7c9c344 100644 --- a/cell.py +++ b/cell.py @@ -5,18 +5,19 @@ ACTIVE_COLOR = "#C0E5C8" -class Cell: - def __init__(self, pos: tuple, dimensions: tuple, alive=False): - self.active = alive +class Cell(Rect): + def __init__(self, pos: tuple, dimensions: tuple, active=False): + self.active = active self.future_state = None - self.rectangle = Rect(pos[0], pos[1], dimensions[0], dimensions[1]) + + super().__init__(pos, dimensions) def draw(self, surface): """ This method checks what state the cell is in, and draws it in the appropriate color on the provided surface """ color = ACTIVE_COLOR if self.active else INACTIVE_COLOR - return pygame.draw.rect(surface, color, self.rectangle) + return pygame.draw.rect(surface, color, self) def __str__(self): return "X" if self.active else "_" diff --git a/grid.py b/grid.py index fbd8b45..070bb4e 100644 --- a/grid.py +++ b/grid.py @@ -16,7 +16,6 @@ def __init__(self, screen_dimensions: tuple, surface, width: int, height: int): self.cells = [ [Cell((PADDING + x * (cell_width + CELL_OFFSET), PADDING + y * (cell_height + CELL_OFFSET)), (cell_width, cell_height)) for x in range(width)] for y in range(height)] - self.rects = [] def __str__(self): output = "" @@ -49,15 +48,15 @@ def update(self): cell.update() def draw(self, surface): - self.rects = [] for row in self.cells: - self.rects.append([cell.draw(surface) for cell in row]) + for cell in row: + cell.draw(surface) def check_clicks(self, pos): - for i, row in enumerate(self.rects): - for j, rect in enumerate(row): - if rect.collidepoint(pos): - self.cells[i][j].flip() + for row in self.cells: + for cell in row: + if cell.collidepoint(pos): + cell.flip() def reset(self): for row in self.cells: From dca08d4c6897f8f5aa27ef31c07299e7c08b2af7 Mon Sep 17 00:00:00 2001 From: LL_Mehdi Date: Wed, 1 Dec 2021 18:24:22 +0100 Subject: [PATCH 07/11] Resetting the game now pauses the animation --- controller.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/controller.py b/controller.py index 2fd67e1..f9aca81 100644 --- a/controller.py +++ b/controller.py @@ -16,7 +16,7 @@ def assess(self, event, state): if event.ui_element == self.start_button: return handle_start_pause(state, event.ui_element) if event.ui_element == self.reset_button: - return handle_reset(state) + return handle_reset(state, self.start_button) if event.ui_element == self.next_button: return handle_next(state, self.start_button) else: @@ -33,8 +33,11 @@ def handle_quit(state): return state -def handle_reset(state): +def handle_reset(state, start_button): state['grid'].reset() + state['animation_running'] = False + start_button.set_text('Start') + return state From dfcde57a1acbad9efa27a2aa5b851056362456a0 Mon Sep 17 00:00:00 2001 From: LL_Mehdi Date: Wed, 1 Dec 2021 18:26:38 +0100 Subject: [PATCH 08/11] Added tooltips to all the buttons --- game.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/game.py b/game.py index 29fab44..2ab85ab 100644 --- a/game.py +++ b/game.py @@ -36,16 +36,19 @@ start_button = pygame_gui.elements.UIButton( relative_rect=pygame.Rect((70, GAME_HEIGHT + 30), (BUTTON_WIDTH, BUTTON_HEIGHT)), text='Start', + tool_tip_text='Start or Pause the simulation', manager=manager) reset_button = pygame_gui.elements.UIButton( relative_rect=pygame.Rect((2*70 + BUTTON_WIDTH, GAME_HEIGHT + 30), (BUTTON_WIDTH, BUTTON_HEIGHT)), text='Reset', + tool_tip_text='Clear all cells from the screen', manager=manager) next_button = pygame_gui.elements.UIButton( - relative_rect=pygame.Rect((3*70 + 2*BUTTON_WIDTH, GAME_HEIGHT + 30),(BUTTON_WIDTH, BUTTON_HEIGHT)), + relative_rect=pygame.Rect((3*70 + 2*BUTTON_WIDTH, GAME_HEIGHT + 30), (BUTTON_WIDTH, BUTTON_HEIGHT)), text='Next', + tool_tip_text='Move the simulation one step forward then pause it', manager=manager) rules_button = pygame_gui.elements.UIButton( From bed8b8119b672b4bceeecd96d744531419fc9e05 Mon Sep 17 00:00:00 2001 From: LL_Mehdi Date: Thu, 2 Dec 2021 10:24:54 +0100 Subject: [PATCH 09/11] Add requirements.txt --- requirements.txt | Bin 0 -> 98 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..11000669750cd61459af298e0284e5d97de80aae GIT binary patch literal 98 zcmezWFP9;eA%`KKA%!86A(6or2n`wZfS8woi=lv_k|7-^3Q_}-F#^lzF&JRT>H^i3 R0!;v^G61SF1!8lsDgcUu4|@Or literal 0 HcmV?d00001 From 1f3258dc9bfb9b4e6579f7851d0cc429788370ed Mon Sep 17 00:00:00 2001 From: LL_Mehdi Date: Thu, 2 Dec 2021 17:38:53 +0100 Subject: [PATCH 10/11] fixed requirements.txt --- requirements.txt | Bin 98 -> 70 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/requirements.txt b/requirements.txt index 11000669750cd61459af298e0284e5d97de80aae..7dc88c06cf00c136958dd51b327c071c715d46b9 100644 GIT binary patch delta 8 PcmYdtWBUJZqMQo=5Htgu delta 36 ocmZ=ulKcNJmm!rQhasOKg&~t6k--)S4H@)+n3sWzVIq?Y0JH!HmjD0& From 5e8551333e2446a3ddd4b47c2f5045f878c38074 Mon Sep 17 00:00:00 2001 From: MariamAlnaqbi <61577106+MariamAlnaqbi@users.noreply.github.com> Date: Thu, 28 Apr 2022 09:07:38 +0400 Subject: [PATCH 11/11] commit --- .idea/.gitignore | 8 ++++++++ .idea/challenge1.iml | 8 ++++++++ .idea/inspectionProfiles/profiles_settings.xml | 6 ++++++ .idea/misc.xml | 4 ++++ .idea/modules.xml | 8 ++++++++ .idea/vcs.xml | 6 ++++++ 6 files changed, 40 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/challenge1.iml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/challenge1.iml b/.idea/challenge1.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/.idea/challenge1.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..dc9ea49 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..02c1e86 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file