diff --git a/algorithms/genetic/common.py b/algorithms/genetic/common.py new file mode 100644 index 0000000..9a4ed11 --- /dev/null +++ b/algorithms/genetic/common.py @@ -0,0 +1,7 @@ +from dataclasses import dataclass + + +@dataclass +class Position: + row: int + col: int diff --git a/algorithms/genetic/const.py b/algorithms/genetic/const.py new file mode 100644 index 0000000..91398c7 --- /dev/null +++ b/algorithms/genetic/const.py @@ -0,0 +1,25 @@ +# map config +KNIGHTS_PER_TEAM_COUNT = 4 +SAND_COUNT = 21 +WATER_COUNT = 21 +TREE_COUNT = 37 +MONSTERS_COUNT = 2 +CASTLES_COUNT = 1 +ROWS = 19 +COLUMNS = 24 +KNIGHTS_SPAWN_WIDTH = 4 +KNIGHTS_SPAWN_HEIGHT = 7 +LEFT_KNIGHTS_SPAWN_FIRST_ROW = 6 +LEFT_KNIGHTS_SPAWN_FIRST_COL = 0 +RIGHT_KNIGHTS_SPAWN_FIRST_ROW = 6 +RIGHT_KNIGHTS_SPAWN_FIRST_COL = 20 + +# aliases +GRASS = 0 +SAND = 1 +WATER = 2 +TREE = 3 +MONSTER = 4 +CASTLE = 5 +KNIGHT_RED = 6 +KNIGHT_BLUE = 7 diff --git a/algorithms/genetic/genome.py b/algorithms/genetic/genome.py new file mode 100644 index 0000000..81ee497 --- /dev/null +++ b/algorithms/genetic/genome.py @@ -0,0 +1,71 @@ +from random import randrange +from typing import List + +import numpy as np +import numpy.typing as npt + +from common import Position +from const import * + + +class Genome: + grid: npt.NDArray + knights_red: List[Position] + knights_blue: List[Position] + + def __init__(self): + self.grid = np.zeros((ROWS, COLUMNS), dtype=int) + + # todo: spawning castle, monsters, sand, trees in the same way as bellow + self.knights_red = spawn_objects_in_given_area( + grid=self.grid, + object_alias=KNIGHT_RED, + objects_count=KNIGHTS_PER_TEAM_COUNT, + spawn_position_start=Position(row=LEFT_KNIGHTS_SPAWN_FIRST_ROW, col=LEFT_KNIGHTS_SPAWN_FIRST_COL), + width=KNIGHTS_SPAWN_WIDTH, + height=KNIGHTS_SPAWN_HEIGHT + ) + + self.knights_blue = spawn_objects_in_given_area( + grid=self.grid, + object_alias=KNIGHT_BLUE, + objects_count=KNIGHTS_PER_TEAM_COUNT, + spawn_position_start=Position(row=RIGHT_KNIGHTS_SPAWN_FIRST_ROW, col=RIGHT_KNIGHTS_SPAWN_FIRST_COL), + width=KNIGHTS_SPAWN_WIDTH, + height=KNIGHTS_SPAWN_HEIGHT + ) + + +def is_empty(grid: npt.NDArray, position: Position) -> bool: + return grid[position.row, position.col] in [GRASS, SAND] + + +def is_invalid_area(spawn_position_start, height, width) -> bool: + return spawn_position_start.row + height - 1 < 0 or \ + spawn_position_start.row + height - 1 >= ROWS or \ + spawn_position_start.col + width - 1 < 0 or \ + spawn_position_start.col + width - 1 >= COLUMNS + + +def spawn_objects_in_given_area(grid: npt.NDArray, object_alias: KNIGHT_RED | KNIGHT_BLUE | CASTLE | MONSTER, + objects_count: int = 1, + spawn_position_start: Position = Position(row=0, col=0), + width: int = 1, + height: int = 1) -> List[Position]: + if is_invalid_area(spawn_position_start, height, width): + raise ValueError("Invalid spawn area") + + objects_remaining = int(objects_count) + positions = [] + + while objects_remaining > 0: + row = randrange(spawn_position_start.row, spawn_position_start.row + height) + col = randrange(spawn_position_start.col, spawn_position_start.col + width) + position = Position(row=row, col=col) + + if is_empty(grid=grid, position=position): + grid[position.row, position.col] = object_alias + positions.append(position) + objects_remaining -= 1 + + return positions diff --git a/algorithms/genetic/map_generator.py b/algorithms/genetic/map_generator.py index 751096b..0165783 100644 --- a/algorithms/genetic/map_generator.py +++ b/algorithms/genetic/map_generator.py @@ -1,102 +1,4 @@ -from dataclasses import dataclass -from random import randrange -from typing import List - -import numpy as np -import numpy.typing as npt - -# map config -KNIGHTS_PER_TEAM_COUNT = 4 -SAND_COUNT = 21 -WATER_COUNT = 21 -TREE_COUNT = 37 -MONSTERS_COUNT = 2 -CASTLES_COUNT = 1 -ROWS = 19 -COLUMNS = 24 -KNIGHTS_SPAWN_WIDTH = 4 -KNIGHTS_SPAWN_HEIGHT = 7 -LEFT_KNIGHTS_SPAWN_FIRST_ROW = 6 -LEFT_KNIGHTS_SPAWN_FIRST_COL = 0 -RIGHT_KNIGHTS_SPAWN_FIRST_ROW = 6 -RIGHT_KNIGHTS_SPAWN_FIRST_COL = 20 - -# aliases -GRASS = 0 -SAND = 1 -WATER = 2 -TREE = 3 -MONSTER = 4 -CASTLE = 5 -KNIGHT_RED = 6 -KNIGHT_BLUE = 7 - - -@dataclass -class Position: - row: int - col: int - - -class Genome: - grid: npt.NDArray - knights_red: List[Position] - knights_blue: List[Position] - - def __init__(self): - self.grid = np.zeros((ROWS, COLUMNS), dtype=int) - self.knights_red = spawn_objects_in_given_area( - grid=self.grid, - object_alias=KNIGHT_RED, - objects_count=KNIGHTS_PER_TEAM_COUNT, - spawn_position_start=Position(row=LEFT_KNIGHTS_SPAWN_FIRST_ROW, col=LEFT_KNIGHTS_SPAWN_FIRST_COL), - width=KNIGHTS_SPAWN_WIDTH, - height=KNIGHTS_SPAWN_HEIGHT - ) - - self.knights_blue = spawn_objects_in_given_area( - grid=self.grid, - object_alias=KNIGHT_BLUE, - objects_count=KNIGHTS_PER_TEAM_COUNT, - spawn_position_start=Position(row=RIGHT_KNIGHTS_SPAWN_FIRST_ROW, col=RIGHT_KNIGHTS_SPAWN_FIRST_COL), - width=KNIGHTS_SPAWN_WIDTH, - height=KNIGHTS_SPAWN_HEIGHT - ) - - -def is_empty(grid: npt.NDArray, position: Position) -> bool: - return grid[position.row, position.col] in [GRASS, SAND] - - -def is_invalid_area(spawn_position_start, height, width) -> bool: - return spawn_position_start.row + height - 1 < 0 or \ - spawn_position_start.row + height - 1 >= ROWS or \ - spawn_position_start.col + width - 1 < 0 or \ - spawn_position_start.col + width - 1 >= COLUMNS - - -def spawn_objects_in_given_area(grid: npt.NDArray, object_alias: KNIGHT_RED | KNIGHT_BLUE | CASTLE | MONSTER, - objects_count: int = 1, - spawn_position_start: Position = Position(row=0, col=0), - width: int = 1, - height: int = 1) -> List[Position]: - if is_invalid_area(spawn_position_start, height, width): - raise ValueError("Invalid spawn area") - - objects_remaining = int(objects_count) - positions = [] - - while objects_remaining > 0: - row = randrange(spawn_position_start.row, spawn_position_start.row + height) - col = randrange(spawn_position_start.col, spawn_position_start.col + width) - position = Position(row=row, col=col) - - if is_empty(grid=grid, position=position): - grid[position.row, position.col] = object_alias - positions.append(position) - objects_remaining -= 1 - - return positions +from genome import Genome def main() -> None: