Skip to content

Commit

Permalink
Merge branch 'arayabrain:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
gallorob committed Oct 31, 2022
2 parents d058ef3 + 891403d commit fa65e43
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 40 deletions.
9 changes: 6 additions & 3 deletions pcgsepy/fi2pop/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def subdivide_solutions(lcs: List[CandidateSolution],
logging.getLogger('fi2pop').debug(f'[{__name__}.subdivide_solutions] Initial {len(lcs)=}.')
for i, cs in enumerate(lcs):
try:
_ = cs.content.as_array
for t in [ConstraintTime.DURING, ConstraintTime.END]:
sat = lsystem.hl_solver._check_constraints(cs=cs,
when=t,
Expand All @@ -45,8 +46,8 @@ def subdivide_solutions(lcs: List[CandidateSolution],
except IntersectionException:
logging.getLogger('fi2pop').debug(f'[{__name__}.subdivide_solutions] {cs.string} removed: intersection.')
pass
except MemoryError:
logging.getLogger('fi2pop').debug(f'[{__name__}.subdivide_solutions] {cs.string} removed: too large.')
except (MemoryError, np.core._exceptions._ArrayMemoryError) as e:
logging.getLogger('fi2pop').debug(f'[{__name__}.subdivide_solutions] {cs.string} removed: too large ({type(e).__name__}).')
removable.append(i)
for i in list(reversed(removable)):
lcs.pop(i)
Expand Down Expand Up @@ -116,13 +117,15 @@ def create_new_pool(population: List[CandidateSolution],
logging.getLogger('fi2pop').debug(f'[{__name__}.create_new_pool] xover1p: Parent: {p.string=},{p.base_color}; Offsprings: {o1.string=},{o1.base_color}; {o2.string=},{o2.base_color}')
childs = [o1, o2]
for o in childs:
logging.getLogger('fi2pop').debug(f'[{__name__}.create_new_pool] xover1p: {len(o.string)=}; {MAX_STRING_LEN=} {len(o.string) <= MAX_STRING_LEN=}')
if MAX_STRING_LEN == -1 or len(o.string) <= MAX_STRING_LEN:
# mutation
try:
mutate(cs=o, n_iteration=generation)
except EvoException as e:
logging.getLogger('fi2pop').error(f'[{__name__}.create_new_pool] xover1p: Parent: {e=}')
if o not in pool:
logging.getLogger('fi2pop').debug(f'[{__name__}.create_new_pool] xover1p: {o not in pool=}; {len(o.string) <= MAX_STRING_LEN=}')
if o not in pool and (MAX_STRING_LEN == -1 or len(o.string) <= MAX_STRING_LEN):
pool.append(o)
if len(pool) == prev_len_pool:
patience -= 1
Expand Down
3 changes: 1 addition & 2 deletions pcgsepy/guis/ships_comparator/webapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,7 @@ def parse_contents(filename: str,
Tuple[int, int, str]: The RNG seed, the number of the experiment, and the content string.
"""
if filename.endswith('.zip'):
raise ValueError('Do not upload the .zip file; only upload the spaceship file (`spaceship_{YOUR_ID}_exp{N}`).')
logging.getLogger('webapp').error(msg=f'[{__name__}.parse_contents] {filename=}')
raise ValueError('Do not upload the `.zip` file; only upload the spaceship file (`spaceship_{YOUR_ID}_exp{N}`).')
_, rngseed, exp_n = filename.split('_')
rngseed = int(rngseed)
exp_n = int(exp_n.replace('exp', ''))
Expand Down
53 changes: 27 additions & 26 deletions pcgsepy/hullbuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from typing import List, Optional, Tuple
from itertools import product
from pcgsepy.common.vecs import rotate, get_rotation_matrix
from scipy.spatial.transform import Rotation
from enum import IntEnum


Expand All @@ -31,8 +30,23 @@ class BlockValue(IntEnum):
BlockValue.CORNERSQUAREINV_BLOCK: 'MyObjectBuilder_CubeBlock_LargeBlockArmorCornerSquareInverted',
}

_orientations = [Orientation.FORWARD, Orientation.BACKWARD, Orientation.UP, Orientation.DOWN, Orientation.LEFT, Orientation.RIGHT]
_valid_orientations = [(of, ou) for (of, ou) in list(product(_orientations, _orientations)) if of != ou and of != orientation_from_vec(ou.value.opposite())]
# _smoothing_order = {
# BlockValue.BASE_BLOCK: [BlockValue.SLOPE_BLOCK, BlockValue.CORNERSQUARE_BLOCK, BlockValue.CORNER_BLOCK],
# BlockValue.CORNERSQUAREINV_BLOCK: [],
# BlockValue.CORNERINV_BLOCK: [],
# BlockValue.SLOPE_BLOCK: [BlockValue.CORNERSQUARE_BLOCK, BlockValue.CORNER_BLOCK]
# }
_smoothing_order = {
BlockValue.BASE_BLOCK: [BlockValue.SLOPE_BLOCK],
BlockValue.SLOPE_BLOCK: [BlockValue.CORNER_BLOCK]
}


class HullBuilder:
__slots__ = ['available_erosion_types', 'erosion_type', 'erosion', 'footprint', 'iterations', 'apply_erosion', 'apply_smoothing', 'base_block', 'obstruction_targets', '_blocks_set']

def __init__(self,
erosion_type: str,
apply_erosion: bool,
Expand Down Expand Up @@ -68,19 +82,6 @@ def __init__(self,
self.base_block = 'MyObjectBuilder_CubeBlock_LargeBlockArmorBlock'
self.obstruction_targets = ['window', 'thrust']
self._blocks_set = {}

self._orientations = [Orientation.FORWARD, Orientation.BACKWARD, Orientation.UP, Orientation.DOWN, Orientation.LEFT, Orientation.RIGHT]
self._valid_orientations = [(of, ou) for (of, ou) in list(product(self._orientations, self._orientations)) if of != ou and of != orientation_from_vec(ou.value.opposite())]
# self._smoothing_order = {
# BlockValue.BASE_BLOCK: [BlockValue.SLOPE_BLOCK, BlockValue.CORNERSQUARE_BLOCK, BlockValue.CORNER_BLOCK],
# BlockValue.CORNERSQUAREINV_BLOCK: [],
# BlockValue.CORNERINV_BLOCK: [],
# BlockValue.SLOPE_BLOCK: [BlockValue.CORNERSQUARE_BLOCK, BlockValue.CORNER_BLOCK]
# }
self._smoothing_order = {
BlockValue.BASE_BLOCK: [BlockValue.SLOPE_BLOCK],
BlockValue.SLOPE_BLOCK: [BlockValue.CORNER_BLOCK]
}

def _get_convex_hull(self,
arr: np.ndarray) -> np.ndarray:
Expand Down Expand Up @@ -229,7 +230,7 @@ def _remove_obstructing_blocks(self,
for (i, j, k) in list(self._blocks_set.keys()):
if hull[i, j, k] != BlockValue.AIR_BLOCK: # skip removed blocks
loc = Vec.from_tuple((scale * i, scale * j, scale * k))
for direction in self._orientations:
for direction in _orientations:
ntt = self._next_to_target(loc=loc,
structure=structure,
direction=direction.value.scale(scale))
Expand Down Expand Up @@ -274,7 +275,7 @@ def _remove_floating_blocks(self,
for block_position in to_check:
if mask[block_position] == BlockValue.BASE_BLOCK:
connected_blocks.add(block_position)
for direction in self._orientations:
for direction in _orientations:
dpos = Vec.from_tuple(block_position).sum(direction.value)
if 0 <= dpos.x < structure_shape.x and 0 <= dpos.y < structure_shape.y and 0 <= dpos.z < structure_shape.z:
to_add.add(dpos.as_tuple())
Expand Down Expand Up @@ -305,7 +306,7 @@ def _get_outer_indices(self,
n_neighbours = np.zeros_like(arr)
for idx, _ in np.ndenumerate(arr):
if self._blocks_set.get(idx, None):
for offset in self._orientations:
for offset in _orientations:
pos = Vec.from_tuple(idx).sum(offset.value).as_tuple()
if self._blocks_set.get(pos, None):
n_neighbours[idx] = n_neighbours[idx] + 1
Expand All @@ -329,7 +330,7 @@ def adj_in_hull(self,
List[Tuple[int, int, int]]: The list of adjacent indices.
"""
adjs = []
for direction in self._orientations:
for direction in _orientations:
new_idx = Vec.from_tuple(idx).sum(direction.value).as_tuple()
if new_idx in self._blocks_set.keys():
adjs.append(new_idx)
Expand Down Expand Up @@ -553,7 +554,7 @@ def _check_valid_position(self,
"""
valid = True
area_err = 0
for direction in self._orientations:
for direction in _orientations:
res, delta_area = self._check_valid_placement(idx=idx,
block=block,
direction=direction,
Expand Down Expand Up @@ -589,19 +590,19 @@ def try_smoothing(self,
if not valid:
return None, BlockValue.AIR_BLOCK
# replacement check
elif block_type in self._smoothing_order.keys():
elif block_type in _smoothing_order.keys():
# give priority to surrounding blocks orientations
neighbourhood = self._get_neighbourhood(idx=idx,
structure=structure)
priority_scores = np.zeros(shape=len(self._valid_orientations), dtype=np.int8).tolist()
priority_scores = np.zeros(shape=len(_valid_orientations), dtype=np.int8).tolist()
for other_block in neighbourhood:
oo = (orientation_from_vec(other_block.orientation_forward),
orientation_from_vec(other_block.orientation_up))
priority_scores[self._valid_orientations.index(oo)] = priority_scores[self._valid_orientations.index(oo)] + 1
idxs = [x for _, x in sorted(zip(priority_scores, np.arange(len(self._valid_orientations)).tolist()))]
priority_orientations = [self._valid_orientations[i] for i in idxs]
for possible_type in self._smoothing_order[block_type]:
orientation_scores, valids = np.zeros(shape=len(self._valid_orientations), dtype=np.float32), np.zeros(shape=len(self._valid_orientations), dtype=np.bool8)
priority_scores[_valid_orientations.index(oo)] = priority_scores[_valid_orientations.index(oo)] + 1
idxs = [x for _, x in sorted(zip(priority_scores, np.arange(len(_valid_orientations)).tolist()))]
priority_orientations = [_valid_orientations[i] for i in idxs]
for possible_type in _smoothing_order[block_type]:
orientation_scores, valids = np.zeros(shape=len(_valid_orientations), dtype=np.float32), np.zeros(shape=len(_valid_orientations), dtype=np.bool8)
# try replacement
for i, (of, ou) in enumerate(priority_orientations):
possible_block = Block(block_type=block_value_types[possible_type],
Expand Down
16 changes: 8 additions & 8 deletions pcgsepy/structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,9 @@ def __init__(self, origin: Vec,

self._blocks: Dict[Tuple(int, int, int), Block] = {}
self._has_intersections: bool = None
self._scaled_arr: npt.NDArray[np.uint32] = None
self._scaled_arr: npt.NDArray[np.uint16] = None
self._air_gridmask: npt.NDArray[np.bool8] = None
self._arr: npt.NDArray[np.uint32] = None
self._arr: npt.NDArray[np.uint16] = None

def __repr__(self) -> str:
return f'{self.grid_size}x Structure with {len(self._blocks.keys())} blocks'
Expand Down Expand Up @@ -288,15 +288,15 @@ def _min_dims(self) -> Tuple[int, int, int]:
return min_x, min_y, min_z

@property
def as_array(self) -> npt.NDArray[np.uint32]:
def as_array(self) -> npt.NDArray[np.uint16]:
"""Convert the structure to its equivalent NumPy array.
Each point in the XYZ matrix represents the block type.
Returns:
npt.NDArray[np.uint32]: The 3D NumPy array.
npt.NDArray[np.uint16]: The 3D NumPy array.
"""
if self._scaled_arr is None:
self._scaled_arr = np.zeros(shape=Vec.from_tuple(self._max_dims).add(v=self.grid_size).as_tuple(), dtype=np.uint32)
self._scaled_arr = np.zeros(shape=Vec.from_tuple(self._max_dims).add(v=self.grid_size).as_tuple(), dtype=np.uint16)
for (i, j, k), block in self._blocks.items():
r = block.scaled_size
if np.sum(self._scaled_arr[i:i + r.x, j:j + r.y, k:k + r.z]) != 0:
Expand All @@ -305,15 +305,15 @@ def as_array(self) -> npt.NDArray[np.uint32]:
return self._scaled_arr

@property
def as_grid_array(self) -> npt.NDArray[np.uint32]:
def as_grid_array(self) -> npt.NDArray[np.uint16]:
"""Convert the structure to the grid-sized array.
Each point in the XYZ matrix represents the block type.
Returns:
npt.NDArray[np.uint32]: The 3D NumPy grid-sized array.
npt.NDArray[np.uint16]: The 3D NumPy grid-sized array.
"""
if self._arr is None:
self._arr = np.zeros(shape=Vec.from_tuple(self._max_dims).scale(v=1 / self.grid_size).to_veci().add(v=1).as_tuple(), dtype=np.uint32)
self._arr = np.zeros(shape=Vec.from_tuple(self._max_dims).scale(v=1 / self.grid_size).to_veci().add(v=1).as_tuple(), dtype=np.uint16)
for r, block in self._blocks.items():
r = Vec.from_tuple(r).scale(v=1 / self.grid_size).to_veci().as_tuple()
if np.sum(self._arr[r]) != 0:
Expand Down
2 changes: 1 addition & 1 deletion user-study/configs.ini
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ crossover_p = 0.4
population_size = 20
n_initial_retries = 100
n_generations = 50
max_string_len = 500
max_string_len = 1000
gen_patience = 5
[FITNESS]
use_bounding_box = False
Expand Down

0 comments on commit fa65e43

Please sign in to comment.