import os import random import time from tkinter import * import pandas as pd from bin.Classess.Field import Field from bin.Classess.Mine import Mine from bin.Classess.Travel import Travel from bin.Classess.Player import Player from bin.Classess.NeuralNetwork import NeuralNetwork import bin.Classess.Node as nd import bin.Classess.Travel as tr from resources.Globals import * from bin.Classess.DecisionTree import DecisionTree # Creating objects player = Player() field = Field() travel = Travel() decision_tree = DecisionTree() neural_network = NeuralNetwork() # Globals fringe = [] explored = [] action_list = [] images_coord = [] label = None def Arrow(direction): image = "" if direction == "north": image = player.arrow_north_image elif direction == "south": image = player.arrow_south_image elif direction == "west": image = player.arrow_west_image elif direction == "east": image = player.arrow_east_image field.small_field_canvas.itemconfig(player.image_canvas_id, image=image) # Putting images def Fill(bool): global images_coord if bool: field.PuttingSmallImages() travel.points_coord.append(field.small_field_canvas.coords(field.canvas_small_images[0])) travel.points_coord.extend(field.mines_coord) for i in range(0, len(travel.points_coord)): travel.points_map[i + 1] = travel.points_coord[i] print(travel.points_map) for i in range(0, len(field.canvas_small_images)): images_coord.append(field.small_field_canvas.coords(field.canvas_small_images[i])) nd.init_data(images_coord, field.cell_expense) DrawingLargeImage() def DrawingLargeImage(): large_img_name = field.large_image_array[player.current_array_y][player.current_array_x] # ToDo change positions? field.PuttingLargeImage(large_img_name) def NextDirection(action): # Define next direction current_direction = player.direction t = -1 for i in range(4): if player.directions[i] == current_direction: t = i break # Write next direction to Player if action == "Right": player.direction = player.directions[(t + 1) % 4] elif action == "Left": player.direction = player.directions[(t - 1) % 4] return player.direction def MovingForward(): if player.direction == "east" and field.small_field_canvas.coords(player.image_canvas_id)[ 0] + player.step < FRAME_WIDTH: field.small_field_canvas.move(player.image_canvas_id, player.step, 0) elif player.direction == "west" and field.small_field_canvas.coords(player.image_canvas_id)[0] > player.x_start: field.small_field_canvas.move(player.image_canvas_id, -player.step, 0) elif player.direction == "north" and field.small_field_canvas.coords(player.image_canvas_id)[1] > player.y_start: field.small_field_canvas.move(player.image_canvas_id, 0, -player.step) elif player.direction == "south" and field.small_field_canvas.coords(player.image_canvas_id)[ 1] + player.step < FRAME_HEIGHT: field.small_field_canvas.move(player.image_canvas_id, 0, player.step) def Moving(action): # Moving if action == "Right": # player.MovingRight() field.Moving() Fill(False) next_direction = NextDirection(action) Arrow(next_direction) elif action == "Left": # player.MovingLeft() field.Moving() Fill(False) next_direction = NextDirection(action) Arrow(next_direction) elif action == "Up": player.Moving() field.Moving() Fill(False) MovingForward() Arrow(player.direction) def ImagesInArray(images_array, array, paths_array, switch): # Filling array from directory row = column = 0 for i in range(len(images_array)): is_done = False while not is_done: if array[row][column] == 0: array[row][column] = images_array[i] if switch: field.large_image_array_filepath[row][column] = paths_array[i] is_done = True else: column += 1 if column == 10: column = 0 row += 1 if row == 10: break column += 1 if column == 10: column = 0 row += 1 if row == 10: break # for el in images_array: # is_done = False # while not is_done: # if array[row][column] == 0: # array[row][column] = el # is_done = True # else: # column += 1 # if column == 10: # column = 0 # row += 1 # if row == 10: # break # # column += 1 # if column == 10: # column = 0 # row += 1 # if row == 10: # break def CellDesignation(array, color): for element in array: if element[0] == 0: element[0] = player.current_x element[1] = player.current_y element[2] = color break def Action(action): if action in ["Right", "Left", "Up", "space"]: Moving(action) # elif action in ["1", "2"]: # if action == "1": # CellDesignation(field.state_of_cell_array, "red") # else: # CellDesignation(field.state_of_cell_array, "green") # Modified by Artem to search in the status area def create_action_list(states, index): global fringe global action_list if index == 0: action_list.reverse() return True action_list.append(fringe[index].action) state_parent = [fringe[index].parent[0], fringe[index].parent[1]] create_action_list(states, states.index(state_parent)) def MakeDecision(): if player.current_array_x != 0 or player.current_array_y != 0: mine = field.state_of_cell_array[player.current_array_y][player.current_array_x] # print(field.state_of_cell_array) # print(mine) attributes_dict = {'known': [mine.known], 'power': [mine.power], 'new': [mine.new], 'location': [mine.location], 'stable': [mine.stable], 'chain_reaction': [mine.chain_reaction]} attributes = f'{mine.known}; {mine.power}; {mine.new}; {mine.location}; {mine.stable}; {mine.chain_reaction}' global label_text label_text += attributes + '\n' global label label.config(text=label_text) field.win.update() data_frame = pd.DataFrame.from_dict(attributes_dict) predict = decision_tree.classifier.predict(data_frame) return predict def MarkMine(prediction): if prediction == 0: DrawFlag(field.flag_green_img) if prediction == 1: DrawFlag(field.flag_yellow_img) if prediction == 2: DrawFlag(field.flag_red_img) if prediction == 3: DrawFlag(field.flag_bleu_img) field.win.update() def ChangeChainReactionParameter(prediction, source_x, source_y, x, y): if prediction == 0: print(f"x: {source_x}; y: {source_y}") print(f'state of cell: {field.state_of_cell_array[source_x][source_y]}') print(f'img path: {field.large_image_array_filepath}') field.state_of_cell_array[source_x][source_y].chain_reaction = 1 field.state_of_cell_array[x][y] = "House" def CheckIfItIsHouse(x, y): print('Pre prediction') print(f"x: {x}; y: {y}") print(f'image path: {field.large_image_array_filepath[x][y]}') print(field.large_image_array_filepath) print(f'state of cell: {field.state_of_cell_array[x][y]}') print(field.state_of_cell_array) prediction = NeuralNetwork.Prediction(neural_network, x, y, field) print(f'Prediction: {prediction}') return prediction def CheckForHouses(): if player.current_array_x > 0 and field.state_of_cell_array[player.current_array_x - 1][player.current_array_y] == "None": prediction = CheckIfItIsHouse(player.current_array_x - 1, player.current_array_y) ChangeChainReactionParameter(prediction, player.current_array_x, player.current_array_y, player.current_array_x - 1, player.current_array_y) if player.current_array_x < 9 and field.state_of_cell_array[player.current_array_x + 1][player.current_array_y] == "None": prediction = CheckIfItIsHouse(player.current_array_x + 1, player.current_array_y) ChangeChainReactionParameter(prediction, player.current_array_x, player.current_array_y, player.current_array_x + 1, player.current_array_y) if player.current_array_y > 0 and field.state_of_cell_array[player.current_array_x][player.current_array_y - 1] == "None": prediction = CheckIfItIsHouse(player.current_array_x, player.current_array_y - 1) ChangeChainReactionParameter(prediction, player.current_array_x, player.current_array_y, player.current_array_x, player.current_array_y - 1) if player.current_array_y < 9 and field.state_of_cell_array[player.current_array_x][player.current_array_y + 1] == "None": prediction = CheckIfItIsHouse(player.current_array_x, player.current_array_y + 1) ChangeChainReactionParameter(prediction, player.current_array_x, player.current_array_y, player.current_array_x, player.current_array_y + 1) def MouseClickEvent(track): global fringe global explored global action_list print("The best individual is: {} {}".format(track[1], track[0])) for point in range(0, len(track[1]) + 1): start_position = field.small_field_canvas.coords(player.image_canvas_id) if point == len(track[1]): end_position = travel.points_map[1] else: end_position = travel.points_map[track[1][point]] node = nd.Node() if len(fringe) == 0: node.state.coord = start_position node.state.direction = "east" else: states = [] for k in range(0, len(fringe)): new_state = fringe[k].state.coord states.append(new_state) start_node = fringe[-1] node.state.coord = start_node.state.coord node.state.direction = start_node.state.direction fringe.clear() explored.clear() action_list.clear() fringe = nd.graph_search_A(fringe, explored, node.state, end_position) states = [] goal_all = [] for i in range(0, len(fringe)): new_state = [fringe[i].state.coord, fringe[i].state.direction] states.append(new_state) if end_position[0] == fringe[i].state.coord[0] and end_position[1] == fringe[i].state.coord[1]: goal_all.append(fringe[i]) elem_min = goal_all[0] for i in range(1, len(goal_all)): if elem_min.priority > goal_all[i].priority: elem_min = goal_all[i] index = fringe.index(elem_min) fringe = fringe[:index + 1] create_action_list(states, -1) # Start moving AutoMove() # Check if there are houses nearby CheckForHouses() # Decision by tree prediction = MakeDecision() # Draw the right flag MarkMine(prediction) time.sleep(SLEEP_AFTER_CHECK_MINE) # Check in which locations is mine def CheckLocation(x, y): # Add x + y like strings that create xy number temp_x = str(x) temp_y = str(y) position_str = temp_x + temp_y position = int(position_str) color_number = -1 if field.cell_expense[position] == standard_cell_cost: color_number = 0 elif field.cell_expense[position] == sand_cell_cost: color_number = 1 elif field.cell_expense[position] == water_cell_cost: color_number = 2 elif field.cell_expense[position] == swamp_cell_cost: color_number = 3 return color_number # Add mines on the field and to arrays def PutMines(mines_array): counter = 0 while counter < AMOUNT_OF_MINES: x = random.randint(0, 9) y = random.randint(0, 9) is_equal = False for mine in mines_array: if mine.array_x == x and mine.array_y == y: is_equal = True if not is_equal: if x == 0 and y == 0: continue else: known = random.randint(0, 1) power = random.randint(1, 10) new = random.randint(0, 1) location = CheckLocation(x, y) stable = random.randint(0, 1) mine = Mine(x, y, known, power, new, location, stable) mines_array.append(mine) # Add mine to array at the right position field.state_of_cell_array[x][y] = mine field.field_state_array[x][y] = True counter += 1 def MinesInArrays(mines_array, directory, imgs_array, bool_mines_coord): counter = 0 temp_array = [] if directory == "../../files/small_mines_images": for file in os.listdir(directory): if counter < AMOUNT_OF_MINES: image_name = file image_path = f"{directory}/{image_name}" image = PhotoImage(master=field.small_field_canvas, file=image_path) temp_array.append(image) counter += 1 for i in range(AMOUNT_OF_MINES): mines_array[i].small_img = temp_array[i] # Add images in image array imgs_array[mines_array[i].array_x][mines_array[i].array_y] = temp_array[i] elif directory == "../../files/large_mines_images": for file in os.listdir(directory): if counter < AMOUNT_OF_MINES: image_name = file image_path = f"{directory}/{image_name}" image = PhotoImage(master=field.large_image_canvas, file=image_path) temp_array.append(image) counter += 1 for i in range(AMOUNT_OF_MINES): mines_array[i].large_img = temp_array[i] # Add images in image array imgs_array[mines_array[i].array_x][mines_array[i].array_y] = temp_array[i] if bool_mines_coord: for i in range(len(mines_array)): field.mines_coord.append([mines_array[i].array_x, mines_array[i].array_y]) def DrawFlag(image): field.small_field_canvas.create_image(player.current_x, player.current_y, anchor=NW, image=image) # def IsItMine(): # visited = 0 # 0 - not mine; 1 - on this mine for the first time; 2 - already been on this mine # # # Checks if the player is on the mine # for i in field.mines_coord: # if i[0] == player.current_x and i[1] == player.current_y: # visited = 1 # # Checks if the player has already been on this mine # for y in field.visited_mines: # if y[0] == player.current_x and y[1] == player.current_y: # visited = 2 # if visited == 1: # DrawFlag() def AutoMove(): for action in action_list: # Program wait for better illustration time.sleep(DELAY_TIME) # Move once Action(action) # Check if player on mine and if yes, draw flag # IsItMine() # Update main window field.win.update() # Draws rectangles that indicate type of cells def DrawRectangle(): x = 4 y = 4 color = None # Chose color for rectangle for i in range(len(field.cell_expense)): if field.cell_expense[i] == standard_cell_cost: color = "None" elif field.cell_expense[i] == sand_cell_cost: color = "yellow" elif field.cell_expense[i] == water_cell_cost: color = "dodger blue" elif field.cell_expense[i] == swamp_cell_cost: color = "green4" if color != "None": field.small_field_canvas.create_rectangle(x, y, x + IMAGE_SIZE + 2, y + IMAGE_SIZE + 2, width=2, outline=color) x += player.step if x + IMAGE_SIZE + 2 > field.width: x = 4 y += player.step def AddCostCellsToArray(amount, cost): counter = 0 while counter < amount: r = random.randint(0, 99) if field.cell_expense[r] == 0: field.cell_expense[r] = cost counter += 1 def CostingOfCells(): AddCostCellsToArray(amount_of_sand_cells, sand_cell_cost) AddCostCellsToArray(amount_of_water_cells, water_cell_cost) AddCostCellsToArray(amount_of_swamp_cells, swamp_cell_cost) AddCostCellsToArray( field.rows * field.columns - (amount_of_sand_cells + amount_of_water_cells + amount_of_swamp_cells), standard_cell_cost) # Draw rectangles DrawRectangle() def click_button(): btn.destroy() global label label = Label(field.win, text="Wait...\nAI conquers the world...", fg='black', font="20", bg='gray') label.place(x=10, y=560) field.win.update() track = tr.genetic_algorithm(travel.points_map) track[1].remove(1) label.config(text=track[1]) field.win.update() MouseClickEvent(track) # Check if there mines near and if, mark it def CheckForMinesAndHousesNear(x, y): if x > 0: if field.state_of_cell_array[x - 1][y] != "None": # Mark by chain reaction current mine field.state_of_cell_array[x][y].chain_reaction = 1 # Mark by chain reaction mine that near field.state_of_cell_array[x - 1][y].chain_reaction = 1 if x < 9: if field.state_of_cell_array[x + 1][y] != "None": # Mark by chain reaction current mine field.state_of_cell_array[x][y].chain_reaction = 1 # Mark by chain reaction mine that near field.state_of_cell_array[x + 1][y].chain_reaction = 1 if y > 0: if field.state_of_cell_array[x][y - 1] != "None": # Mark by chain reaction current mine field.state_of_cell_array[x][y].chain_reaction = 1 # Mark by chain reaction mine that near field.state_of_cell_array[x][y - 1].chain_reaction = 1 if y < 9: if field.state_of_cell_array[x][y + 1] != "None": # Mark by chain reaction current mine field.state_of_cell_array[x][y].chain_reaction = 1 # Mark by chain reaction mine that near field.state_of_cell_array[x][y + 1].chain_reaction = 1 def CheckForChainReaction(): for x in range(field.columns): for y in range(field.rows): if field.state_of_cell_array[x][y] != "None": CheckForMinesAndHousesNear(x, y) def LoadAndMixImages(directory_small_images, directory_large_images): small_images_array = [] large_images_array = [] large_image_array_filepath = [] for filename in os.listdir(directory_small_images): image_path = f"{directory_small_images}/{filename}" image = PhotoImage(master=field.small_field_canvas, file=image_path) small_images_array.append(image) for filename in os.listdir(directory_large_images): image_path = f"{directory_large_images}/{filename}" image = PhotoImage(master=field.large_image_canvas, file=image_path) large_images_array.append(image) large_image_array_filepath.append(f'{directory_large_images}/{filename}') zip_array = list(zip(small_images_array, large_images_array, large_image_array_filepath)) random.shuffle(zip_array) small_images_array, large_images_array, large_image_array_filepath = zip(*zip_array) return small_images_array, large_images_array, large_image_array_filepath def HousesImagesInArray(images_array, array_for_images, array_of_paths, is_large_images): i = 0 while i < AMOUNT_OF_HOUSES: x = random.randint(0, 9) y = random.randint(0, 9) if array_for_images[x][y] == 0: array_for_images[x][y] = images_array[i] if is_large_images: field.large_image_array_filepath[x][y] = array_of_paths[i] i += 1 def funct(small_images_of_houses_array, large_images_of_houses_array, large_image_array_filepath): i = 0 while i < AMOUNT_OF_HOUSES: x = random.randint(0, 9) y = random.randint(0, 9) if field.small_image_array[x][y] == 0 and field.large_image_array[x][y] == 0: field.small_image_array[x][y] = small_images_of_houses_array[i] field.large_image_array[x][y] = large_images_of_houses_array[i] field.large_image_array_filepath[x][y] = large_image_array_filepath i += 1 def LoadImages(directory): array = [] for filename in os.listdir(directory): image_path = f"{directory}/{filename}" image = PhotoImage(master=field.large_image_canvas, file=image_path) array.append(image) return array def LoadImages_2(directory): array = [] for filename in os.listdir(directory): image_path = f"{directory}/{filename}" image = PhotoImage(master=field.small_field_canvas, file=image_path) array.append(image) return array def LoadPath(directory): array = [] for filename in os.listdir(directory): array.append(f'{directory}/{filename}') return array def LoadData(small_directory, large_directory): small_array = [] large_array = [] path_array = [] for filename in sorted(os.listdir(small_directory)): image_path = f'{small_directory}/{filename}' image = PhotoImage(master=field.small_field_canvas, file=image_path) small_array.append(image) for filename in sorted(os.listdir(large_directory)): image_path = f'{large_directory}/{filename}' image = PhotoImage(master=field.large_image_canvas, file=image_path) large_array.append(image) path_array.append(f'{large_directory}/{filename}') return small_array, large_array, path_array def main(): # Creating the main window of an application win_size = f'{WINDOW_X}x{WINDOW_Y}' field.win.title("Sapper") field.win.configure(bg='gray') field.win.geometry(win_size) print(f'Amount of mines: {AMOUNT_OF_MINES}') print(f'Amount of houses: {AMOUNT_OF_HOUSES}') global btn btn = Button(field.win, text="Search for mines", # текст кнопки background="#555", # фоновый цвет кнопки foreground="#ccc", # цвет текста padx="20", # отступ от границ до содержимого по горизонтали pady="8", # отступ от границ до содержимого по вертикали font="24", # высота шрифта command=click_button ) btn.place(x=10, y=560) # Create array with mines objects mines_array = [] CostingOfCells() # Put mines on coordinates PutMines(mines_array) # Add images of mines in arrays MinesInArrays(mines_array, "../../files/small_mines_images", field.small_image_array, True) MinesInArrays(mines_array, "../../files/large_mines_images", field.large_image_array, False) # small_images_of_houses_array, large_images_of_houses_array, large_image_array_filepath = LoadAndMixImages( # "../../files/small_images_houses", # "../../files/large_images_houses") # small_images_of_houses_array, large_images_of_houses_array, large_image_array_filepath = LoadImages("../../files/small_images_houses", "../../files/large_images_houses") # small_images_of_houses_array = LoadImages("../../files/small_images_houses") # large_images_of_houses_array = LoadImages_2("../../files/large_images_houses") # large_image_array_filepath = LoadPath("../../files/large_images_houses") small_images_of_houses_array, large_images_of_houses_array, large_image_array_filepath = LoadData("../../files/small_images_houses", "../../files/large_images_houses") HousesImagesInArray(small_images_of_houses_array, field.small_image_array, [], False) HousesImagesInArray(large_images_of_houses_array, field.large_image_array, large_image_array_filepath, True) # funct(small_images_of_houses_array, large_images_of_houses_array, large_image_array_filepath) # First check only for mines CheckForChainReaction() small_directory = "../../files/small_images" large_directory = "../../files/large_images" # small_images_array, large_images_array, large_image_array_filepath = LoadAndMixImages(small_directory, # large_directory) # small_images_array = LoadImages("../../files/small_images_houses") # large_images_array = LoadImages_2("../../files/large_images_houses") # large_image_array_filepath = LoadPath("../../files/large_images_houses") small_images_array, large_images_array, large_image_array_filepath = LoadData(small_directory, large_directory) # Filling image arrays ImagesInArray(small_images_array, field.small_image_array, [], False) ImagesInArray(large_images_array, field.large_image_array, large_image_array_filepath, True) # Add arrow image to Player class images = [] for file in os.listdir("../../files/arrow"): path = f"../../files/arrow/{file}" img = PhotoImage(master=field.small_field_canvas, file=path) images.append(img) player.arrow_east_image = images[0] player.arrow_north_image = images[1] player.arrow_south_image = images[2] player.arrow_west_image = images[3] # Filling window with images Fill(True) # Drawing arrow (player) image = player.arrow_east_image player.image_canvas_id = field.small_field_canvas.create_image(player.current_x, player.current_y, anchor=NW, image=image) for i in range(10): print(field.large_image_array_filepath[i]) # Arrow(player.direction) # Rectangle(True, "None") # Rectangle() # Binding keyboard press to function # field.win.bind("", Action) # field.small_field_canvas.bind("", MouseClickEvent) # Starting mainloop for window field.win.mainloop() if __name__ == '__main__': main()