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 Neighborhood, MooreNeighborhood, VonNeumannNeighborhood, EdgeRule
|
||||||
from .neighborhood import *
|
from .rule import Rule
|
||||||
from .rule import *
|
from .factory import CAFactory
|
||||||
from .factory import *
|
from .display import CAWindow
|
||||||
from .automaton import *
|
|
||||||
from .display import *
|
|
||||||
|
@ -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
|
import multiprocessing
|
||||||
from multiprocessing import freeze_support
|
from multiprocessing import freeze_support
|
||||||
from ctypes import c_int
|
from ctypes import c_int
|
||||||
@ -12,10 +28,10 @@ class CellularAutomatonProcessor:
|
|||||||
self.evolve()
|
self.evolve()
|
||||||
|
|
||||||
def evolve(self):
|
def evolve(self):
|
||||||
self._ca.current_evolution_step += 1
|
|
||||||
i = self._ca.current_evolution_step
|
i = self._ca.current_evolution_step
|
||||||
r = self._ca.evolution_rule.evolve_cell
|
r = self._ca.evolution_rule.evolve_cell
|
||||||
list(map(lambda c: c.evolve_if_ready(r, i), tuple(self._ca.cells.values())))
|
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):
|
def get_dimension(self):
|
||||||
return self._ca.dimension
|
return self._ca.dimension
|
||||||
@ -40,7 +56,6 @@ class CellularAutomatonMultiProcessor(CellularAutomatonProcessor):
|
|||||||
|
|
||||||
self.evolve_range = range(len(self._ca.cells))
|
self.evolve_range = range(len(self._ca.cells))
|
||||||
self._ca.current_evolution_step = multiprocessing.RawValue(c_int, self._ca.current_evolution_step)
|
self._ca.current_evolution_step = multiprocessing.RawValue(c_int, self._ca.current_evolution_step)
|
||||||
|
|
||||||
self.__init_processes_and_clean_cell_instances(process_count)
|
self.__init_processes_and_clean_cell_instances(process_count)
|
||||||
|
|
||||||
def __init_processes_and_clean_cell_instances(self, 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()),
|
initargs=(tuple(self._ca.cells.values()),
|
||||||
self._ca.evolution_rule,
|
self._ca.evolution_rule,
|
||||||
self._ca.current_evolution_step))
|
self._ca.current_evolution_step))
|
||||||
for cell in self._ca.cells.values():
|
|
||||||
del cell.neighbor_states
|
|
||||||
|
|
||||||
def evolve(self):
|
def evolve(self):
|
||||||
self._ca.current_evolution_step += 1
|
|
||||||
self.pool.map(_process_routine, self.evolve_range)
|
self.pool.map(_process_routine, self.evolve_range)
|
||||||
|
self._ca.current_evolution_step.value += 1
|
||||||
|
|
||||||
def get_current_evolution_step(self):
|
def get_current_evolution_step(self):
|
||||||
return self._ca.current_evolution_step.value
|
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:
|
class Cell:
|
||||||
def __init__(self, state_class: Type[CellState]):
|
def __init__(self, state_class: cs.CellState, neighbors):
|
||||||
self.state = state_class()
|
self._state = state_class
|
||||||
self.neighbor_states = []
|
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):
|
def evolve_if_ready(self, rule, evolution_step):
|
||||||
if self.state.is_active(evolution_step):
|
if self._state.is_active(evolution_step):
|
||||||
new_state = rule(self.state.get_state_of_last_evolution_step(evolution_step),
|
new_state = rule(list(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])
|
[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)
|
self.set_new_state_and_activate(new_state, evolution_step)
|
||||||
|
|
||||||
def set_new_state_and_activate(self, new_state: CellState, 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)
|
changed = self._state.set_state_of_evolution_step(new_state, evolution_step)
|
||||||
if changed:
|
if changed:
|
||||||
self.state.set_active_for_next_evolution_step(evolution_step)
|
self._state.set_active_for_next_evolution_step(evolution_step)
|
||||||
for n in self.neighbor_states:
|
for n in self._neighbor_states:
|
||||||
n.set_active_for_next_evolution_step(evolution_step)
|
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 multiprocessing import RawArray, RawValue
|
||||||
from ctypes import c_float, c_bool
|
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 cellular_automaton.cellular_automaton import Rule
|
||||||
from typing import Type
|
|
||||||
|
|
||||||
|
|
||||||
class CellularAutomatonState:
|
class CellularAutomatonState:
|
||||||
def __init__(self, cells, dimension, evolution_rule: Type[Rule]):
|
def __init__(self, cells, dimension, evolution_rule: Rule):
|
||||||
self.cells = cells
|
self.cells = cells
|
||||||
self.dimension = dimension
|
self.dimension = dimension
|
||||||
self.evolution_rule = evolution_rule
|
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 pygame
|
||||||
import time
|
import time
|
||||||
import operator
|
import operator
|
||||||
|
|
||||||
from . import CellularAutomatonState, CellularAutomatonProcessor
|
import cellular_automaton.cellular_automaton._automaton as automaton
|
||||||
|
|
||||||
|
|
||||||
class _DisplayInfo:
|
class _CASurface:
|
||||||
def __init__(self, grid_size, grid_pos, cell_size, screen):
|
def __init__(self, grid_rect: pygame.Rect, cellular_automaton: automaton.CellularAutomatonProcessor, 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):
|
|
||||||
self._cellular_automaton = cellular_automaton
|
self._cellular_automaton = cellular_automaton
|
||||||
cell_size = self._calculate_cell_display_size(grid_rect[-2:])
|
self.__rect = grid_rect
|
||||||
self._display_info = _DisplayInfo(grid_rect[-2:], grid_rect[:2], cell_size, screen)
|
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):
|
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)
|
pygame.display.update(update_rects)
|
||||||
|
|
||||||
def _cell_redraw_rectangles(self):
|
def __cell_redraw_dirty_rectangles(self):
|
||||||
for coordinate, cell in self._cellular_automaton.cells.items():
|
for coordinate, cell in self._cellular_automaton.get_cells().items():
|
||||||
if cell.state.is_set_for_redraw():
|
if cell.is_set_for_redraw():
|
||||||
cell_color = cell.state.get_state_draw_color(self._cellular_automaton.current_evolution_step)
|
yield from self.__redraw_cell(cell, coordinate)
|
||||||
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 _calculate_cell_display_size(self, grid_size):
|
def __redraw_cell(self, cell, coordinate):
|
||||||
grid_dimension = self._cellular_automaton.dimension
|
cell_color = self.__get_cell_color(cell)
|
||||||
return list(map(operator.truediv, grid_size, grid_dimension))
|
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 __get_cell_color(self, cell):
|
||||||
def _calculate_cell_position(cell_size, coordinate):
|
return self._cellular_automaton.get_current_rule().get_state_draw_color(
|
||||||
return list(map(operator.mul, cell_size, coordinate))
|
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:
|
class CAWindow:
|
||||||
def __init__(self, window_size: list, cellular_automaton: CellularAutomatonState):
|
def __init__(self, cellular_automaton: automaton.CellularAutomatonProcessor,
|
||||||
self._window_size = window_size
|
evolution_steps_per_draw=1,
|
||||||
self._cellular_automaton = cellular_automaton
|
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.init()
|
||||||
pygame.display.set_caption("Cellular Automaton")
|
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._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):
|
def __loop_evolution_and_redraw_of_automaton(self, evolution_steps_per_draw):
|
||||||
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):
|
|
||||||
running = True
|
running = True
|
||||||
|
|
||||||
while running:
|
while running:
|
||||||
pygame.event.get()
|
pygame.event.get()
|
||||||
time_ca_start = time.time()
|
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()
|
time_ca_end = time.time()
|
||||||
self.ca_display.redraw_cellular_automaton()
|
self.ca_display.redraw_cellular_automaton()
|
||||||
time_ds_end = time.time()
|
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 ._cell import Cell
|
||||||
from ._state import CellularAutomatonState
|
from ._state import CellularAutomatonState
|
||||||
|
from ._cell_state import CellState, SynchronousCellState
|
||||||
from typing import Type
|
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
|
import itertools
|
||||||
|
|
||||||
|
|
||||||
class CAFactory:
|
class CAFactory:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def make_cellular_automaton(dimension,
|
def make_single_process_cellular_automaton(dimension,
|
||||||
neighborhood: Neighborhood,
|
neighborhood: Neighborhood,
|
||||||
state_class: Type[CellState],
|
|
||||||
rule: Type[Rule]):
|
rule: Type[Rule]):
|
||||||
cells = CAFactory._make_cells(dimension, state_class)
|
|
||||||
CAFactory._apply_neighborhood_to_cells(cells, neighborhood, dimension)
|
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)
|
return CellularAutomatonState(cells, dimension, rule)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _make_cells(dimension, state_class):
|
def make_multi_process_cellular_automaton(dimension,
|
||||||
cells = {}
|
neighborhood: Neighborhood,
|
||||||
for c in itertools.product(*[range(d) for d in dimension]):
|
rule: Type[Rule],
|
||||||
cells[tuple(c)] = Cell(state_class)
|
processes: int):
|
||||||
return cells
|
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
|
@staticmethod
|
||||||
def _apply_neighborhood_to_cells(cells, neighborhood, dimension):
|
def _make_cell_states(state_class, rule, dimension):
|
||||||
for coordinate, cell in cells.items():
|
cell_states = {}
|
||||||
n_coordinates = neighborhood.calculate_cell_neighbor_coordinates(coordinate, dimension)
|
for c in itertools.product(*[range(d) for d in dimension]):
|
||||||
cell.neighbor_states = [cells[tuple(nc)].state for nc in n_coordinates]
|
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
|
Copyright 2019 Richard Feistenauer
|
||||||
from itertools import product
|
|
||||||
|
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_EDGE_CELLS = 0
|
||||||
IGNORE_MISSING_NEIGHBORS_OF_EDGE_CELLS = 1
|
IGNORE_MISSING_NEIGHBORS_OF_EDGE_CELLS = 1
|
||||||
FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS = 2
|
FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS = 2
|
||||||
@ -29,13 +45,16 @@ class Neighborhood:
|
|||||||
self.__grid_dimensions = grid_dimensions
|
self.__grid_dimensions = grid_dimensions
|
||||||
return list(self.__neighbors_generator(cell_coordinate))
|
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):
|
def __neighbors_generator(self, cell_coordinate):
|
||||||
if not self.__does_ignore_edge_cell_rule_apply(cell_coordinate):
|
if not self.__does_ignore_edge_cell_rule_apply(cell_coordinate):
|
||||||
for rel_n in self._rel_neighbors:
|
for rel_n in self._rel_neighbors:
|
||||||
yield from self.__calculate_abs_neighbor_and_decide_validity(cell_coordinate, rel_n)
|
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):
|
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)
|
n_folded = self.__apply_edge_overflow(n)
|
||||||
if n == n_folded or self.__edge_rule == EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS:
|
if n == n_folded or self.__edge_rule == EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS:
|
||||||
yield n_folded
|
yield n_folded
|
||||||
@ -70,6 +89,6 @@ class VonNeumannNeighborhood(Neighborhood):
|
|||||||
|
|
||||||
|
|
||||||
def _rel_neighbor_generator(dimension, range_, rule):
|
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:
|
if rule(c) and c != (0, ) * dimension:
|
||||||
yield tuple(reversed(c))
|
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:
|
class Rule:
|
||||||
def __init__(self):
|
def __init__(self, neighborhood_: neighbour.Neighborhood):
|
||||||
pass
|
self._neighborhood = neighborhood_
|
||||||
|
|
||||||
@staticmethod
|
def _get_neighbor_by_relative_coordinate(self, neighbours, rel_coordinate):
|
||||||
@abstractmethod
|
return neighbours[self._neighborhood.get_neighbor_id_from_rel(rel_coordinate)]
|
||||||
def evolve_cell(last_cell_state, neighbors_last_states):
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def evolve_cell(self, last_cell_state, neighbors_last_states):
|
||||||
""" Calculates and sets new state of 'cell'.
|
""" Calculates and sets new state of 'cell'.
|
||||||
:param last_cell_state: The cells current state to calculate new state for.
|
:param last_cell_state: The cells current state to calculate new state for.
|
||||||
:param neighbors_last_states: The cells neighbors current states.
|
: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.
|
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
|
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 *
|
from cellular_automaton import *
|
||||||
|
|
||||||
|
|
||||||
|
ALIVE = [1.0]
|
||||||
|
DEAD = [0]
|
||||||
|
|
||||||
|
|
||||||
class TestRule(Rule):
|
class TestRule(Rule):
|
||||||
random_seed = random.seed(1000)
|
random_seed = random.seed(13)
|
||||||
|
|
||||||
def init_state(self, cell_coordinate):
|
def init_state(self, cell_coordinate):
|
||||||
rand = random.randrange(0, 101, 1)
|
rand = random.randrange(0, 16, 1)
|
||||||
init = max(.0, float(rand - 99))
|
init = max(.0, float(rand - 14))
|
||||||
return (init,)
|
return (init,)
|
||||||
|
|
||||||
def evolve_cell(self, last_cell_state, neighbors_last_states):
|
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):
|
def get_state_draw_color(self, current_state):
|
||||||
return [255 if current_state[0] else 0, 0, 0]
|
return [255 if current_state[0] else 0, 0, 0]
|
||||||
@ -21,7 +43,8 @@ class TestRule(Rule):
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
neighborhood = MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS)
|
neighborhood = MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS)
|
||||||
ca = CAFactory.make_single_process_cellular_automaton(dimension=[100, 100],
|
ca = CAFactory.make_multi_process_cellular_automaton(dimension=[100, 100],
|
||||||
neighborhood=neighborhood,
|
neighborhood=neighborhood,
|
||||||
rule=TestRule)
|
rule=TestRule,
|
||||||
|
processes=4)
|
||||||
ca_window = CAWindow(cellular_automaton=ca, evolution_steps_per_draw=1)
|
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],
|
ca = CAFactory.make_single_process_cellular_automaton(dimension=[100, 100],
|
||||||
neighborhood=neighborhood,
|
neighborhood=neighborhood,
|
||||||
rule=TestRule)
|
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
|
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
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
class TestState(CellState):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
|
|
||||||
class TestCellState(unittest.TestCase):
|
class TestCellState(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.cell = Cell(TestState)
|
self.neighbors = [CellState() for x in range(5)]
|
||||||
self.neighbors = [TestState() for x in range(5)]
|
|
||||||
for neighbor in self.neighbors:
|
for neighbor in self.neighbors:
|
||||||
neighbor.set_state_of_evolution_step((0, ), 0)
|
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):
|
def cell_and_neighbors_active(self, evolution_step):
|
||||||
self.neighbors.append(self.cell.state)
|
self.neighbors.append(self.cell._state)
|
||||||
all_active = True
|
all_active = True
|
||||||
for state in self.neighbors:
|
for state in self.neighbors:
|
||||||
if not state.is_active(evolution_step):
|
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
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
class TestCellState(unittest.TestCase):
|
class TestCellState(unittest.TestCase):
|
||||||
def setUp(self):
|
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):
|
def test_get_state_with_overflow(self):
|
||||||
self.cell_state.set_state_of_evolution_step(new_state=(1,), evolution_step=0)
|
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)
|
return self.cell_state.set_state_of_evolution_step(new_state=(1, 1), evolution_step=0)
|
||||||
|
|
||||||
def test_redraw_flag(self):
|
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.assertTrue(self.cell_state.is_set_for_redraw())
|
||||||
self.cell_state.was_redrawn()
|
self.cell_state.was_redrawn()
|
||||||
self.assertFalse(self.cell_state.is_set_for_redraw())
|
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
|
import sys
|
||||||
sys.path.append('../src')
|
sys.path.append('../..')
|
||||||
|
|
||||||
from cellular_automaton.cellular_automaton import *
|
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 unittest
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
|
|
||||||
class TestFac(CAFactory):
|
class TestFac(CAFactory):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def make_cells(dimension, state_class):
|
def make_cell_states(state_class, rule_, dimension):
|
||||||
return CAFactory._make_cells(dimension, state_class)
|
return CAFactory._make_cell_states(state_class, rule_, dimension)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def apply_neighborhood(cells, neighborhood, dimension):
|
def make_cells(cells, neighborhood_, dimension):
|
||||||
return CAFactory._apply_neighborhood_to_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):
|
class TestCAFactory(unittest.TestCase):
|
||||||
@ -21,48 +54,52 @@ class TestCAFactory(unittest.TestCase):
|
|||||||
self._neighborhood = MooreNeighborhood(EdgeRule.IGNORE_EDGE_CELLS)
|
self._neighborhood = MooreNeighborhood(EdgeRule.IGNORE_EDGE_CELLS)
|
||||||
|
|
||||||
def test_make_ca_calls_correct_methods(self):
|
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, '_make_cell_states', return_value={1: True}) as m1:
|
||||||
with mock.patch.object(CAFactory, '_apply_neighborhood_to_cells') as m2:
|
with mock.patch.object(CAFactory, '_make_cells') as m2:
|
||||||
CAFactory.make_cellular_automaton([10], self._neighborhood, CellState, Rule())
|
TestFac.make_cellular_automaton_state([10], self._neighborhood, CellState, Rule)
|
||||||
m1.assert_called_once_with([10], CellState)
|
m1.assert_called_once()
|
||||||
m2.assert_called_once_with({1: True}, self._neighborhood, [10])
|
m2.assert_called_once_with({1: True}, self._neighborhood, [10])
|
||||||
|
|
||||||
def test_make_ca_returns_correct_values(self):
|
def test_make_ca_returns_correct_values(self):
|
||||||
|
with mock.patch.object(CAFactory, '_make_cell_states', return_value={1: True}):
|
||||||
with mock.patch.object(CAFactory, '_make_cells', return_value={1: True}):
|
with mock.patch.object(CAFactory, '_make_cells', return_value={1: True}):
|
||||||
with mock.patch.object(CAFactory, '_apply_neighborhood_to_cells'):
|
ca = TestFac.make_cellular_automaton_state([10], self._neighborhood, CellState, Rule)
|
||||||
ca = CAFactory.make_cellular_automaton([10], self._neighborhood, CellState, Rule())
|
|
||||||
self.assertIsInstance(ca, CellularAutomatonState)
|
self.assertIsInstance(ca, CellularAutomatonState)
|
||||||
self.assertEqual(tuple(ca.cells.values()), (True, ))
|
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):
|
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,)])
|
self.assertEqual(list(c.keys()), [(0,), (1,), (2,)])
|
||||||
|
|
||||||
def test_2dimension_coordinates(self):
|
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)])
|
self.assertEqual(list(c.keys()), [(0, 0), (0, 1), (1, 0), (1, 1)])
|
||||||
|
|
||||||
def test_3dimension_coordinates(self):
|
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),
|
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)])
|
(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__':
|
if __name__ == '__main__':
|
||||||
unittest.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
|
import sys
|
||||||
sys.path.append('../src')
|
sys.path.append('../..')
|
||||||
|
|
||||||
from cellular_automaton import cellular_automaton as csn
|
from cellular_automaton import cellular_automaton as csn
|
||||||
import unittest
|
import unittest
|
||||||
|
Loading…
Reference in New Issue
Block a user