Compare commits

..

No commits in common. "master" and "decision_tree_impl" have entirely different histories.

32 changed files with 107 additions and 1047 deletions

3
.gitignore vendored
View File

@ -149,5 +149,4 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear # and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder. # option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/ .idea/
/algorithms/neural_network/data/

View File

@ -4,11 +4,10 @@ import heapq
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Tuple, Optional, List from typing import Tuple, Optional, List
from algorithms.genetic.const import MAP_ALIASES
from common.constants import ROWS, COLUMNS, LEFT, RIGHT, UP, DOWN from common.constants import ROWS, COLUMNS, LEFT, RIGHT, UP, DOWN
from common.helpers import directions from common.helpers import directions
EMPTY_FIELDS = [MAP_ALIASES.get("SAND"), MAP_ALIASES.get("GRASS"), ' '] EMPTY_FIELDS = ['s', 'g', ' ']
TURN_LEFT = 'TURN_LEFT' TURN_LEFT = 'TURN_LEFT'
TURN_RIGHT = 'TURN_RIGHT' TURN_RIGHT = 'TURN_RIGHT'

View File

@ -51,7 +51,7 @@ def graphsearch(initial_state: State, map, goal_list, fringe: List[Node] = None,
explored_states = set() explored_states = set()
fringe_states = set() fringe_states = set()
# train Node # root Node
fringe.append(Node(initial_state)) fringe.append(Node(initial_state))
fringe_states.add((initial_state.row, initial_state.column, initial_state.direction)) fringe_states.add((initial_state.row, initial_state.column, initial_state.direction))
@ -71,7 +71,7 @@ def graphsearch(initial_state: State, map, goal_list, fringe: List[Node] = None,
parent = element.parent parent = element.parent
while parent is not None: while parent is not None:
# train's action will be None, don't add it # root's action will be None, don't add it
if parent.action is not None: if parent.action is not None:
actions_sequence.append(parent.action) actions_sequence.append(parent.action)
parent = parent.parent parent = parent.parent

View File

@ -1,142 +0,0 @@
from dataclasses import dataclass
import numpy as np
from const import *
from typing import List, Dict, Tuple
import numpy.typing as npt
@dataclass
class Position:
row: int
col: int
@dataclass
class Area:
position: Position
width: int
height: int
AREAS_TO_CROSS = [
# up above left knights spawn
Area(position=Position(row=0, col=0),
width=KNIGHTS_SPAWN_WIDTH,
height=LEFT_KNIGHTS_SPAWN_FIRST_ROW),
# down below left knights spawn
Area(position=Position(row=LEFT_KNIGHTS_SPAWN_FIRST_ROW + KNIGHTS_SPAWN_HEIGHT, col=0),
width=KNIGHTS_SPAWN_WIDTH,
height=ROWS - LEFT_KNIGHTS_SPAWN_FIRST_ROW - KNIGHTS_SPAWN_HEIGHT),
# between left knights spawn and castle
Area(position=Position(row=0, col=KNIGHTS_SPAWN_WIDTH),
width=CASTLE_SPAWN_FIRST_COL - KNIGHTS_SPAWN_WIDTH,
height=ROWS),
# up above castle
Area(position=Position(row=0, col=CASTLE_SPAWN_FIRST_COL),
width=2,
height=CASTLE_SPAWN_FIRST_ROW),
# down below castle
Area(position=Position(row=CASTLE_SPAWN_FIRST_ROW + 2, col=CASTLE_SPAWN_FIRST_COL),
width=2,
height=ROWS - CASTLE_SPAWN_FIRST_ROW - 2),
# between castle and right knights spawn
Area(position=Position(row=0, col=CASTLE_SPAWN_FIRST_COL + 2),
width=RIGHT_KNIGHTS_SPAWN_FIRST_COL - CASTLE_SPAWN_FIRST_COL - 2,
height=ROWS),
# up above right knights spawn
Area(position=Position(row=0, col=RIGHT_KNIGHTS_SPAWN_FIRST_COL),
width=KNIGHTS_SPAWN_WIDTH,
height=RIGHT_KNIGHTS_SPAWN_FIRST_ROW),
# down below right knights spawn
Area(position=Position(row=RIGHT_KNIGHTS_SPAWN_FIRST_ROW + KNIGHTS_SPAWN_HEIGHT, col=RIGHT_KNIGHTS_SPAWN_FIRST_COL),
width=KNIGHTS_SPAWN_WIDTH,
height=ROWS - RIGHT_KNIGHTS_SPAWN_FIRST_ROW - KNIGHTS_SPAWN_HEIGHT),
]
def dfs(grid: npt.NDArray, visited: Dict[Tuple[int, int], bool], position: Position, rows: int, cols: int) -> None:
visited[(position.row, position.col)] = True
row_vector = [0, 0, 1, -1]
col_vector = [-1, 1, 0, 0]
neighbours = []
for i in range(4):
rr = position.row + row_vector[i]
cc = position.col + col_vector[i]
if rr < 0 or rr >= ROWS:
continue
elif cc < 0 or cc >= COLUMNS:
continue
else:
p = Position(rr, cc)
if (p.row, p.col) in visited:
neighbours.append(p)
for neighbour in neighbours:
if not visited[(neighbour.row, neighbour.col)]:
dfs(grid, visited, neighbour, rows, cols)
def get_islands(grid: npt.NDArray, positions: List[Position], rows: int = ROWS, cols: int = COLUMNS) -> List[Position]:
"""it returns list of all islands roots"""
visited = {}
for position in positions:
visited[(position.row, position.col)] = False
islands = 0
roots = []
for position in positions:
if not visited[(position.row, position.col)]:
dfs(grid, visited, position, rows, cols)
roots.append(position)
islands += 1
return roots
def find_neighbours(grid: npt.NDArray, col: int, row: int) -> List[Position]:
dr = [-1, 1, 0, 0]
dc = [0, 0, -1, 1]
neighbours = []
for i in range(4):
rr = row + dr[i]
cc = col + dc[i]
if 0 <= rr < ROWS and 0 <= cc < COLUMNS and grid[rr][cc] == MAP_ALIASES.get('GRASS'):
neighbours.append(Position(row=rr, col=cc))
return neighbours
def get_tiles_positions(grid: npt.NDArray):
sands = []
trees = []
waters = []
monsters = []
for row_num in range(len(grid)):
for col_num in range(len(grid[row_num])):
if grid[row_num][col_num] == MAP_ALIASES.get('WATER'):
waters.append(Position(row=row_num, col=col_num))
elif grid[row_num][col_num] == MAP_ALIASES.get('TREE'):
trees.append(Position(row=row_num, col=col_num))
elif grid[row_num][col_num] == MAP_ALIASES.get('SAND'):
sands.append(Position(row=row_num, col=col_num))
elif grid[row_num][col_num] == MAP_ALIASES.get('MONSTER'):
monsters.append(Position(row=row_num, col=col_num))
return sands, trees, waters, monsters

View File

@ -1,29 +0,0 @@
# 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
CASTLE_SPAWN_FIRST_ROW = 7
CASTLE_SPAWN_FIRST_COL = 11
# map aliases
MAP_ALIASES = {
"GRASS": 0,
"SAND": 1,
"WATER": 2,
"TREE": 3,
"MONSTER": 4,
"CASTLE": 5,
"KNIGHT_RED": 6,
"KNIGHT_BLUE": 7,
}

View File

@ -1,166 +0,0 @@
import math
import random
from copy import deepcopy
from random import randrange
from typing import List
import numpy as np
import numpy.typing as npt
from common import Position, get_islands, AREAS_TO_CROSS, find_neighbours, get_tiles_positions
from const import *
class Genome:
grid: npt.NDArray
knights_red: List[Position]
knights_blue: List[Position]
waters: List[Position]
trees: List[Position]
sands: List[Position]
monsters: List[Position]
fitness: int
sand_islands: List[Position]
tree_islands: List[Position]
water_islands: List[Position]
def __init__(self):
self.grid = np.zeros((ROWS, COLUMNS), dtype=int)
self.fitness = 0
self.knights_red = spawn_objects_in_given_area(
grid=self.grid,
object_alias=MAP_ALIASES.get("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=MAP_ALIASES.get("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
)
spawn_objects_in_given_area(
grid=self.grid,
object_alias=MAP_ALIASES.get("CASTLE"),
objects_count=4,
spawn_position_start=Position(row=CASTLE_SPAWN_FIRST_ROW, col=CASTLE_SPAWN_FIRST_COL),
width=2,
height=2
)
self.waters = spawn_objects_in_given_area(grid=self.grid, object_alias=MAP_ALIASES.get("WATER"),
objects_count=WATER_COUNT)
self.trees = spawn_objects_in_given_area(grid=self.grid, object_alias=MAP_ALIASES.get("TREE"),
objects_count=TREE_COUNT)
self.sands = spawn_objects_in_given_area(grid=self.grid, object_alias=MAP_ALIASES.get("SAND"),
objects_count=SAND_COUNT)
self.monsters = spawn_objects_in_given_area(grid=self.grid, object_alias=MAP_ALIASES.get("MONSTER"),
objects_count=MONSTERS_COUNT)
self.sand_islands = get_islands(self.grid, self.sands)
self.tree_islands = get_islands(self.grid, self.trees)
self.water_islands = get_islands(self.grid, self.waters)
def update_map(self):
self.sands, self.trees, self.waters, self.monsters = get_tiles_positions(self.grid)
self.sand_islands = get_islands(self.grid, self.sands)
self.tree_islands = get_islands(self.grid, self.trees)
self.water_islands = get_islands(self.grid, self.waters)
def calc_fitness(self):
score = SAND_COUNT + TREE_COUNT + WATER_COUNT
score = score - len(self.sand_islands) - len(self.tree_islands) - len(self.water_islands)
sands, trees, waters, monsters = get_tiles_positions(self.grid)
if len(monsters) != MONSTERS_COUNT:
self.fitness = 0
return
if len(sands) < SAND_COUNT or len(trees) < TREE_COUNT or len(waters) < WATER_COUNT:
self.fitness = 5
return
self.fitness = score
def crossover(self, partner):
# replace a randomly selected part of the grid with partner's part
child = Genome()
child.grid = deepcopy(self.grid)
area_to_cross = random.choice(AREAS_TO_CROSS)
for row in range(area_to_cross.position.row, area_to_cross.position.row + area_to_cross.height):
for col in range(area_to_cross.position.col, area_to_cross.position.col + area_to_cross.width):
child.grid[row][col] = partner.grid[row][col]
child.update_map()
return child
def mutate(self, mutation_rate: float):
# remove 1 item from a random island and add a neighbor to another island
if random.random() < mutation_rate:
# select islands of the same, random type
islands_of_same_type = random.choice([self.sand_islands, self.tree_islands, self.water_islands])
random_index = random.randint(0, len(islands_of_same_type) - 1)
island = islands_of_same_type[random_index]
next_island = islands_of_same_type[(random_index + 1) % len(islands_of_same_type)]
free_tiles_nearby = find_neighbours(self.grid, next_island.col, next_island.row)
tile_type = self.grid[island.row][island.col]
self.grid[island.row][island.col] = MAP_ALIASES.get('GRASS')
# todo: if there are no free tiles around then randomize another next_island
if len(free_tiles_nearby) > 0:
random_free_tile = random.choice(free_tiles_nearby)
island.row = random_free_tile.row
island.col = random_free_tile.col
self.grid[island.row][island.col] = tile_type
self.update_map()
def is_empty(grid: npt.NDArray, position: Position) -> bool:
return grid[position.row, position.col] in [MAP_ALIASES.get("GRASS"), MAP_ALIASES.get("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: str,
objects_count: int = 1,
spawn_position_start: Position = Position(row=0, col=0),
width: int = COLUMNS,
height: int = ROWS) -> 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

View File

@ -1,26 +0,0 @@
from algorithms.genetic.genome import Genome
from algorithms.genetic.map_importer_exporter import export_map
from population import Population
def main() -> None:
population_size = 500
mutation_rate = 0.3
population = Population(mutation_rate, population_size, 55)
while not population.evaluate():
# create next generation
population.generate()
# calc fitness
population.calc_fitness()
print(population.best_genome.grid)
print("Fitness of the best: ", population.best_genome.fitness)
export_map(population.best_genome.grid)
if __name__ == '__main__':
main()

View File

@ -1,42 +0,0 @@
import json
import random
import string
from datetime import datetime
from pathlib import Path
import numpy
import numpy.typing as npt
from os import listdir
from os.path import isfile, join
# Save map to file
def export_map(grid: npt.NDArray):
json_data = {"map": grid.tolist()}
now = datetime.now()
file_name = "map_" + now.strftime("%Y_%m_%d_%H_%M_%S") + ".json"
path = Path("../../resources/maps/")
file_to_open = path / file_name
with open(file_to_open, "w+") as write_file:
json.dump(json_data, write_file)
print("Saved map to file " + file_name)
def import_random_map() -> object:
path = "resources/maps"
files = [f for f in listdir(path) if isfile(join(path, f))]
random_map_name = random.choice(files)
return import_map(random_map_name)
# Read map from file
def import_map(file_name: string) -> object:
file_to_open = "resources/maps/" + file_name
with open(file_to_open, "r") as read_file:
print("Reading map from file " + file_name)
decoded_json = json.load(read_file)
decoded_grid = numpy.asarray(decoded_json["map"])
print(decoded_grid)
return decoded_grid.tolist()

View File

@ -1,81 +0,0 @@
import random
from typing import List
import numpy as np
import numpy.typing as npt
from genome import Genome
class Population:
population: List[Genome] = [] # array to hold the current population
mating_pool: List[Genome] = [] # array which we will use for our "mating pool"
generations: int = 0 # number of generations
finished: bool = False # are we finished evolving?
mutation_rate: float
perfect_score: int
best_genome: Genome
def __init__(self, mutation_rate, population_size, perfect_score=20):
self.mutation_rate = mutation_rate
self.perfect_score = perfect_score
for i in range(0, population_size):
new_genome = Genome()
new_genome.calc_fitness()
self.population.append(new_genome)
# create a new generation
def generate(self):
max_fitness = 0
for genome in self.population:
if genome.fitness > max_fitness:
max_fitness = genome.fitness
print("Max fitness of generation " + str(self.generations) + " = " + str(max_fitness))
# refill the population with children from the mating pool
new_population = []
for genome in self.population:
partner_a = self.accept_reject(max_fitness)
partner_b = self.accept_reject(max_fitness)
child = partner_a.crossover(partner_b)
child.mutate(self.mutation_rate)
new_population.append(child)
self.population = new_population
self.generations += 1
# select random with correct probability from population
def accept_reject(self, max_fitness: int):
safe_flag = 0
while safe_flag < 10000:
partner = random.choice(self.population)
r = random.randint(0, max_fitness)
if r < partner.fitness:
return partner
safe_flag += 1
# compute the current "most fit" member of the population
def evaluate(self):
record = 0
best_index = 0
for index in range(len(self.population)):
genome = self.population[index]
if genome.fitness > record:
record = genome.fitness
best_index = index
self.best_genome = self.population[best_index]
if record >= self.perfect_score:
self.finished = True
return self.finished
def calc_fitness(self):
for genome in self.population:
genome.calc_fitness()

View File

@ -1,64 +0,0 @@
import torch
import pytorch_lightning as pl
import torch.nn as nn
from torch.optim import SGD, Adam, lr_scheduler
import torch.nn.functional as F
from torch.utils.data import DataLoader
from watersandtreegrass import WaterSandTreeGrass
from common.constants import DEVICE, BATCH_SIZE, NUM_EPOCHS, LEARNING_RATE, SETUP_PHOTOS, ID_TO_CLASS
class NeuralNetwork(pl.LightningModule):
def __init__(self, numChannels=3, batch_size=BATCH_SIZE, learning_rate=LEARNING_RATE, num_classes=4):
super(NeuralNetwork, self).__init__()
self.conv1 = nn.Conv2d(numChannels, 24, (3, 3), padding=1)
self.relu1 = nn.ReLU()
self.maxpool1 = nn.MaxPool2d((2, 2), stride=2)
self.conv2 = nn.Conv2d(24, 48, (3, 3), padding=1)
self.relu2 = nn.ReLU()
self.fc1 = nn.Linear(48*18*18, 800)
self.relu3 = nn.ReLU()
self.fc2 = nn.Linear(800, 400)
self.relu4 = nn.ReLU()
self.fc3 = nn.Linear(400, 4)
self.logSoftmax = nn.LogSoftmax(dim=1)
self.batch_size = batch_size
self.learning_rate = learning_rate
def forward(self, x):
x = self.conv1(x)
x = self.relu1(x)
x = self.maxpool1(x)
x = self.conv2(x)
x = self.relu2(x)
x = x.reshape(x.shape[0], -1)
x = self.fc1(x)
x = self.relu3(x)
x = self.fc2(x)
x = self.relu4(x)
x = self.fc3(x)
x = self.logSoftmax(x)
return x
def configure_optimizers(self):
optimizer = Adam(self.parameters(), lr=self.learning_rate)
return optimizer
def training_step(self, batch, batch_idx):
x, y = batch
scores = self(x)
loss = F.nll_loss(scores, y)
return loss
def validation_step(self, batch, batch_idx):
x, y = batch
scores = self(x)
val_loss = F.nll_loss(scores, y)
self.log("val_loss", val_loss, on_step=True, on_epoch=True, sync_dist=True)
def test_step(self, batch, batch_idx):
x, y = batch
scores = self(x)
test_loss = F.nll_loss(scores, y)
self.log("test_loss", test_loss, on_step=True, on_epoch=True, sync_dist=True)

View File

@ -1,125 +0,0 @@
import torch
import common.helpers
from common.constants import DEVICE, BATCH_SIZE, NUM_EPOCHS, LEARNING_RATE, SETUP_PHOTOS, ID_TO_CLASS
from watersandtreegrass import WaterSandTreeGrass
from torch.utils.data import DataLoader
from neural_network import NeuralNetwork
from torchvision.io import read_image, ImageReadMode
import torch.nn as nn
from torch.optim import Adam
import matplotlib.pyplot as plt
import pytorch_lightning as pl
from pytorch_lightning.callbacks import EarlyStopping
import torchvision.transforms.functional as F
from PIL import Image
def check_accuracy_tiles():
answer = 0
for i in range(100):
if what_is_it('../../resources/textures/grass_with_tree.jpg') == 'tree':
answer = answer + 1
print("Accuracy(%) grass_with_tree.jpg", answer)
answer = 0
for i in range(100):
if what_is_it('../../resources/textures/grass2.png') == 'grass':
answer = answer + 1
print("Accuracy(%) grass2.png", answer)
answer = 0
for i in range(100):
if what_is_it('../../resources/textures/grass3.png') == 'grass':
answer = answer + 1
print("Accuracy(%) grass3.png", answer)
answer = 0
for i in range(100):
if what_is_it('../../resources/textures/grass4.png') == 'grass':
answer = answer + 1
print("Accuracy(%) grass4.png", answer)
answer = 0
for i in range(100):
if what_is_it('../../resources/textures/grass1.png') == 'grass':
answer = answer + 1
print("Accuracy(%) grass1.png", answer)
answer = 0
for i in range(100):
if what_is_it('../../resources/textures/water.png') == 'water':
answer = answer + 1
print("Accuracy(%) water.png", answer)
answer = 0
for i in range(100):
if what_is_it('../../resources/textures/sand.png') == 'sand':
answer = answer + 1
print("Accuracy(%) sand.png", answer)
def what_is_it(img_path, show_img=False):
image = Image.open(img_path).convert('RGB')
if show_img:
plt.imshow(image)
plt.show()
image = SETUP_PHOTOS(image).unsqueeze(0)
model = NeuralNetwork.load_from_checkpoint('./lightning_logs/version_20/checkpoints/epoch=3-step=324.ckpt')
with torch.no_grad():
model.eval()
idx = int(model(image).argmax(dim=1))
return ID_TO_CLASS[idx]
def check_accuracy(tset):
model = NeuralNetwork.load_from_checkpoint('./lightning_logs/version_23/checkpoints/epoch=3-step=324.ckpt')
num_correct = 0
num_samples = 0
model = model.to(DEVICE)
model.eval()
with torch.no_grad():
for photo, label in tset:
photo = photo.to(DEVICE)
label = label.to(DEVICE)
scores = model(photo)
predictions = scores.argmax(dim=1)
num_correct += (predictions == label).sum()
num_samples += predictions.size(0)
print(f'Got {num_correct} / {num_samples} with accuracy {float(num_correct)/float(num_samples)*100:.2f}%')
def check_accuracy_data():
trainset = WaterSandTreeGrass('./data/train_csv_file.csv', transform=SETUP_PHOTOS)
testset = WaterSandTreeGrass('./data/test_csv_file.csv', transform=SETUP_PHOTOS)
train_loader = DataLoader(trainset, batch_size=BATCH_SIZE, shuffle=True)
test_loader = DataLoader(testset, batch_size=BATCH_SIZE)
print("Accuracy of train_set:")
check_accuracy(train_loader)
print("Accuracy of test_set:")
check_accuracy(test_loader)
#CNN = NeuralNetwork()
#common.helpers.createCSV()
#trainer = pl.Trainer(accelerator='gpu', callbacks=EarlyStopping('val_loss'), devices=1, max_epochs=NUM_EPOCHS)
#trainer = pl.Trainer(accelerator='gpu', devices=1, auto_lr_find=True, max_epochs=NUM_EPOCHS)
#trainset = WaterSandTreeGrass('./data/train_csv_file.csv', transform=SETUP_PHOTOS)
#testset = WaterSandTreeGrass('./data/test_csv_file.csv', transform=SETUP_PHOTOS)
#train_loader = DataLoader(trainset, batch_size=BATCH_SIZE, shuffle=True)
#test_loader = DataLoader(testset, batch_size=BATCH_SIZE)
#trainer.fit(CNN, train_loader, test_loader)
#trainer.tune(CNN, train_loader, test_loader)
#print(what_is_it('../../resources/textures/grass2.png', True))
#check_accuracy_data()
#check_accuracy_tiles()

View File

@ -1,27 +0,0 @@
import torch
from torch.utils.data import Dataset
import pandas as pd
from torchvision.io import read_image, ImageReadMode
from common.helpers import createCSV
from PIL import Image
class WaterSandTreeGrass(Dataset):
def __init__(self, annotations_file, transform=None):
createCSV()
self.img_labels = pd.read_csv(annotations_file)
self.transform = transform
def __len__(self):
return len(self.img_labels)
def __getitem__(self, idx):
image = Image.open(self.img_labels.iloc[idx, 0]).convert('RGB')
label = torch.tensor(int(self.img_labels.iloc[idx, 1]))
if self.transform:
image = self.transform(image)
return image, label

View File

@ -1,12 +1,10 @@
from enum import Enum from enum import Enum
import torchvision.transforms as transforms
import torch
GAME_TITLE = 'WMICraft' GAME_TITLE = 'WMICraft'
WINDOW_HEIGHT = 800 WINDOW_HEIGHT = 800
WINDOW_WIDTH = 1360 WINDOW_WIDTH = 1360
FPS_COUNT = 60 FPS_COUNT = 60
TURN_INTERVAL = 200 TURN_INTERVAL = 300
GRID_CELL_PADDING = 5 GRID_CELL_PADDING = 5
GRID_CELL_SIZE = 36 GRID_CELL_SIZE = 36
@ -65,32 +63,12 @@ ACTION = {
"go": 0, "go": 0,
} }
LEFT = 'LEFT'
RIGHT = 'RIGHT'
UP = 'UP'
DOWN = 'DOWN'
# HEALTH_BAR # HEALTH_BAR
BAR_ANIMATION_SPEED = 1 BAR_ANIMATION_SPEED = 1
BAR_WIDTH_MULTIPLIER = 0.9 # (0;1> BAR_WIDTH_MULTIPLIER = 0.9 # (0;1>
BAR_HEIGHT_MULTIPLIER = 0.1 BAR_HEIGHT_MULTIPLIER = 0.1
LEFT = 'LEFT'
#NEURAL_NETWORK RIGHT = 'RIGHT'
LEARNING_RATE = 0.000630957344480193 UP = 'UP'
BATCH_SIZE = 64 DOWN = 'DOWN'
NUM_EPOCHS = 9
DEVICE = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
print("Using ", DEVICE)
CLASSES = ['grass', 'sand', 'tree', 'water']
SETUP_PHOTOS = transforms.Compose([
transforms.ToTensor(),
transforms.Resize((36, 36)),
transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])
ID_TO_CLASS = {i: j for i, j in enumerate(CLASSES)}
CLASS_TO_ID = {value: key for key, value in ID_TO_CLASS.items()}

View File

@ -2,11 +2,6 @@ from typing import Tuple, List
import pygame import pygame
from algorithms.genetic.const import MAP_ALIASES
from common.constants import GRID_CELL_PADDING, GRID_CELL_SIZE, COLUMNS, ROWS, CLASSES, CLASS_TO_ID
import csv
import os
from common.constants import GRID_CELL_PADDING, GRID_CELL_SIZE from common.constants import GRID_CELL_PADDING, GRID_CELL_SIZE
from common.constants import ROWS, COLUMNS, LEFT, RIGHT, UP, DOWN from common.constants import ROWS, COLUMNS, LEFT, RIGHT, UP, DOWN
@ -29,44 +24,6 @@ def draw_text(text, color, surface, x, y, text_size=30, is_bold=False):
surface.blit(textobj, textrect) surface.blit(textobj, textrect)
def createCSV():
train_data_path = './data/train'
test_data_path = './data/test'
if os.path.exists(train_data_path):
train_csvfile = open('./data/train_csv_file.csv', 'w', newline="")
writer = csv.writer(train_csvfile)
writer.writerow(["filepath", "type"])
for class_name in CLASSES:
class_dir = train_data_path + "/" + class_name
for filename in os.listdir(class_dir):
f = os.path.join(class_dir, filename)
if os.path.isfile(f):
writer.writerow([f, CLASS_TO_ID[class_name]])
train_csvfile.close()
else:
print("Brak plików do uczenia")
if os.path.exists(test_data_path):
test_csvfile = open('./data/test_csv_file.csv', 'w', newline="")
writer = csv.writer(test_csvfile)
writer.writerow(["filepath", "type"])
for class_name in CLASSES:
class_dir = test_data_path + "/" + class_name
for filename in os.listdir(class_dir):
f = os.path.join(class_dir, filename)
if os.path.isfile(f):
writer.writerow([f, CLASS_TO_ID[class_name]])
test_csvfile.close()
else:
print("Brak plików do testowania")
def print_numbers(): def print_numbers():
display_surface = pygame.display.get_surface() display_surface = pygame.display.get_surface()
font = pygame.font.SysFont('Arial', 16) font = pygame.font.SysFont('Arial', 16)
@ -101,7 +58,7 @@ def castle_neighbors(map, castle_bottom_right_row, castle_bottom_right_col):
return neighbors return neighbors
def find_neighbours(grid: List[List[int]], col: int, row: int) -> List[Tuple[int, int]]: def find_neighbours(grid: List[List[str]], col: int, row: int) -> List[Tuple[int, int]]:
dr = [-1, 1, 0, 0] dr = [-1, 1, 0, 0]
dc = [0, 0, -1, 1] dc = [0, 0, -1, 1]
@ -113,7 +70,7 @@ def find_neighbours(grid: List[List[int]], col: int, row: int) -> List[Tuple[int
if rr < 0 or cc < 0: continue if rr < 0 or cc < 0: continue
if rr >= ROWS or cc >= COLUMNS: continue if rr >= ROWS or cc >= COLUMNS: continue
if grid[rr][cc] not in [MAP_ALIASES.get("GRASS"), MAP_ALIASES.get("SAND"), '.']: continue if grid[rr][cc] not in ['g', 's', '.']: continue
neighbours.append((rr, cc)) neighbours.append((rr, cc))
return neighbours return neighbours

View File

@ -34,7 +34,7 @@ class DecisionTree:
self.model = DecisionTreeClassifier(criterion='entropy') self.model = DecisionTreeClassifier(criterion='entropy')
self.model.fit(self.train_set.values, self.goals) self.model.fit(self.train_set.values, self.goals)
def predict_move(self, grid: List[List[int]], current_knight: Knight, castle: Castle, monsters: List[Monster], def predict_move(self, grid: List[List[str]], current_knight: Knight, castle: Castle, monsters: List[Monster],
opponents: List[Knight]) -> \ opponents: List[Knight]) -> \
List[Tuple[int, int]]: List[Tuple[int, int]]:
distance_to_castle = manhattan_distance(current_knight.position, castle.position) distance_to_castle = manhattan_distance(current_knight.position, castle.position)
@ -42,23 +42,22 @@ class DecisionTree:
monsters_parsed = [] monsters_parsed = []
for monster in monsters: for monster in monsters:
monsters_parsed.append((manhattan_distance(current_knight.position, monster.position), parse_hp( monsters_parsed.append((manhattan_distance(current_knight.position, monster.position), parse_hp(
monster.health_bar.current_hp))) monster.current_hp)))
opponents_parsed = [] opponents_parsed = []
for opponent in opponents: for opponent in opponents:
opponents_parsed.append( opponents_parsed.append(
(manhattan_distance(current_knight.position, opponent.position), (manhattan_distance(current_knight.position, opponent.position), parse_hp(opponent.current_hp)))
parse_hp(opponent.health_bar.current_hp)))
prediction = self.get_prediction(tower_dist=distance_to_castle, tower_hp=castle.health_bar.current_hp, prediction = self.get_prediction(tower_dist=distance_to_castle, tower_hp=castle.current_hp,
mob1_dist=monsters_parsed[0][0], mob1_hp=monsters_parsed[0][1], mob1_dist=monsters_parsed[0][0], mob1_hp=monsters_parsed[0][1],
mob2_dist=monsters_parsed[1][0], mob2_hp=monsters_parsed[1][1], mob2_dist=monsters_parsed[1][0], mob2_hp=monsters_parsed[1][1],
opp1_dist=opponents_parsed[0][0], opp1_hp=opponents_parsed[0][1], opp1_dist=opponents_parsed[0][0], opp1_hp=opponents_parsed[0][1],
opp2_dist=opponents_parsed[1][0], opp2_hp=opponents_parsed[1][1], opp2_dist=opponents_parsed[1][0], opp2_hp=opponents_parsed[1][1],
opp3_dist=opponents_parsed[2][0], opp3_hp=opponents_parsed[2][1], opp3_dist=opponents_parsed[2][0], opp3_hp=opponents_parsed[2][1],
opp4_dist=opponents_parsed[3][0], opp4_hp=opponents_parsed[3][1], opp4_dist=opponents_parsed[3][0], opp4_hp=opponents_parsed[3][1],
agent_hp=current_knight.health_bar.current_hp) agent_hp=current_knight.current_hp)
print(f'Prediction = {prediction}') print(prediction)
if prediction == 'tower': # castle... if prediction == 'tower': # castle...
return castle_neighbors(grid, castle_bottom_right_row=castle.position[0], return castle_neighbors(grid, castle_bottom_right_row=castle.position[0],
castle_bottom_right_col=castle.position[1]) castle_bottom_right_col=castle.position[1])

View File

@ -27,6 +27,7 @@ class Game:
self.screens = {'credits': Credits(self.screen, self.clock), 'options': Options(self.screen, self.clock)} self.screens = {'credits': Credits(self.screen, self.clock), 'options': Options(self.screen, self.clock)}
def main_menu(self): def main_menu(self):
menu = MainMenu(self.screen, self.clock, self.bg, menu = MainMenu(self.screen, self.clock, self.bg,
self.game, self.game,
@ -37,6 +38,7 @@ class Game:
def game(self): def game(self):
logs = Logs(self.screen) logs = Logs(self.screen)
level = Level(self.screen, logs) level = Level(self.screen, logs)
stats = Stats(self.screen)
# setup clock for rounds # setup clock for rounds
NEXT_TURN = pygame.USEREVENT + 1 NEXT_TURN = pygame.USEREVENT + 1
@ -44,8 +46,6 @@ class Game:
# create level # create level
level.create_map() level.create_map()
stats = Stats(self.screen, level.list_knights_blue, level.list_knights_red)
level.setup_stats(stats)
print_numbers_flag = False print_numbers_flag = False
running = True running = True
@ -61,7 +61,8 @@ class Game:
running = False running = False
if event.key == pygame.K_n: if event.key == pygame.K_n:
print_numbers_flag = not print_numbers_flag print_numbers_flag = not print_numbers_flag
if event.key == pygame.K_r:
stats.red_team_hp_bar.take_dmg(5)
if event.type == NEXT_TURN: # is called every 'TURN_INTERVAL' milliseconds if event.type == NEXT_TURN: # is called every 'TURN_INTERVAL' milliseconds
level.handle_turn() level.handle_turn()

View File

@ -9,6 +9,7 @@ class HealthBar:
self.rect = rect self.rect = rect
self.screen = screen self.screen = screen
self.current_hp = current_hp self.current_hp = current_hp
self.target_hp = current_hp
self.max_hp = max_hp self.max_hp = max_hp
self.x = self.rect.x self.x = self.rect.x
self.y = self.rect.y self.y = self.rect.y
@ -37,22 +38,22 @@ class HealthBar:
self.health_ratio = self.max_hp / self.width self.health_ratio = self.max_hp / self.width
def take_dmg(self, amount): def take_dmg(self, dmg_taken):
if self.current_hp - amount > 0: if self.target_hp > 0:
self.current_hp -= amount self.target_hp -= dmg_taken
elif self.current_hp - amount <= 0: elif self.target_hp < 0:
self.current_hp = 0 self.target_hp = 0
def heal(self, amount): def heal(self, amount):
if self.current_hp + amount < self.max_hp: if self.target_hp < self.max_hp:
self.current_hp += amount self.target_hp += amount
elif self.current_hp + amount >= self.max_hp: elif self.target_hp > self.max_hp:
self.current_hp = self.max_hp self.target_hp = self.max_hp
def show(self): def show(self):
pygame.Surface.fill(self.screen, BLACK, (self.x-1, self.y-1, self.width+2, self.height+2)) pygame.Surface.fill(self.screen, BLACK, (self.x-1, self.y-1, self.width+2, self.height+2))
pygame.Surface.fill(self.screen, RED, (self.x, self.y, self.width, self.height)) pygame.Surface.fill(self.screen, RED, (self.x, self.y, self.width, self.height))
pygame.Surface.fill(self.screen, GREEN, (self.x, self.y, int(self.current_hp / self.health_ratio), self.height)) pygame.Surface.fill(self.screen, GREEN, (self.x, self.y, int(self.target_hp / self.health_ratio), self.height))

View File

@ -10,7 +10,7 @@ class KnightsQueue:
def dequeue_knight(self): def dequeue_knight(self):
if self.both_teams_alive(): if self.both_teams_alive():
knight = self.queues[self.team_idx_turn].popleft() knight = self.queues[self.team_idx_turn].popleft()
if knight.health_bar.current_hp <= 0: if knight.max_hp <= 0:
return self.dequeue_knight() return self.dequeue_knight()
else: else:
self.queues[self.team_idx_turn].append(knight) self.queues[self.team_idx_turn].append(knight)

View File

@ -3,11 +3,10 @@ import random
import pygame import pygame
from algorithms.a_star import a_star, State, TURN_RIGHT, TURN_LEFT, FORWARD from algorithms.a_star import a_star, State, TURN_RIGHT, TURN_LEFT, FORWARD
from algorithms.genetic.const import MAP_ALIASES
from algorithms.genetic.map_importer_exporter import import_random_map
from common.constants import * from common.constants import *
from learning.decision_tree import DecisionTree from learning.decision_tree import DecisionTree
from logic.knights_queue import KnightsQueue from logic.knights_queue import KnightsQueue
from logic.spawner import Spawner
from models.castle import Castle from models.castle import Castle
from models.knight import Knight from models.knight import Knight
from models.monster import Monster from models.monster import Monster
@ -22,7 +21,7 @@ class Level:
# sprite group setup # sprite group setup
self.sprites = pygame.sprite.LayeredUpdates() self.sprites = pygame.sprite.LayeredUpdates()
self.map = [] self.map = [['g' for _ in range(COLUMNS)] for y in range(ROWS)]
self.list_knights_blue = [] self.list_knights_blue = []
self.list_knights_red = [] self.list_knights_red = []
@ -31,21 +30,28 @@ class Level:
self.knights_queue = None self.knights_queue = None
self.stats = None
def setup_stats(self, stats):
self.stats = stats
def add_points(self, team, points_to_add):
if self.stats is not None:
self.stats.add_points(team, points_to_add)
def create_map(self): def create_map(self):
self.map = import_random_map() self.generate_map()
self.setup_base_tiles() self.setup_base_tiles()
self.setup_objects() self.setup_objects()
self.knights_queue = KnightsQueue(self.list_knights_blue, self.list_knights_red) self.knights_queue = KnightsQueue(self.list_knights_blue, self.list_knights_red)
def generate_map(self):
spawner = Spawner(self.map)
spawner.spawn_where_possible(['w' for _ in range(NBR_OF_WATER)])
spawner.spawn_where_possible(['t' for _ in range(NBR_OF_TREES)])
spawner.spawn_where_possible(['s' for _ in range(NBR_OF_SANDS)])
spawner.spawn_in_area(['k_b' for _ in range(4)], LEFT_KNIGHTS_SPAWN_FIRST_ROW, LEFT_KNIGHTS_SPAWN_FIRST_COL,
KNIGHTS_SPAWN_WIDTH, KNIGHTS_SPAWN_HEIGHT)
spawner.spawn_in_area(['k_r' for _ in range(4)], RIGHT_KNIGHTS_SPAWN_FIRST_ROW, RIGHT_KNIGHTS_SPAWN_FIRST_COL,
KNIGHTS_SPAWN_WIDTH, KNIGHTS_SPAWN_HEIGHT)
spawner.spawn_in_area(['c'], CASTLE_SPAWN_FIRST_ROW, CASTLE_SPAWN_FIRST_COL, CASTLE_SPAWN_WIDTH,
CASTLE_SPAWN_HEIGHT, 2)
spawner.spawn_where_possible(['m' for _ in range(NBR_OF_MONSTERS)])
def setup_base_tiles(self): def setup_base_tiles(self):
textures = [] textures = []
for texture_path in TILES: for texture_path in TILES:
@ -57,15 +63,15 @@ class Level:
for col_index, col in enumerate(row): for col_index, col in enumerate(row):
# add base tiles, e.g. water, tree, grass # add base tiles, e.g. water, tree, grass
if col == MAP_ALIASES.get('WATER'): if col == "w":
texture_index = 5 texture_index = 5
texture_surface = textures[texture_index][1] texture_surface = textures[texture_index][1]
Tile((col_index, row_index), texture_surface, self.sprites, 'w') Tile((col_index, row_index), texture_surface, self.sprites, 'w')
elif col == MAP_ALIASES.get('TREE'): elif col == "t":
texture_index = 6 texture_index = 6
texture_surface = textures[texture_index][1] texture_surface = textures[texture_index][1]
Tile((col_index, row_index), texture_surface, self.sprites, 't') Tile((col_index, row_index), texture_surface, self.sprites, 't')
elif col == MAP_ALIASES.get('SAND'): elif col == "s":
texture_index = 4 texture_index = 4
texture_surface = textures[texture_index][1] texture_surface = textures[texture_index][1]
Tile((col_index, row_index), texture_surface, self.sprites) Tile((col_index, row_index), texture_surface, self.sprites)
@ -82,148 +88,37 @@ class Level:
for col_index, col in enumerate(row): for col_index, col in enumerate(row):
# add objects, e.g. knights, monsters, castle # add objects, e.g. knights, monsters, castle
if col == MAP_ALIASES.get('KNIGHT_BLUE'): if col == "k_b":
knight = Knight(self.screen, (col_index, row_index), self.sprites, "blue") knight = Knight(self.screen, (col_index, row_index), self.sprites, "blue")
self.map[row_index][col_index] = knight self.map[row_index][col_index] = knight
self.list_knights_blue.append(knight) self.list_knights_blue.append(knight)
elif col == MAP_ALIASES.get('KNIGHT_RED'): elif col == "k_r":
knight = Knight(self.screen, (col_index, row_index), self.sprites, "red") knight = Knight(self.screen, (col_index, row_index), self.sprites, "red")
self.map[row_index][col_index] = knight self.map[row_index][col_index] = knight
self.list_knights_red.append(knight) self.list_knights_red.append(knight)
elif col == MAP_ALIASES.get('MONSTER'): elif col == "m":
monster = Monster(self.screen, (col_index, row_index), self.sprites) monster = Monster(self.screen, (col_index, row_index), self.sprites)
self.map[row_index][col_index] = monster self.map[row_index][col_index] = monster
self.list_monsters.append(monster) self.list_monsters.append(monster)
elif col == MAP_ALIASES.get('CASTLE'): elif col == "c":
castle_count += 1 castle_count += 1
if castle_count == 4: if castle_count == 4:
castle = Castle(self.screen, (col_index, row_index), self.sprites) castle = Castle(self.screen, (col_index, row_index), self.sprites)
self.map[row_index][col_index] = castle self.map[row_index][col_index] = castle
self.list_castles.append(castle) self.list_castles.append(castle)
#def attack_knight(self, knights_list, positions, current_knight):
# op_pos_1 = current_knight.position[0] - 1, current_knight.position[1]
# positions.append(op_pos_1)
# op_pos_2 = current_knight.position[0], current_knight.position[1] - 1
# positions.append(op_pos_2)
# op_pos_3 = current_knight.position[0] + 1, current_knight.position[1]
# positions.append(op_pos_3)
# op_pos_4 = current_knight.position[0], current_knight.position[1] + 1
# positions.append(op_pos_4)
# for some_knight in knights_list:
# for some_position in positions:
# if (some_knight.position == some_position and some_knight.team != current_knight.team):
# some_knight.health_bar.take_dmg(current_knight.attack)
# if some_knight.health_bar.current_hp == 0:
# some_knight.kill()
# positions.clear()
def attack_knight_left(self, knights_list, current_knight):
position_left = current_knight.position[0] - 1, current_knight.position[1]
for some_knight in knights_list:
if (some_knight.position == position_left and some_knight.team != current_knight.team):
some_knight.health_bar.take_dmg(current_knight.attack)
if some_knight.health_bar.current_hp <= 0:
some_knight.kill()
self.add_points(current_knight.team, 5)
for monster in self.list_monsters:
if monster.position == position_left:
monster.health_bar.take_dmg(current_knight.attack)
if monster.health_bar.current_hp <= 0:
monster.kill()
self.add_points(current_knight.team, monster.points)
else:
current_knight.health_bar.take_dmg(monster.attack)
if current_knight.health_bar.current_hp <= 0:
current_knight.kill()
for castle in self.list_castles:
if castle.position == position_left:
castle.health_bar.take_dmg(current_knight.attack)
def attack_knight_right(self, knights_list, current_knight):
position_right = current_knight.position[0] + 1, current_knight.position[1]
for some_knight in knights_list:
if (some_knight.position == position_right and some_knight.team != current_knight.team):
some_knight.health_bar.take_dmg(current_knight.attack)
if some_knight.health_bar.current_hp == 0:
some_knight.kill()
self.add_points(current_knight.team, 5)
for monster in self.list_monsters:
if monster.position == position_right:
monster.health_bar.take_dmg(current_knight.attack)
if monster.health_bar.current_hp <= 0:
monster.kill()
self.add_points(current_knight.team, monster.points)
else:
current_knight.health_bar.take_dmg(monster.attack)
if current_knight.health_bar.current_hp <= 0:
current_knight.kill()
for castle in self.list_castles:
if castle.position == position_right:
castle.health_bar.take_dmg(current_knight.attack)
def attack_knight_up(self, knights_list, current_knight):
position_up = current_knight.position[0], current_knight.position[1] - 1
for some_knight in knights_list:
if (some_knight.position == position_up and some_knight.team != current_knight.team):
some_knight.health_bar.take_dmg(current_knight.attack)
if some_knight.health_bar.current_hp == 0:
some_knight.kill()
self.add_points(current_knight.team, 5)
for monster in self.list_monsters:
if monster.position == position_up:
monster.health_bar.take_dmg(current_knight.attack)
if monster.health_bar.current_hp <= 0:
monster.kill()
self.add_points(current_knight.team, monster.points)
else:
current_knight.health_bar.take_dmg(monster.attack)
if current_knight.health_bar.current_hp <= 0:
current_knight.kill()
for castle in self.list_castles:
if castle.position == position_up:
castle.health_bar.take_dmg(current_knight.attack)
def attack_knight_down(self, knights_list, current_knight):
position_down = current_knight.position[0], current_knight.position[1] + 1
for some_knight in knights_list:
if (some_knight.position == position_down and some_knight.team != current_knight.team):
some_knight.health_bar.take_dmg(current_knight.attack)
if some_knight.health_bar.current_hp == 0:
some_knight.kill()
self.add_points(current_knight.team, 5)
for monster in self.list_monsters:
if monster.position == position_down:
monster.health_bar.take_dmg(current_knight.attack)
if monster.health_bar.current_hp <= 0:
monster.kill()
self.add_points(current_knight.team, monster.points)
else:
current_knight.health_bar.take_dmg(monster.attack)
if current_knight.health_bar.current_hp <= 0:
current_knight.kill()
for castle in self.list_castles:
if castle.position == position_down:
castle.health_bar.take_dmg(current_knight.attack)
def handle_turn(self): def handle_turn(self):
print("next turn")
current_knight = self.knights_queue.dequeue_knight() current_knight = self.knights_queue.dequeue_knight()
knights_list = self.list_knights_red + self.list_knights_blue
print("next turn " + current_knight.team)
knight_pos_x = current_knight.position[0] knight_pos_x = current_knight.position[0]
knight_pos_y = current_knight.position[1] knight_pos_y = current_knight.position[1]
positions = []
goal_list = self.decision_tree.predict_move(grid=self.map, current_knight=current_knight, goal_list = self.decision_tree.predict_move(grid=self.map, current_knight=current_knight,
monsters=self.list_monsters, monsters=self.list_monsters,
opponents=self.list_knights_blue opponents=self.list_knights_red
if current_knight.team_alias() == 'k_r' else self.list_knights_red, if current_knight.team_alias == 'k_r' else self.list_knights_blue,
castle=self.list_castles[0]) castle=self.list_castles[0])
if (len(self.list_knights_blue) == 0 or len(self.list_knights_red) == 0):
pygame.quit()
if len(goal_list) == 0: if len(goal_list) == 0:
return return
@ -236,19 +131,6 @@ class Level:
return return
next_action = action_list.pop(0) next_action = action_list.pop(0)
#if current_knight.health_bar.current_hp != 0:
#self.attack_knight(knights_list, positions, current_knight)
if current_knight.direction.name == UP:
self.attack_knight_up(knights_list, current_knight)
elif current_knight.direction.name == DOWN:
self.attack_knight_down(knights_list, current_knight)
elif current_knight.direction.name == RIGHT:
self.attack_knight_right(knights_list, current_knight)
elif current_knight.direction.name == LEFT:
self.attack_knight_left(knights_list, current_knight)
if next_action == TURN_LEFT: if next_action == TURN_LEFT:
self.logs.enqueue_log(f'AI {current_knight.team}: Obrót w lewo.') self.logs.enqueue_log(f'AI {current_knight.team}: Obrót w lewo.')
current_knight.rotate_left() current_knight.rotate_left()
@ -257,9 +139,9 @@ class Level:
current_knight.rotate_right() current_knight.rotate_right()
elif next_action == FORWARD: elif next_action == FORWARD:
current_knight.step_forward() current_knight.step_forward()
self.map[knight_pos_y][knight_pos_x] = MAP_ALIASES.get("GRASS") self.map[knight_pos_y][knight_pos_x] = 'g'
# update knight on map # update knight on map
if current_knight.direction.name == UP: if current_knight.direction.name == UP:
self.logs.enqueue_log(f'AI {current_knight.team}: Ruch do góry.') self.logs.enqueue_log(f'AI {current_knight.team}: Ruch do góry.')
self.map[knight_pos_y - 1][knight_pos_x] = current_knight.team_alias() self.map[knight_pos_y - 1][knight_pos_x] = current_knight.team_alias()
@ -273,6 +155,19 @@ class Level:
self.logs.enqueue_log(f'AI {current_knight.team}: Ruch w lewo.') self.logs.enqueue_log(f'AI {current_knight.team}: Ruch w lewo.')
self.map[knight_pos_y][knight_pos_x - 1] = current_knight.team_alias() self.map[knight_pos_y][knight_pos_x - 1] = current_knight.team_alias()
def update_health_bars(self):
for knight in self.list_knights_blue:
knight.health_bar.update()
for knight in self.list_knights_red:
knight.health_bar.update()
for monster in self.list_monsters:
monster.health_bar.update()
for castle in self.list_castles:
castle.health_bar.update()
def update(self): def update(self):
bg_width = (GRID_CELL_PADDING + GRID_CELL_SIZE) * COLUMNS + BORDER_WIDTH bg_width = (GRID_CELL_PADDING + GRID_CELL_SIZE) * COLUMNS + BORDER_WIDTH
bg_height = (GRID_CELL_PADDING + GRID_CELL_SIZE) * ROWS + BORDER_WIDTH bg_height = (GRID_CELL_PADDING + GRID_CELL_SIZE) * ROWS + BORDER_WIDTH
@ -280,7 +175,4 @@ class Level:
# update and draw the game # update and draw the game
self.sprites.draw(self.screen) self.sprites.draw(self.screen)
self.sprites.update() self.update_health_bars() # has to be called last

View File

@ -16,7 +16,5 @@ class Castle(pygame.sprite.Sprite):
position_in_px = (parse_cord(position[0]), parse_cord(position[1])) position_in_px = (parse_cord(position[0]), parse_cord(position[1]))
self.rect = self.image.get_rect(center=position_in_px) self.rect = self.image.get_rect(center=position_in_px)
self.max_hp = 80 self.max_hp = 80
self.health_bar = HealthBar(screen, self.rect, current_hp=self.max_hp, max_hp=self.max_hp, calculate_xy=True, calculate_size=True) self.current_hp = random.randint(1, self.max_hp)
self.health_bar = HealthBar(screen, self.rect, current_hp=self.current_hp, max_hp=self.max_hp, calculate_xy=True, calculate_size=True)
def update(self):
self.health_bar.update()

View File

@ -7,11 +7,8 @@ from common.helpers import parse_cord
from logic.health_bar import HealthBar from logic.health_bar import HealthBar
def load_knight_textures(team): def load_knight_textures():
if team == "blue": random_index = random.randint(1, 4)
random_index = 3
else:
random_index = 4
states = [ states = [
pygame.image.load(f'resources/textures/knight_{random_index}_up.png').convert_alpha(), # up = 0 pygame.image.load(f'resources/textures/knight_{random_index}_up.png').convert_alpha(), # up = 0
pygame.image.load(f'resources/textures/knight_{random_index}_right.png').convert_alpha(), # right = 1 pygame.image.load(f'resources/textures/knight_{random_index}_right.png').convert_alpha(), # right = 1
@ -27,7 +24,7 @@ class Knight(pygame.sprite.Sprite):
super().__init__(group) super().__init__(group)
self.direction = Direction.DOWN self.direction = Direction.DOWN
self.states = load_knight_textures(team) self.states = load_knight_textures()
self.image = self.states[self.direction.value] self.image = self.states[self.direction.value]
self.position = position self.position = position
@ -36,35 +33,21 @@ class Knight(pygame.sprite.Sprite):
self.rect = self.image.get_rect(topleft=position_in_px) self.rect = self.image.get_rect(topleft=position_in_px)
self.team = team self.team = team
self.max_hp = random.randint(9, 13) self.max_hp = random.randint(7, 12)
self.attack = random.randint(2, 4) self.current_hp = random.randint(1, self.max_hp)
self.attack = random.randint(4, 7)
self.defense = random.randint(1, 4) self.defense = random.randint(1, 4)
self.points = 1 self.points = 1
self.health_bar = HealthBar(screen, self.rect, current_hp=self.max_hp, max_hp=self.max_hp, calculate_xy=True, calculate_size=True) self.health_bar = HealthBar(screen, self.rect, current_hp=self.current_hp, max_hp=self.max_hp, calculate_xy=True, calculate_size=True)
def rotate_left(self): def rotate_left(self):
self.direction = self.direction.left() self.direction = self.direction.left()
self.image = self.states[self.direction.value] self.image = self.states[self.direction.value]
def update(self):
self.health_bar.update()
def rotate_right(self): def rotate_right(self):
self.direction = self.direction.right() self.direction = self.direction.right()
self.image = self.states[self.direction.value] self.image = self.states[self.direction.value]
def take_dmg(self, amount):
self.health_bar.take_dmg(amount)
def heal(self, amount):
self.health_bar.heal(amount)
def get_current_hp(self):
return self.health_bar.current_hp
def get_max_hp(self):
return self.health_bar.max_hp
def step_forward(self): def step_forward(self):
if self.direction.name == 'UP': if self.direction.name == 'UP':
self.position = (self.position[0], self.position[1] - 1) self.position = (self.position[0], self.position[1] - 1)

View File

@ -22,13 +22,14 @@ class Monster(pygame.sprite.Sprite):
position_in_px = (parse_cord(position[0]), parse_cord(position[1])) position_in_px = (parse_cord(position[0]), parse_cord(position[1]))
self.rect = self.image.get_rect(topleft=position_in_px) self.rect = self.image.get_rect(topleft=position_in_px)
self.position = position self.position = position
self.max_hp = random.randrange(15, 20) self.max_hp = random.randrange(15, 25)
self.health_bar = HealthBar(screen, self.rect, current_hp=self.max_hp, max_hp=self.max_hp, self.current_hp = random.randint(1, self.max_hp)
self.health_bar = HealthBar(screen, self.rect, current_hp=self.current_hp, max_hp=self.max_hp,
calculate_xy=True, calculate_size=True) calculate_xy=True, calculate_size=True)
self.attack = random.randrange(4, 6) self.attack = random.randrange(2, 10)
if self.image == monster_images[0]: if self.image == monster_images[0]:
self.max_hp = 20 self.max_hp = 20
self.attack = 6 self.attack = 9
self.points = 10 self.points = 10
elif self.image == monster_images[1]: elif self.image == monster_images[1]:
self.max_hp = 15 self.max_hp = 15
@ -42,6 +43,3 @@ class Monster(pygame.sprite.Sprite):
self.max_hp = 7 self.max_hp = 7
self.attack = 2 self.attack = 2
self.points = 2 self.points = 2
def update(self):
self.health_bar.update()

Binary file not shown.

View File

@ -1 +0,0 @@
{"map": [[0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [0, 0, 0, 0, 3, 3, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3], [0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3], [0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 4, 0, 0, 0, 2, 0, 3], [0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2], [0, 0, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 0, 2, 2, 2, 0, 0, 0, 0, 0, 7, 2, 0], [0, 0, 0, 6, 0, 0, 0, 2, 2, 2, 0, 5, 5, 0, 2, 0, 0, 2, 2, 2, 2, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 5, 5, 0, 2, 0, 0, 0, 0, 2, 2, 1, 1, 7], [0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 1, 7], [6, 0, 0, 6, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 1, 1, 0], [6, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 3, 3, 0, 0, 0, 0, 3, 3, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 3, 0, 1, 1, 7, 0], [0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 3, 3, 1, 1, 1, 0], [0, 3, 3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 1, 1, 0, 0], [0, 3, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 4, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]}

View File

@ -1 +0,0 @@
{"map": [[0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0], [0, 3, 3, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 3, 3, 3, 0, 0, 0, 2, 0, 0, 0, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0], [0, 0, 3, 2, 2, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 2, 2, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 3, 0, 0, 0, 0, 0, 3, 3, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 6, 3, 3, 0, 0, 0, 0, 0, 3, 0, 4, 0, 3, 0, 0, 0, 0, 0, 0, 7, 0, 0], [0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 7, 7, 0, 0], [6, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 3, 7, 0, 0, 0], [0, 0, 6, 6, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0], [0, 2, 2, 2, 2, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0], [2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2, 0, 2, 0, 0, 0, 0, 0, 4, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]}

View File

@ -1 +0,0 @@
{"map": [[0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 3, 3], [0, 0, 0, 0, 2, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 3, 0], [0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 2, 0], [0, 0, 3, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 2, 0], [0, 0, 3, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0], [0, 0, 3, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0], [0, 0, 0, 6, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], [0, 6, 0, 0, 0, 0, 3, 0, 0, 0, 0, 5, 5, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 5, 5, 1, 2, 0, 0, 0, 0, 0, 0, 7, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 3, 0, 0, 0, 4, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0], [0, 0, 3, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 4], [6, 0, 0, 6, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1, 1, 0, 7, 0, 7, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 3, 2, 0, 0, 0, 0, 0, 0], [0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0], [0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]}

View File

@ -1,31 +1,6 @@
import pygame
from ui.screens.screen import Screen from ui.screens.screen import Screen
from common.colors import BLACK
from common.helpers import draw_text
class Credits(Screen): class Credits(Screen):
def __init__(self, screen, clock): def __init__(self, screen, clock):
super().__init__('credits', screen, clock) super().__init__('credits', screen, clock)
def display_screen(self):
running = True
while running:
self.screen.fill((252, 164, 12))
draw_text('Twórcy :', BLACK, self.screen, 520, 150)
draw_text('Angelika Iskra', BLACK, self.screen, 520, 250)
draw_text('Dawid Korzępa', BLACK, self.screen, 520, 300)
draw_text('Juliusz Sadowski', BLACK, self.screen, 520, 350)
draw_text('Aleksandra Muczyńska', BLACK, self.screen, 520, 400)
draw_text('Jerzy Tomaszewski', BLACK, self.screen, 520, 450)
draw_text('Mateusz Konofał', BLACK, self.screen, 520, 500)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
pygame.display.update()
self.clock.tick(60)

View File

@ -8,23 +8,13 @@ from common.helpers import draw_text
class Stats: class Stats:
def __init__(self, screen, list_knights_blue, list_knights_red): def __init__(self, screen):
self.grid = [] self.grid = []
self.list_knights_blue = list_knights_blue
self.list_knights_red = list_knights_red
self.screen = screen self.screen = screen
self.x = (GRID_CELL_PADDING + GRID_CELL_SIZE) * COLUMNS + BORDER_WIDTH + 15 self.x = (GRID_CELL_PADDING + GRID_CELL_SIZE) * COLUMNS + BORDER_WIDTH + 15
self.y = 5 self.y = 5
self.blue_team_hp_bar = HealthBar(self.screen, self.blue_team_hp_bar = HealthBar(self.screen, pygame.Rect(self.x + 30, self.y + 210, 100, 15), current_hp=50, max_hp=100)
pygame.Rect(self.x + 30, self.y + 210, 100, 15), self.red_team_hp_bar = HealthBar(self.screen, pygame.Rect(self.x + 210, self.y + 210, 100, 15), 100, 100)
current_hp=sum([knight.get_current_hp() for knight in self.list_knights_blue]),
max_hp=sum([knight.get_max_hp() for knight in self.list_knights_blue]))
self.red_team_hp_bar = HealthBar(self.screen,
pygame.Rect(self.x + 210, self.y + 210, 100, 15),
current_hp=sum([knight.get_current_hp() for knight in self.list_knights_red]),
max_hp=sum([knight.get_max_hp() for knight in self.list_knights_red]))
self.blue_team_points = 0
self.red_team_points = 0
def update(self): def update(self):
@ -43,25 +33,21 @@ class Stats:
draw_text('VS', FONT_DARK, self.screen, self.x + 150, self.y + 120, 36) draw_text('VS', FONT_DARK, self.screen, self.x + 150, self.y + 120, 36)
# HP bars # HP bars
self.red_team_hp_bar.take_dmg(self.red_team_hp_bar.current_hp - #pygame.draw.rect(screen, RED, pygame.Rect(x + 30, y + 210, 100, 15), 0, 4)
sum([knight.get_current_hp() for knight in self.list_knights_red])) #pygame.draw.rect(screen, RED, pygame.Rect(x + 210, y + 210, 100, 15), 0, 4)
self.blue_team_hp_bar.take_dmg(self.blue_team_hp_bar.current_hp -
sum([knight.get_current_hp() for knight in self.list_knights_blue]))
self.red_team_hp_bar.update() self.red_team_hp_bar.update()
self.blue_team_hp_bar.update() self.blue_team_hp_bar.update()
# texts
draw_text('Rycerze: ' + str(len(self.list_knights_blue)), FONT_DARK, self.screen, self.x + 35, self.y + 240, 18) # blue
draw_text('Rycerze: ' + str(len(self.list_knights_red)), FONT_DARK, self.screen, self.x + 215, self.y + 240, 18)
# texts
draw_text('Rycerze: 2', FONT_DARK, self.screen, self.x + 35, self.y + 240, 18)
draw_text('Fortece: 1', FONT_DARK, self.screen, self.x + 35, self.y + 270, 18)
draw_text('Rycerze: 4', FONT_DARK, self.screen, self.x + 215, self.y + 240, 18)
draw_text('Fortece: 0', FONT_DARK, self.screen, self.x + 215, self.y + 270, 18)
# points # points
pygame.draw.rect(self.screen, ORANGE, pygame.Rect(self.x, self.y + 390, 340, 3)) pygame.draw.rect(self.screen, ORANGE, pygame.Rect(self.x, self.y + 390, 340, 3))
draw_text('PUNKTY: ' + str(self.blue_team_points), FONT_DARK, self.screen, self.x + 35, self.y + 408, 18, True) draw_text('PUNKTY: 10', FONT_DARK, self.screen, self.x + 35, self.y + 408, 18, True)
draw_text('PUNKTY: ' + str(self.red_team_points), FONT_DARK, self.screen, self.x + 215, self.y + 408, 18, True) draw_text('PUNKTY: 10', FONT_DARK, self.screen, self.x + 215, self.y + 408, 18, True)
def add_points(self, team, points):
if team == "blue":
self.blue_team_points += points
else:
self.red_team_points += points