Skip to content

Commit

Permalink
Chop!
Browse files Browse the repository at this point in the history
  • Loading branch information
Flowtter committed Mar 24, 2020
1 parent 2fceaac commit f591e0a
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 42 deletions.
16 changes: 12 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@

Unrailed! is a Video Game available on steam [there](https://unrailed-game.com/) :

We decided to make a bot to play the game with an AI.
I decided to make a bot to play the game with an AI.

+ [Brice PARENT](https://github.com/Naexys)
+ [Léo BENITO ](https://github.com/TrAyZeN)

My friend helped me to clean the repo. Cheers.

+ [Léo BENITO ](https://github.com/TrAyZeN)

## Pictures

![](assets/demo.gif)
![](assets/chop.gif)
![](assets/Dot.PNG)

## Get started
Expand All @@ -25,5 +29,9 @@ We decided to make a bot to play the game with an AI.
## TO-DO

* add the qwerty layout as an argument in the main.py
* add the bot movement
* add a pause key to the bot
* add a pause key to the bot
* add an autoclicker
* handle better errors
* show map each after each movement
* fix axe detection
* clean the repo
Binary file added assets/chop.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
60 changes: 48 additions & 12 deletions src/debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,44 @@

from detection import axe, trees, player, rock, blackrock, river, terrain, green


from player import bot
from capture import windowcapture
from show_map import game_map

def debug_main():
"""function to replace the main to keep it clean"""

def test(im):
p_bot = bot.Bot(5)
im = cut(im)

time.sleep(2)

game = game_map(20,36,22,16,10) # (self, height, width, cell_size, refresh_rate):
game.init_matrix()
set_array_from_bin(game, im)

player_pos = game.get_pos('P')[0]

#player_pos = p_bot.move("axe", game, False, player_pos)

a = "Not None :)"

while a != None:
player_pos = p_bot.move("tree", game, False, player_pos)
a = p_bot.breaking('T', player_pos, game)
if a!= None:
player_pos = a
game.replace_letter('t', 'M', 'T')

game.matrix[player_pos[0]][player_pos[1]] = 'P'

game.draw_matrix()
im2 = game.draw_image()
grid(im)
show2([im, im2])

def debug_game():
#im = single_screenshot()

im = cv2.imread("../test_data/img_debug.png", cv2.COLOR_RGB2BGR)
Expand All @@ -25,7 +56,7 @@ def debug_main():
game.init_matrix()


get_array_from_bin(game, im)
set_array_from_bin(game, im)


game.print_matrix()
Expand All @@ -37,7 +68,9 @@ def debug_main():

game2 = game_map(20,36,22,16,10) # (self, height, width, cell_size, refresh_rate):
game2.init_matrix()
get_array_from_bin(game2, im)
set_array_from_bin(game2, im)


im5 = astar_map(game2)


Expand Down Expand Up @@ -71,18 +104,20 @@ def cut(im):


def astar_map(g):
start, end = (15,19), (19,6)
print(g.get_matrix()[start[1]][start[0]])
print(g.get_matrix()[end[1]][end[0]])
player = g.get_pos('P')
tree = g.get_pos('t')
start = player[0]

# pour opti il faut ajoyter les contours, les M avec un T à coté deviennent V, je vérifie ces valuers là

try:
original = g.get_binary_matrix()
astar.run(original, start, end, g)
end = astar.run(original, start, tree, g)
except:
print(" ")


g.matrix_add(start[1], start[0], 'S')
g.matrix_add(start[1], start[0], 'P')
g.matrix_add(end[1], end[0], 'U')
g.draw_matrix()

Expand All @@ -95,7 +130,7 @@ def unpack_array(arr, vall, game):
game.matrix_add(e[0], e[1], vall)


def get_array_from_bin(game, im):
def set_array_from_bin(game, im):
x, y = player.get_pos(im, cv2.cvtColor(im,cv2.COLOR_BGR2HSV))

bin_green = green.get_bin(im, cv2.cvtColor(im,cv2.COLOR_BGR2HSV))
Expand All @@ -104,15 +139,15 @@ def get_array_from_bin(game, im):
bin_black = blackrock.get_bin(im, cv2.cvtColor(im, cv2.COLOR_BGR2HSV))
bin_river = river.get_bin(im, cv2.cvtColor(im,cv2.COLOR_BGR2HSV ))
bin_terrain = terrain.get_bin(im, cv2.cvtColor(im,cv2.COLOR_BGR2HSV ))
bin_axe = axe.get_bin(im, cv2.cvtColor(im,cv2.COLOR_BGR2HSV ))
#bin_axe = axe.get_bin(im, cv2.cvtColor(im,cv2.COLOR_BGR2HSV ))

#arrplayer = element(game, bin_player, bin_player, 6)
arrtree = element(game, bin_trees, bin_trees, 3)
arrrock = element(game, bin_rocks, bin_rocks, 4)
arrblack = element(game, bin_black, bin_black, 3)
arrriver = element(game, bin_river, bin_river, 3)
arrmain = element(game, bin_green, bin_green, 5)
areaxe = element(game, bin_axe, bin_axe, 3)
#areaxe = element(game, bin_axe, bin_axe, 3)

arrout = element(game, bin_terrain, bin_terrain, 6)

Expand All @@ -122,9 +157,10 @@ def get_array_from_bin(game, im):
unpack_array(arrtree,'T', game)
unpack_array(arrrock, 'K', game)
unpack_array(arrout, '0', game)
game.replace_letter('t', 'M', 'T')


game.matrix_add(areaxe[0][0], areaxe[0][1] + 1, 'A') # offset
#game.matrix_add(areaxe[0][0], areaxe[0][1] + 1, 'A') # offset

game.matrix_add(x, y, 'P')

Expand Down
5 changes: 4 additions & 1 deletion src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
DEBUG = True

if DEBUG:
debug.debug_main()
capture = windowcapture.WindowCapture("Unrailed!", FRAME_RATE)
capture.start()
frame = capture.read()
debug.test(frame)
exit()

capture = windowcapture.WindowCapture("Unrailed!", FRAME_RATE)
Expand Down
41 changes: 21 additions & 20 deletions src/pathfinding/astar.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def astar(maze, start, end, allow_diagonal_movement=False):

# Adding a stop condition
outer_iterations = 0
max_iterations = (len(maze[0]) * len(maze) // 2)
max_iterations = (len(maze[0]) * len(maze)) # // 2)

# what squares do we search
adjacent_squares = ((0, -1), (0, 1), (-1, 0), (1, 0),)
Expand Down Expand Up @@ -134,25 +134,26 @@ def astar(maze, start, end, allow_diagonal_movement=False):
# Add the child to the open list
heapq.heappush(open_list, child)

warn("Couldn't get a path to destination")
#warn("Couldn't get a path to destination")
return None


def run(maze, start, end, game):

path = astar(maze, start, end)

for step in path:
game.matrix_add(step[1], step[0], 'C')
# maze[step[0]][step[1]] = 2
#for row in maze:
# line = []
# for col in row:
# if col == 1:
# line.append("M")
# elif col == 0:
# line.append("E")
# elif col == 2:
# line.append("C")
# print("".join(line))
#print(path)
def run(maze, start, end, game, draw=False):
step_min = 5000
best_path = astar(maze, start, end[0])

for i in range (1, len(end)):
path = astar(maze, start, end[i])
if path != None and len(path) < step_min:
step_min = len(path)
best_path = path

if draw:
for i in range (1, len(best_path)):
game.matrix_add(best_path[i][1], best_path[i][0], 'C')


print("--------------------------------")
print(best_path)
print("--------------------------------")
return best_path
134 changes: 134 additions & 0 deletions src/player/bot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import cv2
import numpy as np
import pyautogui
from threading import Thread
import time
import win32gui
import keyboard

from pathfinding import astar

SPEED = 0.12
TIME_OFF = 0.05
BREAK_TIME = 2.1


class Bot:

# function init to declare variables

def __init__(self, updateHZ):
self.should_stop = False
self.wait_time = 1/updateHZ
self._thread_name = "Bot"

# function start, give a thread to the object

def start(self):
self._thread = Thread(target=self.update, name=self._thread_name, args=())
self._thread.daemon = True
self._thread.start()
return self

# function update, replace self.frame by an image that has been screenshoted

def update(self):
while not self.should_stop: # changed True by self...
start = time.time()
delta = time.time() - start

if keyboard.is_pressed("P"):
self.stop()

if delta < self.wait_time:
time.sleep(self.wait_time - delta)

# function that join the thread to then stop them

def stop(self):
self.should_stop = True
self._thread.join()

def input(self, key, t):
pyautogui.keyDown(key)
time.sleep(t)
pyautogui.keyUp(key)

def movement(self, key):
self.input(key, SPEED)
time.sleep(TIME_OFF)

def path(self, start, obj, g, draw):
original = g.get_binary_matrix()
print("path: ")

if obj == "axe":
pickaxe = g.get_pos('A')
return astar.run(original, start, pickaxe, g, draw)

elif obj == "tree":
tree = g.get_pos('t')
return astar.run(original, start, tree, g, draw)

else:
raise Exception("bot: path: not a valid object")


def move(self, obj, game, draw, player_pos):
game.matrix[player_pos[0]][player_pos[1]] = 'M'
movement = self.path(player_pos, obj, game, draw)
i = 0
for vect in movement:
i+= 1
x = player_pos[0] - vect[0]
y = player_pos[1] - vect[1]
player_pos = vect
if y > 0:
self.movement('q')
elif y < 0:
self.movement('d')
elif x < 0:
self.movement('s')
elif x > 0:
self.movement('z')
if obj == "axe":
self.input("space", 0.1)

game.matrix[player_pos[0]][player_pos[1]] = 'P'

return player_pos

def breaking(self, obj, player_pos, game):

game.matrix[player_pos[0]][player_pos[1]] = 'M' # Remove the 't'

if player_pos[0] -1 > 0 and game.matrix[player_pos[0] - 1][player_pos[1]] == obj:
self.input('z', BREAK_TIME)
game.matrix[player_pos[0] - 1][player_pos[1]] = 'P'
return (player_pos[0] - 1,player_pos[1])


elif player_pos[0] +1 < len(game.matrix) and game.matrix[player_pos[0] + 1][player_pos[1]] == obj:
self.input('s', BREAK_TIME)
game.matrix[player_pos[0] + 1][player_pos[1]] = 'P'
return (player_pos[0] + 1,player_pos[1])


elif player_pos[1] -1 > 0 and game.matrix[player_pos[0]][player_pos[1] - 1] == obj:
self.input('q', BREAK_TIME)
game.matrix[player_pos[0]][player_pos[1] - 1] = 'P'
return (player_pos[0],player_pos[1]- 1)


elif player_pos[1] +1 < len(game.matrix[0]) and game.matrix[player_pos[0]][player_pos[1] + 1] == obj:
self.input('d', BREAK_TIME)
game.matrix[player_pos[0]][player_pos[1] + 1] = 'P'
return (player_pos[0],player_pos[1] + 1)

print("no trees are reachable")
return None





Loading

0 comments on commit f591e0a

Please sign in to comment.