Merge pull request 'add decision tree model to trashbins, which are generated on map' (#25) from decision_tree_trashbins into master

Reviewed-on: #25
This commit is contained in:
Bartosz Wieczorek 2022-05-13 12:16:09 +02:00
commit c6cbb587cd
9 changed files with 404 additions and 141 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,109 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 9,
"id": "fac14368",
"metadata": {},
"outputs": [],
"source": [
"dataset = pandas.read_csv('/Users/mac/Desktop/tree_dataset.csv', sep=\";\")\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4d25d809",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "663eaf94",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "f3c9b416",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "bcfb233e",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "11f0c1a2",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "b1a93eb4",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "528f6ade",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "efb466fe",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "5dbe234e",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "env",
"language": "python",
"name": "env"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

126
Untitled.ipynb Normal file
View File

@ -0,0 +1,126 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 24,
"id": "fac14368",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[1]\n"
]
}
],
"source": [
"from sklearn.tree import DecisionTreeClassifier, export_text, plot_tree\n",
"dataset = pandas.read_csv('/Users/mac/Desktop/tree_dataset.csv', sep=\";\")\n",
"decisions = [\"decision\"]\n",
"attributes = [\"season\", \"trash_type\", \"mass\", \"space\", \"trash_mass\"]\n",
"\n",
"x = dataset[attributes]\n",
"y = dataset[decisions]\n",
"decision_tree = DecisionTreeClassifier()\n",
"decision_tree.fit(x.values, y.values)\n",
"decision = decision_tree.predict(\n",
" [[5, 3 , 3, 1, 2]])\n",
"print(decision)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "04bbec40",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "9c1d0193",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "8e40a924",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "b430f8b8",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "58ce5faa",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "a4b72d3d",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "b4e0aae9",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "74fb263f",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "5dbe234e",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "env",
"language": "python",
"name": "env"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -3,37 +3,26 @@ import matplotlib.pyplot as plt
import pandas import pandas
from sklearn.tree import DecisionTreeClassifier, export_text, plot_tree from sklearn.tree import DecisionTreeClassifier, export_text, plot_tree
'''
atrybuty w pliku csv muszą być integerami, wstępnie ustaliłem:
season = {"wiosna": 1, "lato": 2, "jesien":3, "zima":4}
enough_space_in_trashmaster = { "no": 1, "yes":2}
time_since_flush = [1,2,3,4,5,6,7,8,9,10]
type_of_trash = {"bio":1, "szklo":2, "plastik":3, "papier":4, "mieszane":5}
access_to_bin = { "no":1, "yes":2}
distance = [1,2,3,4,5,6,7,8,9,10]
decision = [0,1] - decyzje zostaną zmienione z tych z wagami na zero jedynkowe ze względu na pewne trudności w dalszej pracy
'''
decisions = ["decision"] decisions = ["decision"]
attributes = ["season", "enough_space_in_trashmaster", "time_since_flush", "type_of_trash", "access_to_bin", "distance"] attributes = ["season", "trash_type", "mass", "space", "trash_mass"]
# return tree made from attributes # return tree made from attributes
def tree(): def tree():
dataset = pandas.read_csv('./decision_tree/drzewo_decyzyjne.csv') dataset = pandas.read_csv('/Users/mac/Desktop/tree_dataset.csv', sep=";")
x = dataset[attributes] x = dataset[attributes]
y = dataset[decisions] y = dataset[decisions]
decision_tree = DecisionTreeClassifier() decision_tree = DecisionTreeClassifier()
decision_tree = decision_tree.fit(x, y) decision_tree = decision_tree.fit(x.values, y.values)
return decision_tree return decision_tree
# return decision made from tree and attributes # return decision made from tree and attributes
def decision(decision_tree, season, enough_space_in_trashmaster, time_since_flush, type_of_trash, access_to_bin, def decision(decision_tree, season, trash_type, mass, space, trash_mass):
distance):
decision = decision_tree.predict( decision = decision_tree.predict(
[[season, enough_space_in_trashmaster, time_since_flush, type_of_trash, access_to_bin, distance]]) [[season, trash_type , mass, space, trash_mass]])
return decision return decision

View File

@ -1,94 +1,91 @@
|--- feature_4 <= 1.50 |--- feature_2 <= 3.50
| |--- feature_5 <= 1.50 | |--- feature_4 <= 3.50
| | |--- feature_2 <= 6.50 | | |--- feature_0 <= 1.50
| | | |--- class: 0 | | | |--- class: 0
| | |--- feature_2 > 6.50 | | |--- feature_0 > 1.50
| | | |--- feature_0 <= 3.00 | | | |--- feature_3 <= 3.50
| | | | |--- class: 1 | | | | |--- feature_2 <= 2.50
| | | |--- feature_0 > 3.00
| | | | |--- class: 0
| |--- feature_5 > 1.50
| | |--- class: 0
|--- feature_4 > 1.50
| |--- feature_1 <= 1.50
| | |--- feature_0 <= 3.50
| | | |--- class: 0
| | |--- feature_0 > 3.50
| | | |--- class: 1
| |--- feature_1 > 1.50
| | |--- feature_0 <= 3.50
| | | |--- feature_0 <= 1.50
| | | | |--- feature_3 <= 2.50
| | | | | |--- class: 1 | | | | | |--- class: 1
| | | | |--- feature_3 > 2.50 | | | | |--- feature_2 > 2.50
| | | | | |--- feature_3 <= 3.50 | | | | | |--- feature_4 <= 2.50
| | | | | | |--- feature_5 <= 7.50
| | | | | | | |--- feature_2 <= 5.50
| | | | | | | | |--- class: 0
| | | | | | | |--- feature_2 > 5.50
| | | | | | | | |--- class: 1
| | | | | | |--- feature_5 > 7.50
| | | | | | | |--- class: 0
| | | | | |--- feature_3 > 3.50
| | | | | | |--- class: 1 | | | | | | |--- class: 1
| | | |--- feature_0 > 1.50 | | | | | |--- feature_4 > 2.50
| | | | |--- feature_3 <= 1.50 | | | | | | |--- class: 0
| | | | | |--- feature_5 <= 2.50 | | | |--- feature_3 > 3.50
| | | | | | |--- feature_5 <= 1.50 | | | | |--- feature_3 <= 4.50
| | | | | | | |--- class: 1 | | | | | |--- feature_1 <= 2.50
| | | | | | |--- feature_5 > 1.50 | | | | | | |--- feature_0 <= 2.50
| | | | | | | |--- feature_1 <= 1.50
| | | | | | | | |--- feature_4 <= 2.50
| | | | | | | | | |--- class: 1
| | | | | | | | |--- feature_4 > 2.50
| | | | | | | | | |--- feature_2 <= 2.00
| | | | | | | | | | |--- class: 1
| | | | | | | | | |--- feature_2 > 2.00
| | | | | | | | | | |--- class: 0
| | | | | | | |--- feature_1 > 1.50
| | | | | | | | |--- class: 0
| | | | | | |--- feature_0 > 2.50
| | | | | | | |--- feature_4 <= 2.50
| | | | | | | | |--- class: 1
| | | | | | | |--- feature_4 > 2.50
| | | | | | | | |--- feature_2 <= 2.50
| | | | | | | | | |--- class: 1
| | | | | | | | |--- feature_2 > 2.50
| | | | | | | | | |--- class: 0
| | | | | |--- feature_1 > 2.50
| | | | | | |--- feature_0 <= 3.50
| | | | | | | |--- class: 0
| | | | | | |--- feature_0 > 3.50
| | | | | | | |--- feature_1 <= 3.50
| | | | | | | | |--- feature_2 <= 2.50
| | | | | | | | | |--- class: 1
| | | | | | | | |--- feature_2 > 2.50
| | | | | | | | | |--- feature_4 <= 2.00
| | | | | | | | | | |--- class: 1
| | | | | | | | | |--- feature_4 > 2.00
| | | | | | | | | | |--- class: 0
| | | | | | | |--- feature_1 > 3.50
| | | | | | | | |--- class: 0
| | | | |--- feature_3 > 4.50
| | | | | |--- class: 0
| |--- feature_4 > 3.50
| | |--- feature_2 <= 1.50
| | | |--- feature_4 <= 4.50
| | | | |--- feature_3 <= 3.50
| | | | | |--- feature_0 <= 1.50
| | | | | | |--- class: 0
| | | | | |--- feature_0 > 1.50
| | | | | | |--- class: 1
| | | | |--- feature_3 > 3.50
| | | | | |--- feature_1 <= 2.50
| | | | | | |--- feature_3 <= 4.50
| | | | | | | |--- feature_0 <= 2.50 | | | | | | | |--- feature_0 <= 2.50
| | | | | | | | |--- class: 0 | | | | | | | | |--- class: 0
| | | | | | | |--- feature_0 > 2.50 | | | | | | | |--- feature_0 > 2.50
| | | | | | | | |--- class: 1 | | | | | | | | |--- class: 1
| | | | | |--- feature_5 > 2.50 | | | | | | |--- feature_3 > 4.50
| | | | | | |--- class: 1
| | | | |--- feature_3 > 1.50
| | | | | |--- feature_2 <= 3.50
| | | | | | |--- feature_0 <= 2.50
| | | | | | | |--- feature_5 <= 2.00
| | | | | | | | |--- class: 1
| | | | | | | |--- feature_5 > 2.00
| | | | | | | | |--- feature_5 <= 4.00
| | | | | | | | | |--- class: 0
| | | | | | | | |--- feature_5 > 4.00
| | | | | | | | | |--- feature_3 <= 2.50
| | | | | | | | | | |--- feature_5 <= 7.00
| | | | | | | | | | | |--- class: 0
| | | | | | | | | | |--- feature_5 > 7.00
| | | | | | | | | | | |--- class: 1
| | | | | | | | | |--- feature_3 > 2.50
| | | | | | | | | | |--- class: 1
| | | | | | |--- feature_0 > 2.50
| | | | | | | |--- class: 1
| | | | | |--- feature_2 > 3.50
| | | | | | |--- feature_5 <= 1.50
| | | | | | | |--- class: 0 | | | | | | | |--- class: 0
| | | | | | |--- feature_5 > 1.50 | | | | | |--- feature_1 > 2.50
| | | | | | | |--- feature_3 <= 2.50 | | | | | | |--- class: 0
| | | | | | | | |--- feature_5 <= 5.00 | | | |--- feature_4 > 4.50
| | | | | | | | | |--- class: 1 | | | | |--- class: 0
| | | | | | | | |--- feature_5 > 5.00 | | |--- feature_2 > 1.50
| | | | | | | | | |--- class: 0 | | | |--- class: 0
| | | | | | | |--- feature_3 > 2.50 |--- feature_2 > 3.50
| | | | | | | | |--- feature_5 <= 5.50 | |--- feature_1 <= 1.50
| | | | | | | | | |--- feature_0 <= 2.50 | | |--- feature_4 <= 1.50
| | | | | | | | | | |--- feature_2 <= 4.50 | | | |--- feature_2 <= 4.50
| | | | | | | | | | | |--- class: 0 | | | | |--- feature_3 <= 4.50
| | | | | | | | | | |--- feature_2 > 4.50 | | | | | |--- feature_0 <= 1.50
| | | | | | | | | | | |--- class: 0 | | | | | | |--- class: 0
| | | | | | | | | |--- feature_0 > 2.50 | | | | | |--- feature_0 > 1.50
| | | | | | | | | | |--- feature_2 <= 4.50 | | | | | | |--- class: 1
| | | | | | | | | | | |--- class: 0 | | | | |--- feature_3 > 4.50
| | | | | | | | | | |--- feature_2 > 4.50 | | | | | |--- class: 0
| | | | | | | | | | | |--- truncated branch of depth 2 | | | |--- feature_2 > 4.50
| | | | | | | | |--- feature_5 > 5.50 | | | | |--- class: 0
| | | | | | | | | |--- feature_5 <= 6.50 | | |--- feature_4 > 1.50
| | | | | | | | | | |--- class: 1 | | | |--- class: 0
| | | | | | | | | |--- feature_5 > 6.50 | |--- feature_1 > 1.50
| | | | | | | | | | |--- feature_2 <= 8.50 | | |--- class: 0
| | | | | | | | | | | |--- truncated branch of depth 3
| | | | | | | | | | |--- feature_2 > 8.50
| | | | | | | | | | | |--- truncated branch of depth 4
| | |--- feature_0 > 3.50
| | | |--- class: 1

Binary file not shown.

View File

@ -1,23 +1,23 @@
import pygame as pg import pygame as pg
from enum import Enum from enum import Enum
from random import randrange
from map.tile import Tile from map.tile import Tile
class Waste_Type(Enum):
BIO = 0
GLASS = 1
PLASTIC = 2
PAPER = 3
MIX = 4
def __int__(self):
return self.value
class Trashbin(Tile): class Trashbin(Tile):
def __init__(self, img, x, y, width, height, waste_type: Waste_Type): def __init__(self, img, x, y, width, height, waste_type):
super().__init__(img, x, y, width, height) super().__init__(img, x, y, width, height)
# dis_dump dis_trash mass space trash_mass trash_space
self.x = x
self.y = y
self.waste_type = waste_type self.season = randrange(4)
self.days_after_pickup = 0 self.trash_type = randrange(5)
self.max_capacity = 100 self.mass = randrange(5)
self.used_capacity = 0 self.space = randrange(5)
self.access = True self.trash_mass = randrange(5)
def get_coords(self):
return (self.x, self.y)
def get_attributes(self):
return (self.season, self.trash_type, self.mass, self.space, self.trash_mass)

77
main.py
View File

@ -13,17 +13,22 @@ from path_search_algorthms import a_star, a_star_utils
from decision_tree import decisionTree from decision_tree import decisionTree
from game_objects import aiPlayer from game_objects import aiPlayer
import itertools
def printTree(): def getTree():
tree = decisionTree.tree() tree = decisionTree.tree()
decisionTree.tree_as_txt(tree) decisionTree.tree_as_txt(tree)
decisionTree.tree_to_png(tree) # decisionTree.tree_to_png(tree)
decisionTree.tree_to_structure(tree) decisionTree.tree_to_structure(tree)
drzewo = decisionTree.tree_from_structure('./decision_tree/tree_model') drzewo = decisionTree.tree_from_structure('./decision_tree/tree_model')
print("Dla losowych danych predykcja czy wziąć kosz to: ") # print("Dla losowych danych predykcja czy wziąć kosz to: ")
dec = decisionTree.decision(drzewo, 4, 2, 7, 4, 2, 3) # dec = decisionTree.decision(drzewo, *(4,1,1,1))
print(dec) # print('---')
# print(f"decision is{dec}")
# print('---')
return drzewo
class Game(): class Game():
@ -31,6 +36,7 @@ class Game():
def __init__(self): def __init__(self):
pg.init() pg.init()
self.clock = pg.time.Clock() self.clock = pg.time.Clock()
self.dt = self.clock.tick(FPS) / 333.0
self.screen = pg.display.set_mode((WIDTH, HEIGHT)) self.screen = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption("Trashmaster") pg.display.set_caption("Trashmaster")
self.load_data() self.load_data()
@ -38,8 +44,17 @@ class Game():
# because dont work without data.txt # because dont work without data.txt
# self.init_bfs() # self.init_bfs()
# self.init_a_star() # self.init_a_star()
self.t = aiPlayer.aiPlayer(self.player, game=self)
self.dt = self.clock.tick(FPS) / 1000.0
def get_actions_by_coords(self,x,y):
pos = (x,y)
offset_x, offset_y = self.camera.offset()
clicked_coords = [math.floor(pos[0] / TILESIZE) - offset_x, math.floor(pos[1] / TILESIZE) - offset_y]
actions = a_star.search_path(math.floor(self.player.pos[0] / TILESIZE),
math.floor(self.player.pos[1] / TILESIZE), self.player.rotation(),
clicked_coords[0], clicked_coords[1], self.mapArray)
return actions
def init_game(self): def init_game(self):
# initialize all variables and do all the setup for a new game # initialize all variables and do all the setup for a new game
@ -47,16 +62,15 @@ class Game():
# sprite groups and map array for calculations # sprite groups and map array for calculations
(self.roadTiles, self.wallTiles, self.trashbinTiles), self.mapArray = map.get_tiles() (self.roadTiles, self.wallTiles, self.trashbinTiles), self.mapArray = map.get_tiles()
self.agentSprites = pg.sprite.Group() self.agentSprites = pg.sprite.Group()
# player obj # player obj
self.player = Player(self, 32, 32) self.player = Player(self, 32, 32)
# camera obj # camera obj
self.camera = map_utils.Camera(MAP_WIDTH_PX, MAP_HEIGHT_PX) self.camera = map_utils.Camera(MAP_WIDTH_PX, MAP_HEIGHT_PX)
# other # other
self.debug_mode = False self.debug_mode = False
def init_bfs(self): def init_bfs(self):
start_node = (0, 0) start_node = (0, 0)
target_node = (18, 18) target_node = (18, 18)
@ -81,6 +95,38 @@ class Game():
path = a_star.search_path(start_x, start_y, target_x, target_y, self.mapArray) path = a_star.search_path(start_x, start_y, target_x, target_y, self.mapArray)
print(path) print(path)
def init_decision_tree(self):
# logika pracy z drzewem
self.positive_decision = []
self.negative_decision = []
self.positive_actions = []
self.negative_actions = []
for i in self.trashbinTiles:
atrrs_container = i.get_attributes()
x, y = i.get_coords()
dec = decisionTree.decision(getTree(), *atrrs_container)
if dec[0] == 1:
self.positive_decision.append(i)
self.positive_actions.append(self.get_actions_by_coords(x, y))
else:
self.negative_decision.append(i)
self.negative_actions.append(i)
# j = 0
# for i in self.positive_actions:
# print(f"step {j} actions is : {i}")
# j+=1
# vec = pg.math.Vector2
# for i in self.positive_actions:
# self.t.startAiController(i)
# self.player.pos = vec(32, 32)
self.t.startAiController(self.positive_actions[0])
def load_data(self): def load_data(self):
game_folder = path.dirname(__file__) game_folder = path.dirname(__file__)
img_folder = path.join(game_folder, 'resources/textures') img_folder = path.join(game_folder, 'resources/textures')
@ -91,7 +137,7 @@ class Game():
def run(self): def run(self):
# game loop - set self.playing = False to end the game # game loop - set self.playing = False to end the game
self.playing = True self.playing = True
self.init_decision_tree()
while self.playing: while self.playing:
self.dt = self.clock.tick(FPS) / 1000.0 self.dt = self.clock.tick(FPS) / 1000.0
self.events() self.events()
@ -142,24 +188,17 @@ class Game():
actions = a_star.search_path(math.floor(self.player.pos[0] / TILESIZE), actions = a_star.search_path(math.floor(self.player.pos[0] / TILESIZE),
math.floor(self.player.pos[1] / TILESIZE), self.player.rotation(), math.floor(self.player.pos[1] / TILESIZE), self.player.rotation(),
clicked_coords[0], clicked_coords[1], self.mapArray) clicked_coords[0], clicked_coords[1], self.mapArray)
print(actions) # print(actions)
if (actions != None): if (actions != None):
t = aiPlayer.aiPlayer(self.player, game=self) self.t.startAiController(actions)
t.startAiController(actions)
def show_start_screen(self):
pass
def show_go_screen(self):
pass
# create the game object # create the game object
if __name__ == "__main__": if __name__ == "__main__":
g = Game() g = Game()
g.show_start_screen()
printTree()
g.run() g.run()
g.show_go_screen() g.show_go_screen()

View File

@ -21,13 +21,15 @@ def generate_map():
map[y][x] = 1 map[y][x] = 1
# generowanie smietnikow # generowanie smietnikow
for i in range(0, 5): for i in range(0, 10):
x = random.randint(0, MAP_WIDTH-1) x = random.randint(0, MAP_WIDTH-1)
y = random.randint(0, MAP_HEIGHT-1) y = random.randint(0, MAP_HEIGHT-1)
map[y][x] = 2 map[y][x] = 2
return map return map
trashbins =[]
# tworzenie grup sprite'ow # tworzenie grup sprite'ow
def get_sprites(map, pattern): def get_sprites(map, pattern):
roadTiles = pg.sprite.Group() roadTiles = pg.sprite.Group()
@ -54,6 +56,7 @@ def get_sprites(map, pattern):
trashbin = Trashbin(trashbin_pattern[trashbinId], offsetX, offsetY, 32, 30, trashbinId) trashbin = Trashbin(trashbin_pattern[trashbinId], offsetX, offsetY, 32, 30, trashbinId)
roadTiles.add(tile) roadTiles.add(tile)
trashbinTiles.add(trashbin) trashbinTiles.add(trashbin)
trashbins.append(trashbin)
return roadTiles, wallTiles, trashbinTiles return roadTiles, wallTiles, trashbinTiles