refactoring and licensing
This commit is contained in:
parent
23517f45ff
commit
5e8b07799b
174
LICENSE.txt
174
LICENSE.txt
@ -0,0 +1,174 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
@ -1,6 +1,4 @@
|
||||
from .cell_state import *
|
||||
from .neighborhood import *
|
||||
from .rule import *
|
||||
from .factory import *
|
||||
from .automaton import *
|
||||
from .display import *
|
||||
from .neighborhood import Neighborhood, MooreNeighborhood, VonNeumannNeighborhood, EdgeRule
|
||||
from .rule import Rule
|
||||
from .factory import CAFactory
|
||||
from .display import CAWindow
|
||||
|
@ -1,3 +1,19 @@
|
||||
"""
|
||||
Copyright 2019 Richard Feistenauer
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import multiprocessing
|
||||
from multiprocessing import freeze_support
|
||||
from ctypes import c_int
|
||||
@ -12,10 +28,10 @@ class CellularAutomatonProcessor:
|
||||
self.evolve()
|
||||
|
||||
def evolve(self):
|
||||
self._ca.current_evolution_step += 1
|
||||
i = self._ca.current_evolution_step
|
||||
r = self._ca.evolution_rule.evolve_cell
|
||||
list(map(lambda c: c.evolve_if_ready(r, i), tuple(self._ca.cells.values())))
|
||||
self._ca.current_evolution_step += 1
|
||||
|
||||
def get_dimension(self):
|
||||
return self._ca.dimension
|
||||
@ -40,7 +56,6 @@ class CellularAutomatonMultiProcessor(CellularAutomatonProcessor):
|
||||
|
||||
self.evolve_range = range(len(self._ca.cells))
|
||||
self._ca.current_evolution_step = multiprocessing.RawValue(c_int, self._ca.current_evolution_step)
|
||||
|
||||
self.__init_processes_and_clean_cell_instances(process_count)
|
||||
|
||||
def __init_processes_and_clean_cell_instances(self, process_count):
|
||||
@ -49,12 +64,10 @@ class CellularAutomatonMultiProcessor(CellularAutomatonProcessor):
|
||||
initargs=(tuple(self._ca.cells.values()),
|
||||
self._ca.evolution_rule,
|
||||
self._ca.current_evolution_step))
|
||||
for cell in self._ca.cells.values():
|
||||
del cell.neighbor_states
|
||||
|
||||
def evolve(self):
|
||||
self._ca.current_evolution_step += 1
|
||||
self.pool.map(_process_routine, self.evolve_range)
|
||||
self._ca.current_evolution_step.value += 1
|
||||
|
||||
def get_current_evolution_step(self):
|
||||
return self._ca.current_evolution_step.value
|
||||
|
@ -1,21 +1,45 @@
|
||||
from .cell_state import CellState
|
||||
from typing import Type
|
||||
"""
|
||||
Copyright 2019 Richard Feistenauer
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import cellular_automaton.cellular_automaton._cell_state as cs
|
||||
|
||||
|
||||
class Cell:
|
||||
def __init__(self, state_class: Type[CellState]):
|
||||
self.state = state_class()
|
||||
self.neighbor_states = []
|
||||
def __init__(self, state_class: cs.CellState, neighbors):
|
||||
self._state = state_class
|
||||
self._neighbor_states = neighbors
|
||||
|
||||
def is_set_for_redraw(self):
|
||||
return self._state.is_set_for_redraw()
|
||||
|
||||
def was_redrawn(self):
|
||||
self._state.was_redrawn()
|
||||
|
||||
def get_current_state(self, evolution_step):
|
||||
return self._state.get_state_of_evolution_step(evolution_step)
|
||||
|
||||
def evolve_if_ready(self, rule, evolution_step):
|
||||
if self.state.is_active(evolution_step):
|
||||
new_state = rule(self.state.get_state_of_last_evolution_step(evolution_step),
|
||||
[n.get_state_of_last_evolution_step(evolution_step) for n in self.neighbor_states])
|
||||
if self._state.is_active(evolution_step):
|
||||
new_state = rule(list(self._state.get_state_of_last_evolution_step(evolution_step)),
|
||||
[list(n.get_state_of_last_evolution_step(evolution_step)) for n in self._neighbor_states])
|
||||
self.set_new_state_and_activate(new_state, evolution_step)
|
||||
|
||||
def set_new_state_and_activate(self, new_state: CellState, evolution_step):
|
||||
changed = self.state.set_state_of_evolution_step(new_state, evolution_step)
|
||||
def set_new_state_and_activate(self, new_state: cs.CellState, evolution_step):
|
||||
changed = self._state.set_state_of_evolution_step(new_state, evolution_step)
|
||||
if changed:
|
||||
self.state.set_active_for_next_evolution_step(evolution_step)
|
||||
for n in self.neighbor_states:
|
||||
self._state.set_active_for_next_evolution_step(evolution_step)
|
||||
for n in self._neighbor_states:
|
||||
n.set_active_for_next_evolution_step(evolution_step)
|
||||
|
@ -1,3 +1,19 @@
|
||||
"""
|
||||
Copyright 2019 Richard Feistenauer
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
from multiprocessing import RawArray, RawValue
|
||||
from ctypes import c_float, c_bool
|
||||
|
||||
|
@ -1,10 +1,25 @@
|
||||
"""
|
||||
Copyright 2019 Richard Feistenauer
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
from cellular_automaton.cellular_automaton import Rule
|
||||
from typing import Type
|
||||
|
||||
|
||||
class CellularAutomatonState:
|
||||
def __init__(self, cells, dimension, evolution_rule: Type[Rule]):
|
||||
def __init__(self, cells, dimension, evolution_rule: Rule):
|
||||
self.cells = cells
|
||||
self.dimension = dimension
|
||||
self.evolution_rule = evolution_rule
|
||||
self.current_evolution_step = -1
|
||||
self.current_evolution_step = 0
|
||||
|
@ -1,76 +1,105 @@
|
||||
"""
|
||||
Copyright 2019 Richard Feistenauer
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import pygame
|
||||
import time
|
||||
import operator
|
||||
|
||||
from . import CellularAutomatonState, CellularAutomatonProcessor
|
||||
import cellular_automaton.cellular_automaton._automaton as automaton
|
||||
|
||||
|
||||
class _DisplayInfo:
|
||||
def __init__(self, grid_size, grid_pos, cell_size, screen):
|
||||
self.grid_size = grid_size
|
||||
self.grid_pos = grid_pos
|
||||
self.cell_size = cell_size
|
||||
self.screen = screen
|
||||
|
||||
|
||||
class DisplayFor2D:
|
||||
def __init__(self, grid_rect: list, cellular_automaton: CellularAutomatonState, screen):
|
||||
class _CASurface:
|
||||
def __init__(self, grid_rect: pygame.Rect, cellular_automaton: automaton.CellularAutomatonProcessor, screen):
|
||||
self._cellular_automaton = cellular_automaton
|
||||
cell_size = self._calculate_cell_display_size(grid_rect[-2:])
|
||||
self._display_info = _DisplayInfo(grid_rect[-2:], grid_rect[:2], cell_size, screen)
|
||||
self.__rect = grid_rect
|
||||
self.__cell_size = self._calculate_cell_display_size()
|
||||
self.__screen = screen
|
||||
|
||||
def _calculate_cell_display_size(self):
|
||||
grid_dimension = self._cellular_automaton.get_dimension()
|
||||
return [self.__rect.width / grid_dimension[0], self.__rect.height / grid_dimension[1]]
|
||||
|
||||
def redraw_cellular_automaton(self):
|
||||
update_rects = list(self._cell_redraw_rectangles())
|
||||
update_rects = list(self.__cell_redraw_dirty_rectangles())
|
||||
pygame.display.update(update_rects)
|
||||
|
||||
def _cell_redraw_rectangles(self):
|
||||
for coordinate, cell in self._cellular_automaton.cells.items():
|
||||
if cell.state.is_set_for_redraw():
|
||||
cell_color = cell.state.get_state_draw_color(self._cellular_automaton.current_evolution_step)
|
||||
cell_pos = self._calculate_cell_position(self._display_info.cell_size, coordinate)
|
||||
surface_pos = list(map(operator.add, cell_pos, self._display_info.grid_pos))
|
||||
yield self._display_info.screen.fill(cell_color, (surface_pos, self._display_info.cell_size))
|
||||
cell.state.was_redrawn()
|
||||
def __cell_redraw_dirty_rectangles(self):
|
||||
for coordinate, cell in self._cellular_automaton.get_cells().items():
|
||||
if cell.is_set_for_redraw():
|
||||
yield from self.__redraw_cell(cell, coordinate)
|
||||
|
||||
def _calculate_cell_display_size(self, grid_size):
|
||||
grid_dimension = self._cellular_automaton.dimension
|
||||
return list(map(operator.truediv, grid_size, grid_dimension))
|
||||
def __redraw_cell(self, cell, coordinate):
|
||||
cell_color = self.__get_cell_color(cell)
|
||||
cell_pos = self._calculate_cell_position_in_the_grid(coordinate)
|
||||
surface_pos = self._calculate_cell_position_on_screen(cell_pos)
|
||||
yield self._draw_the_cell_to_screen(cell_color, surface_pos)
|
||||
cell.was_redrawn()
|
||||
|
||||
@staticmethod
|
||||
def _calculate_cell_position(cell_size, coordinate):
|
||||
return list(map(operator.mul, cell_size, coordinate))
|
||||
def __get_cell_color(self, cell):
|
||||
return self._cellular_automaton.get_current_rule().get_state_draw_color(
|
||||
cell.get_current_state(self._cellular_automaton.get_current_evolution_step()))
|
||||
|
||||
def _calculate_cell_position_in_the_grid(self, coordinate):
|
||||
return list(map(operator.mul, self.__cell_size, coordinate))
|
||||
|
||||
def _calculate_cell_position_on_screen(self, cell_pos):
|
||||
return [self.__rect.left + cell_pos[0], self.__rect.top + cell_pos[1]]
|
||||
|
||||
def _draw_the_cell_to_screen(self, cell_color, surface_pos):
|
||||
return self.__screen.fill(cell_color, (surface_pos, self.__cell_size))
|
||||
|
||||
|
||||
class PyGameFor2D:
|
||||
def __init__(self, window_size: list, cellular_automaton: CellularAutomatonState):
|
||||
self._window_size = window_size
|
||||
self._cellular_automaton = cellular_automaton
|
||||
class CAWindow:
|
||||
def __init__(self, cellular_automaton: automaton.CellularAutomatonProcessor,
|
||||
evolution_steps_per_draw=1,
|
||||
window_size=(1000, 800)):
|
||||
self._ca = cellular_automaton
|
||||
self.__window_size = window_size
|
||||
self.__init_pygame()
|
||||
self.__loop_evolution_and_redraw_of_automaton(evolution_steps_per_draw=evolution_steps_per_draw)
|
||||
|
||||
def __init_pygame(self):
|
||||
pygame.init()
|
||||
pygame.display.set_caption("Cellular Automaton")
|
||||
self._screen = pygame.display.set_mode(self._window_size)
|
||||
self._screen = pygame.display.set_mode(self.__window_size)
|
||||
self._font = pygame.font.SysFont("monospace", 15)
|
||||
|
||||
self.ca_display = DisplayFor2D([0, 30, window_size[0], window_size[1] - 30], cellular_automaton, self._screen)
|
||||
self.ca_display = _CASurface(pygame.Rect(0, 30, self.__window_size[0], self.__window_size[1] - 30),
|
||||
self._ca,
|
||||
self._screen)
|
||||
|
||||
def _print_process_duration(self, time_ca_end, time_ca_start, time_ds_end):
|
||||
self._screen.fill([0, 0, 0], ((0, 0), (self._window_size[0], 30)))
|
||||
self._write_text((10, 5), "CA: " + "{0:.4f}".format(time_ca_end - time_ca_start) + "s")
|
||||
self._write_text((310, 5), "Display: " + "{0:.4f}".format(time_ds_end - time_ca_end) + "s")
|
||||
self._write_text((660, 5), "Step: " + str(self._cellular_automaton.current_evolution_step))
|
||||
|
||||
def _write_text(self, pos, text, color=(0, 255, 0)):
|
||||
label = self._font.render(text, 1, color)
|
||||
update_rect = self._screen.blit(label, pos)
|
||||
pygame.display.update(update_rect)
|
||||
|
||||
def main_loop(self, cellular_automaton_processor: CellularAutomatonProcessor, evolution_steps_per_draw):
|
||||
def __loop_evolution_and_redraw_of_automaton(self, evolution_steps_per_draw):
|
||||
running = True
|
||||
|
||||
while running:
|
||||
pygame.event.get()
|
||||
time_ca_start = time.time()
|
||||
cellular_automaton_processor.evolve_x_times(evolution_steps_per_draw)
|
||||
self._ca.evolve_x_times(evolution_steps_per_draw)
|
||||
time_ca_end = time.time()
|
||||
self.ca_display.redraw_cellular_automaton()
|
||||
time_ds_end = time.time()
|
||||
self._print_process_duration(time_ca_end, time_ca_start, time_ds_end)
|
||||
self.__print_process_duration(time_ca_end, time_ca_start, time_ds_end)
|
||||
|
||||
def __print_process_duration(self, time_ca_end, time_ca_start, time_ds_end):
|
||||
self._screen.fill([0, 0, 0], ((0, 0), (self.__window_size[0], 30)))
|
||||
self.__write_text((10, 5), "CA: " + "{0:.4f}".format(time_ca_end - time_ca_start) + "s")
|
||||
self.__write_text((310, 5), "Display: " + "{0:.4f}".format(time_ds_end - time_ca_end) + "s")
|
||||
self.__write_text((660, 5), "Step: " + str(self._ca.get_current_evolution_step()))
|
||||
|
||||
def __write_text(self, pos, text, color=(0, 255, 0)):
|
||||
label = self._font.render(text, 1, color)
|
||||
update_rect = self._screen.blit(label, pos)
|
||||
pygame.display.update(update_rect)
|
||||
|
@ -1,30 +1,72 @@
|
||||
from . import Neighborhood, CellState, Rule
|
||||
from . import Neighborhood, Rule
|
||||
from ._automaton import CellularAutomatonProcessor, CellularAutomatonMultiProcessor
|
||||
from ._cell import Cell
|
||||
from ._state import CellularAutomatonState
|
||||
from ._cell_state import CellState, SynchronousCellState
|
||||
from typing import Type
|
||||
"""
|
||||
Copyright 2019 Richard Feistenauer
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import itertools
|
||||
|
||||
|
||||
class CAFactory:
|
||||
@staticmethod
|
||||
def make_cellular_automaton(dimension,
|
||||
neighborhood: Neighborhood,
|
||||
state_class: Type[CellState],
|
||||
rule: Type[Rule]):
|
||||
cells = CAFactory._make_cells(dimension, state_class)
|
||||
CAFactory._apply_neighborhood_to_cells(cells, neighborhood, dimension)
|
||||
def make_single_process_cellular_automaton(dimension,
|
||||
neighborhood: Neighborhood,
|
||||
rule: Type[Rule]):
|
||||
|
||||
ca = CAFactory._make_cellular_automaton_state(dimension, neighborhood, CellState, rule)
|
||||
return CellularAutomatonProcessor(ca)
|
||||
|
||||
@staticmethod
|
||||
def _make_cellular_automaton_state(dimension, neighborhood, state_class, rule_class):
|
||||
rule = rule_class(neighborhood)
|
||||
cell_states = CAFactory._make_cell_states(state_class, rule, dimension)
|
||||
cells = CAFactory._make_cells(cell_states, neighborhood, dimension)
|
||||
return CellularAutomatonState(cells, dimension, rule)
|
||||
|
||||
@staticmethod
|
||||
def _make_cells(dimension, state_class):
|
||||
cells = {}
|
||||
for c in itertools.product(*[range(d) for d in dimension]):
|
||||
cells[tuple(c)] = Cell(state_class)
|
||||
return cells
|
||||
def make_multi_process_cellular_automaton(dimension,
|
||||
neighborhood: Neighborhood,
|
||||
rule: Type[Rule],
|
||||
processes: int):
|
||||
if processes < 1:
|
||||
raise ValueError("At least one process is necessary")
|
||||
elif processes == 1:
|
||||
return CAFactory.make_single_process_cellular_automaton(dimension, neighborhood, rule)
|
||||
else:
|
||||
ca = CAFactory._make_cellular_automaton_state(dimension, neighborhood, SynchronousCellState, rule)
|
||||
return CellularAutomatonMultiProcessor(ca, processes)
|
||||
|
||||
@staticmethod
|
||||
def _apply_neighborhood_to_cells(cells, neighborhood, dimension):
|
||||
for coordinate, cell in cells.items():
|
||||
n_coordinates = neighborhood.calculate_cell_neighbor_coordinates(coordinate, dimension)
|
||||
cell.neighbor_states = [cells[tuple(nc)].state for nc in n_coordinates]
|
||||
def _make_cell_states(state_class, rule, dimension):
|
||||
cell_states = {}
|
||||
for c in itertools.product(*[range(d) for d in dimension]):
|
||||
coordinate = tuple(c)
|
||||
cell_states[coordinate] = state_class(rule.init_state(coordinate))
|
||||
return cell_states
|
||||
|
||||
@staticmethod
|
||||
def _make_cells(cell_states, neighborhood, dimension):
|
||||
cells = {}
|
||||
for coordinate, cell_state in cell_states.items():
|
||||
n_coordinates = neighborhood.calculate_cell_neighbor_coordinates(coordinate, dimension)
|
||||
neighbor_states = [cell_states[tuple(nc)] for nc in n_coordinates]
|
||||
cells[coordinate] = Cell(cell_state, neighbor_states)
|
||||
return cells
|
||||
|
||||
|
||||
|
@ -1,9 +1,25 @@
|
||||
from enum import Enum
|
||||
from operator import add
|
||||
from itertools import product
|
||||
"""
|
||||
Copyright 2019 Richard Feistenauer
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import enum
|
||||
import operator
|
||||
import itertools
|
||||
|
||||
|
||||
class EdgeRule(Enum):
|
||||
class EdgeRule(enum.Enum):
|
||||
IGNORE_EDGE_CELLS = 0
|
||||
IGNORE_MISSING_NEIGHBORS_OF_EDGE_CELLS = 1
|
||||
FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS = 2
|
||||
@ -29,13 +45,16 @@ class Neighborhood:
|
||||
self.__grid_dimensions = grid_dimensions
|
||||
return list(self.__neighbors_generator(cell_coordinate))
|
||||
|
||||
def get_neighbor_id_from_rel(self, rel_coordinate):
|
||||
return self._rel_neighbors.index(rel_coordinate)
|
||||
|
||||
def __neighbors_generator(self, cell_coordinate):
|
||||
if not self.__does_ignore_edge_cell_rule_apply(cell_coordinate):
|
||||
for rel_n in self._rel_neighbors:
|
||||
yield from self.__calculate_abs_neighbor_and_decide_validity(cell_coordinate, rel_n)
|
||||
|
||||
def __calculate_abs_neighbor_and_decide_validity(self, cell_coordinate, rel_n):
|
||||
n = list(map(add, rel_n, cell_coordinate))
|
||||
n = list(map(operator.add, rel_n, cell_coordinate))
|
||||
n_folded = self.__apply_edge_overflow(n)
|
||||
if n == n_folded or self.__edge_rule == EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS:
|
||||
yield n_folded
|
||||
@ -70,6 +89,6 @@ class VonNeumannNeighborhood(Neighborhood):
|
||||
|
||||
|
||||
def _rel_neighbor_generator(dimension, range_, rule):
|
||||
for c in product(range(-range_, range_ + 1), repeat=dimension):
|
||||
for c in itertools.product(range(-range_, range_ + 1), repeat=dimension):
|
||||
if rule(c) and c != (0, ) * dimension:
|
||||
yield tuple(reversed(c))
|
||||
|
@ -1,13 +1,32 @@
|
||||
from abc import abstractmethod
|
||||
"""
|
||||
Copyright 2019 Richard Feistenauer
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import abc
|
||||
import cellular_automaton.cellular_automaton.neighborhood as neighbour
|
||||
|
||||
|
||||
class Rule:
|
||||
def __init__(self):
|
||||
pass
|
||||
def __init__(self, neighborhood_: neighbour.Neighborhood):
|
||||
self._neighborhood = neighborhood_
|
||||
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def evolve_cell(last_cell_state, neighbors_last_states):
|
||||
def _get_neighbor_by_relative_coordinate(self, neighbours, rel_coordinate):
|
||||
return neighbours[self._neighborhood.get_neighbor_id_from_rel(rel_coordinate)]
|
||||
|
||||
@abc.abstractmethod
|
||||
def evolve_cell(self, last_cell_state, neighbors_last_states):
|
||||
""" Calculates and sets new state of 'cell'.
|
||||
:param last_cell_state: The cells current state to calculate new state for.
|
||||
:param neighbors_last_states: The cells neighbors current states.
|
||||
@ -15,3 +34,15 @@ class Rule:
|
||||
A cells evolution will only be called if it or at least one of its neighbors has changed last evolution_step cycle.
|
||||
"""
|
||||
return last_cell_state
|
||||
|
||||
@abc.abstractmethod
|
||||
def init_state(self, cell_coordinate):
|
||||
""" Set the initial state for the cell with the given coordinate.
|
||||
:param cell_coordinate: Cells coordinate.
|
||||
:return: Iterable that represents the state
|
||||
"""
|
||||
return [0]
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_state_draw_color(self, current_state):
|
||||
return [0, 0, 0]
|
||||
|
@ -4,16 +4,38 @@ import random
|
||||
from cellular_automaton import *
|
||||
|
||||
|
||||
ALIVE = [1.0]
|
||||
DEAD = [0]
|
||||
|
||||
|
||||
class TestRule(Rule):
|
||||
random_seed = random.seed(1000)
|
||||
random_seed = random.seed(13)
|
||||
|
||||
def init_state(self, cell_coordinate):
|
||||
rand = random.randrange(0, 101, 1)
|
||||
init = max(.0, float(rand - 99))
|
||||
rand = random.randrange(0, 16, 1)
|
||||
init = max(.0, float(rand - 14))
|
||||
return (init,)
|
||||
|
||||
def evolve_cell(self, last_cell_state, neighbors_last_states):
|
||||
return self._get_neighbor_by_relative_coordinate(neighbors_last_states, (-1, -1))
|
||||
new_cell_state = last_cell_state
|
||||
alive_neighbours = self.__count_alive_neighbours(neighbors_last_states)
|
||||
if last_cell_state == DEAD and alive_neighbours == 3:
|
||||
new_cell_state = ALIVE
|
||||
if last_cell_state == ALIVE and alive_neighbours < 2:
|
||||
new_cell_state = DEAD
|
||||
if last_cell_state == ALIVE and 1 < alive_neighbours < 4:
|
||||
new_cell_state = ALIVE
|
||||
if last_cell_state == ALIVE and alive_neighbours > 3:
|
||||
new_cell_state = DEAD
|
||||
return new_cell_state
|
||||
|
||||
@staticmethod
|
||||
def __count_alive_neighbours(neighbours):
|
||||
an = []
|
||||
for n in neighbours:
|
||||
if n == ALIVE:
|
||||
an.append(1)
|
||||
return len(an)
|
||||
|
||||
def get_state_draw_color(self, current_state):
|
||||
return [255 if current_state[0] else 0, 0, 0]
|
||||
@ -21,7 +43,8 @@ class TestRule(Rule):
|
||||
|
||||
if __name__ == "__main__":
|
||||
neighborhood = MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS)
|
||||
ca = CAFactory.make_single_process_cellular_automaton(dimension=[100, 100],
|
||||
neighborhood=neighborhood,
|
||||
rule=TestRule)
|
||||
ca = CAFactory.make_multi_process_cellular_automaton(dimension=[100, 100],
|
||||
neighborhood=neighborhood,
|
||||
rule=TestRule,
|
||||
processes=4)
|
||||
ca_window = CAWindow(cellular_automaton=ca, evolution_steps_per_draw=1)
|
||||
|
@ -24,4 +24,4 @@ if __name__ == "__main__":
|
||||
ca = CAFactory.make_single_process_cellular_automaton(dimension=[100, 100],
|
||||
neighborhood=neighborhood,
|
||||
rule=TestRule)
|
||||
ca_window = PyGameFor2D(cellular_automaton=ca, evolution_steps_per_draw=1)
|
||||
ca_window = CAWindow(cellular_automaton=ca, evolution_steps_per_draw=1)
|
||||
|
@ -0,0 +1,72 @@
|
||||
"""
|
||||
Copyright 2019 Richard Feistenauer
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import sys
|
||||
sys.path.append('../..')
|
||||
|
||||
from cellular_automaton import *
|
||||
import unittest
|
||||
|
||||
|
||||
class TestRule(Rule):
|
||||
def evolve_cell(self, last_cell_state, neighbors_last_states):
|
||||
return [last_cell_state[0] + 1]
|
||||
|
||||
def init_state(self, cell_coordinate):
|
||||
return [0]
|
||||
|
||||
def get_state_draw_color(self, current_state):
|
||||
return [0, 0, 0]
|
||||
|
||||
|
||||
class TestCellState(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.neighborhood = MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS)
|
||||
self.processor = CAFactory.make_single_process_cellular_automaton([3, 3],
|
||||
self.neighborhood,
|
||||
TestRule)
|
||||
|
||||
def test_single_process_evolution_steps(self):
|
||||
self.processor.evolve_x_times(5)
|
||||
self.assertEqual(self.processor.get_current_evolution_step(), 5)
|
||||
|
||||
def test_multi_process_evolution_steps(self):
|
||||
self.__create_multi_process_automaton()
|
||||
self.multi_processor.evolve_x_times(5)
|
||||
self.assertEqual(self.multi_processor.get_current_evolution_step(), 5)
|
||||
|
||||
def __create_multi_process_automaton(self):
|
||||
self.multi_processor = CAFactory.make_multi_process_cellular_automaton([3, 3],
|
||||
self.neighborhood,
|
||||
TestRule,
|
||||
processes=2)
|
||||
|
||||
def test_single_process_evolution_calls(self):
|
||||
self.processor.evolve_x_times(5)
|
||||
step = self.processor.get_current_evolution_step()
|
||||
cell = self.processor.get_cells()[(1, 1)].get_current_state(step)[0]
|
||||
self.assertEqual(cell, 4)
|
||||
|
||||
def test_multi_process_evolution_calls(self):
|
||||
self.__create_multi_process_automaton()
|
||||
self.multi_processor.evolve_x_times(5)
|
||||
step = self.multi_processor.get_current_evolution_step()
|
||||
cell = self.multi_processor.get_cells()[(1, 1)].get_current_state(step)[0]
|
||||
self.assertEqual(cell, 4)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -1,25 +1,36 @@
|
||||
"""
|
||||
Copyright 2019 Richard Feistenauer
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import sys
|
||||
sys.path.append('../src')
|
||||
sys.path.append('../..')
|
||||
|
||||
from cellular_automaton.cellular_automaton import *
|
||||
from cellular_automaton.cellular_automaton._cell import Cell
|
||||
from cellular_automaton.cellular_automaton._cell_state import CellState
|
||||
import unittest
|
||||
|
||||
|
||||
class TestState(CellState):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
|
||||
class TestCellState(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.cell = Cell(TestState)
|
||||
self.neighbors = [TestState() for x in range(5)]
|
||||
self.neighbors = [CellState() for x in range(5)]
|
||||
for neighbor in self.neighbors:
|
||||
neighbor.set_state_of_evolution_step((0, ), 0)
|
||||
self.cell.neighbor_states = self.neighbors
|
||||
self.cell = Cell(CellState(), self.neighbors)
|
||||
|
||||
def cell_and_neighbors_active(self, evolution_step):
|
||||
self.neighbors.append(self.cell.state)
|
||||
self.neighbors.append(self.cell._state)
|
||||
all_active = True
|
||||
for state in self.neighbors:
|
||||
if not state.is_active(evolution_step):
|
||||
|
@ -1,13 +1,29 @@
|
||||
import sys
|
||||
sys.path.append('../src')
|
||||
"""
|
||||
Copyright 2019 Richard Feistenauer
|
||||
|
||||
from cellular_automaton import cellular_automaton as cs
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import sys
|
||||
sys.path.append('../..')
|
||||
|
||||
from cellular_automaton.cellular_automaton import _cell_state as cell_state
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCellState(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.cell_state = cs.SynchronousCellState(initial_state=(0,), draw_first_state=False)
|
||||
self.cell_state = cell_state.SynchronousCellState(initial_state=(0,), draw_first_state=False)
|
||||
|
||||
def test_get_state_with_overflow(self):
|
||||
self.cell_state.set_state_of_evolution_step(new_state=(1,), evolution_step=0)
|
||||
@ -47,7 +63,7 @@ class TestCellState(unittest.TestCase):
|
||||
return self.cell_state.set_state_of_evolution_step(new_state=(1, 1), evolution_step=0)
|
||||
|
||||
def test_redraw_flag(self):
|
||||
self.cell_state = cs.SynchronousCellState(initial_state=(0,), draw_first_state=True)
|
||||
self.cell_state = cell_state.SynchronousCellState(initial_state=(0,), draw_first_state=True)
|
||||
self.assertTrue(self.cell_state.is_set_for_redraw())
|
||||
self.cell_state.was_redrawn()
|
||||
self.assertFalse(self.cell_state.is_set_for_redraw())
|
||||
|
@ -1,19 +1,52 @@
|
||||
"""
|
||||
Copyright 2019 Richard Feistenauer
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import sys
|
||||
sys.path.append('../src')
|
||||
sys.path.append('../..')
|
||||
|
||||
from cellular_automaton.cellular_automaton import *
|
||||
from cellular_automaton.cellular_automaton._cell_state import CellState
|
||||
from cellular_automaton.cellular_automaton._state import CellularAutomatonState
|
||||
import unittest
|
||||
import mock
|
||||
|
||||
|
||||
class TestFac(CAFactory):
|
||||
@staticmethod
|
||||
def make_cells(dimension, state_class):
|
||||
return CAFactory._make_cells(dimension, state_class)
|
||||
def make_cell_states(state_class, rule_, dimension):
|
||||
return CAFactory._make_cell_states(state_class, rule_, dimension)
|
||||
|
||||
@staticmethod
|
||||
def apply_neighborhood(cells, neighborhood, dimension):
|
||||
return CAFactory._apply_neighborhood_to_cells(cells, neighborhood, dimension)
|
||||
def make_cells(cells, neighborhood_, dimension):
|
||||
return CAFactory._make_cells(cells, neighborhood_, dimension)
|
||||
|
||||
@staticmethod
|
||||
def make_cellular_automaton_state(dimension, neighborhood_, state_class, rule):
|
||||
return TestFac._make_cellular_automaton_state(dimension, neighborhood_, state_class, rule)
|
||||
|
||||
|
||||
class TestRule(Rule):
|
||||
def evolve_cell(self, last_cell_state, neighbors_last_states):
|
||||
return last_cell_state
|
||||
|
||||
def init_state(self, cell_coordinate):
|
||||
return [1]
|
||||
|
||||
def get_state_draw_color(self, current_state):
|
||||
return [0, 0, 0]
|
||||
|
||||
|
||||
class TestCAFactory(unittest.TestCase):
|
||||
@ -21,48 +54,52 @@ class TestCAFactory(unittest.TestCase):
|
||||
self._neighborhood = MooreNeighborhood(EdgeRule.IGNORE_EDGE_CELLS)
|
||||
|
||||
def test_make_ca_calls_correct_methods(self):
|
||||
with mock.patch.object(CAFactory, '_make_cells', return_value={1: True}) as m1:
|
||||
with mock.patch.object(CAFactory, '_apply_neighborhood_to_cells') as m2:
|
||||
CAFactory.make_cellular_automaton([10], self._neighborhood, CellState, Rule())
|
||||
m1.assert_called_once_with([10], CellState)
|
||||
with mock.patch.object(CAFactory, '_make_cell_states', return_value={1: True}) as m1:
|
||||
with mock.patch.object(CAFactory, '_make_cells') as m2:
|
||||
TestFac.make_cellular_automaton_state([10], self._neighborhood, CellState, Rule)
|
||||
m1.assert_called_once()
|
||||
m2.assert_called_once_with({1: True}, self._neighborhood, [10])
|
||||
|
||||
def test_make_ca_returns_correct_values(self):
|
||||
with mock.patch.object(CAFactory, '_make_cells', return_value={1: True}):
|
||||
with mock.patch.object(CAFactory, '_apply_neighborhood_to_cells'):
|
||||
ca = CAFactory.make_cellular_automaton([10], self._neighborhood, CellState, Rule())
|
||||
with mock.patch.object(CAFactory, '_make_cell_states', return_value={1: True}):
|
||||
with mock.patch.object(CAFactory, '_make_cells', return_value={1: True}):
|
||||
ca = TestFac.make_cellular_automaton_state([10], self._neighborhood, CellState, Rule)
|
||||
self.assertIsInstance(ca, CellularAutomatonState)
|
||||
self.assertEqual(tuple(ca.cells.values()), (True, ))
|
||||
|
||||
def test_make_cells(self):
|
||||
cell_states = self.__create_cell_states()
|
||||
cells = TestFac.make_cells(cell_states, self._neighborhood, [3, 3])
|
||||
neighbours_of_mid = self.__cast_cells_to_list_and_remove_center_cell(cell_states)
|
||||
self.assertEqual(set(cells[(1, 1)]._neighbor_states), set(neighbours_of_mid))
|
||||
|
||||
@staticmethod
|
||||
def __cast_cells_to_list_and_remove_center_cell(cell_states):
|
||||
neighbours_of_mid = list(cell_states.values())
|
||||
neighbours_of_mid.remove(neighbours_of_mid[4])
|
||||
return neighbours_of_mid
|
||||
|
||||
@staticmethod
|
||||
def __create_cell_states():
|
||||
cell_states = {}
|
||||
for x in range(3):
|
||||
for y in range(3):
|
||||
cell_states[(x, y)] = CellState([x * y], False)
|
||||
return cell_states
|
||||
|
||||
def test_1dimension_coordinates(self):
|
||||
c = TestFac.make_cells([3], CellState)
|
||||
c = TestFac.make_cell_states(CellState, Rule(self._neighborhood), [3])
|
||||
self.assertEqual(list(c.keys()), [(0,), (1,), (2,)])
|
||||
|
||||
def test_2dimension_coordinates(self):
|
||||
c = TestFac.make_cells([2, 2], CellState)
|
||||
c = TestFac.make_cell_states(CellState, Rule(self._neighborhood), [2, 2])
|
||||
self.assertEqual(list(c.keys()), [(0, 0), (0, 1), (1, 0), (1, 1)])
|
||||
|
||||
def test_3dimension_coordinates(self):
|
||||
c = TestFac.make_cells([2, 2, 2], CellState)
|
||||
c = TestFac.make_cell_states(CellState, Rule(self._neighborhood), [2, 2, 2])
|
||||
self.assertEqual(list(c.keys()), [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1),
|
||||
(1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)])
|
||||
|
||||
def test_apply_neighborhood(self):
|
||||
cells = TestFac.make_cells([3, 3], CellState)
|
||||
TestFac.apply_neighborhood(cells, self._neighborhood, [3, 3])
|
||||
|
||||
neighbors = self.__create_neighbor_list_of_cell((1, 1), cells)
|
||||
|
||||
self.assertEqual(set(neighbors), set(cells[(1, 1)].neighbor_states))
|
||||
|
||||
@staticmethod
|
||||
def __create_neighbor_list_of_cell(cell_id, cells):
|
||||
neighbors = []
|
||||
for c in cells.values():
|
||||
if c != cells[cell_id]:
|
||||
neighbors.append(c.state)
|
||||
return neighbors
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
@ -1,5 +1,21 @@
|
||||
"""
|
||||
Copyright 2019 Richard Feistenauer
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import sys
|
||||
sys.path.append('../src')
|
||||
sys.path.append('../..')
|
||||
|
||||
from cellular_automaton import cellular_automaton as csn
|
||||
import unittest
|
||||
|
Loading…
Reference in New Issue
Block a user