From 13bdabe15614a97226cf812f1de8379360e35ec3 Mon Sep 17 00:00:00 2001 From: Jonas Mucke Date: Sun, 19 Apr 2020 10:18:22 +0200 Subject: [PATCH] aStar implementation with todos --- src/Overlap/AI/AI_Hero.gd | 208 +++++++++++++++++++++++++++++++++ src/Overlap/AI/prio_queue.gd | 53 +++++++++ src/Overlap/Stats/player_ai.gd | 97 --------------- src/World.tscn | 10 +- 4 files changed, 266 insertions(+), 102 deletions(-) create mode 100644 src/Overlap/AI/AI_Hero.gd create mode 100644 src/Overlap/AI/prio_queue.gd delete mode 100644 src/Overlap/Stats/player_ai.gd diff --git a/src/Overlap/AI/AI_Hero.gd b/src/Overlap/AI/AI_Hero.gd new file mode 100644 index 0000000..776019c --- /dev/null +++ b/src/Overlap/AI/AI_Hero.gd @@ -0,0 +1,208 @@ +extends Node +const PrioQueue = preload("prio_queue.gd") # Relative pat + +enum{ + BOSS, + TORCH, + MINION, + RED, + BLUE, + GREEN, + HEART, + BONFIRE, + BARREL, + TERMINAL_SYMBOL +} + +enum{ + LENGTH, + WAY +} + +enum{ + DAMAGE, + SLOW, + WALL, + FIELD +} + +enum{ + STEP, + ROLL, + NOTHING +} + +var Grid = [] +var used_Flags = [] + +var numbers = [0,0,0,0,0,0,0,0,0] +var prios = [7,6,5,4,3,2,0,0,4] + +var totalPrioTurn = 0 +var executesTurn = false +var abortProb = 0.01 + +#calculates the sum of all present prios +func calcTotalPrio(): + var sum = 0 + var i = BOSS + while i != TERMINAL_SYMBOL: + if(numbers[i]>0): + sum += prios[i] + i=i+1 + return sum + +#calculates the relative porio +func calcRelPrio(index, sum): + return prios[index]/sum + +#calucaltes the prio table of all enemies[0,1) +func calcPrioTable(): + var table = [0,0,0,0,0,0,0,0,0] + var lower = 0 + var sum = calcTotalPrio() + + var i = 0; + while i != TERMINAL_SYMBOL: + lower += calcRelPrio(i, sum) + table[i] = lower + i = i+1 + + return table + +#updates heart and bonfire prio +func adjustPrio(currentHealth, maxHealth): + var prioVal = 10 - (currentHealth/maxHealth)*10 + var bonfire = prioVal + var hearts = prioVal -1 + if(hearts < 0): + hearts = 0 + prios[BONFIRE]=bonfire + prios[HEART]=hearts + +#return the enemie which will be attacked +func calcEnemie(): + var table = calcPrioTable() + var number = randf() + var i = TERMINAL_SYMBOL-1 + while table[i] > number: + i=i-1 + return i + +#returns a move +func getMoveDescription(myPosition : Vector2, targetPositions): + var way = AStar(myPosition, targetPositions[0]) + + #TODO choose enemie with loest distance + return 0 + + +func getFieldState(position): + pass + +func getCost(position): + # var cost = 0 + # for i in Feld[position.x][position.y]: + # match i: + # DAMAGE : cost += damage*prios[BONFIRE]*3 + # SLOW : cost += 2 + # + #return cost + return 0 + +#return an heurestic of distance +# curr - current position +# targ - atarget position +func h(curr, targ): + return min(abs(target[0]-curr[0]),abs(target[0]-curr[0])) + +# currCost - currentCost +# position - position of the field to move to +func g(currCost, position): + return curr + getCost(position) + +#returns the list of adjacent nodes +func adjacent(currentPosition): + var adj := [] + #adj.append([STEP, Vector2(0,0)]) + var p = currentPosition + var pot_adj_step = [[p[0]-1, p[1]-1], [p[0]-1, p[1]-0], [p[0]-1, p[1]+1], + [p[0]+0, p[1]-1], [p[0]+0, p[1]+1], + [p[0]+1, p[1]-1], [p[0]+1, p[1]+0], [p[0]+1, p[1]+1]] + + var pot_adj_roll = [[p[0]-2, p[1]-2], [p[0]-2, p[1]-0], [p[0]-2, p[1]+2], + [p[0]+0, p[1]-2], [p[0]+0, p[1]+2], + [p[0]+2, p[1]-2], [p[0]+2, p[1]+0], [p[0]+2, p[1]+2]] + + for next in pot_adj_step: + if(next[0]<0): + continue + if(next[0]>13): + continue + if(next[1]<0): + continue + if(next[1]>6): + continue + if(used_Flags[next[0]][next[1]]==true): + continue + if(Grid[next[0]][next[1]][0]!=WALL): + adj.append([STEP, Vector2(next[0],next[1])]) + + for next in pot_adj_roll: + if(next[0]<0): + continue + if(next[0]>13): + continue + if(next[1]<0): + continue + if(next[1]>6): + continue + if(used_Flags[next[0]][next[1]]==true): + continue + if(Grid[next[0]][next[1]][0]!=WALL): + adj.append([ROLL, Vector2(next[0],next[1])]) + + return adj + + + +func AStar(source, target): + #swap rtarget and source, when target source istr reached, do inversxse step + # node layout [g+h(x), g(x), current, from, kind] + var tmp = source + source = target + target = tmp + + var Q = PrioQueue.new() + Q.insert([0,0, [source[0], source[1]]]) + while !Q.empty(): + var node = Q.delMin() + + #check if reached + if(node[2][0]==target[0] and node[2][1]==target[1]): + return [node[4], 0]#todo map movement] + + #set flag + used_Flags[current[0]][current[1]] = true + var adj_list = adjacent(node[2]) + for i in adj_ist: + var move_cost = 0 + if(i[0]==STEP): + move_cost = 1 + else: + rmove_cost = 2 + + + + return [NOTHING, 0] + +# Called when the node enters the scene tree for the first time. +func _ready(): + + + + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/src/Overlap/AI/prio_queue.gd b/src/Overlap/AI/prio_queue.gd new file mode 100644 index 0000000..b428bf9 --- /dev/null +++ b/src/Overlap/AI/prio_queue.gd @@ -0,0 +1,53 @@ +extends Node + +# Priority Queue implementation with binary heap +var heaplist +var currentSize + +# node layout [g+h(x), g(x), position] + +func _init(): + heaplist = [[0]] + currentSize = 0 + +func percUp(i): + while floor(i / 2) > 0: + if heaplist[i][0] < heaplist[floor(i / 2)][0]: + var tmp = heaplist[floor(i / 2)] + heaplist[floor(i / 2)] = heaplist[i] + heaplist[i] = tmp + i = floor(i / 2) + +func insert(k): + heaplist.append(k) + currentSize += 1 + percUp(currentSize) + +func percDown(i): + while (i * 2) <= currentSize: + var mc = minChild(i) + if heaplist[i][0] > heaplist[mc][0]: + var tmp = heaplist[i] + heaplist[i] = heaplist[mc] + heaplist[mc] = tmp + i = mc + +func minChild(i): + if i * 2 + 1 > currentSize: + return i * 2 + else: + if heaplist[i*2][0] < heaplist[i*2+1][0]: + return i * 2 + else: + return i * 2 + 1 + +func delMin(): + var retval = heaplist[1] + heaplist[1] = heaplist[currentSize] + heaplist.remove(currentSize - 1) + currentSize -= 1 + percDown(1) + return retval + +func empty(): + return currentSize < 1 diff --git a/src/Overlap/Stats/player_ai.gd b/src/Overlap/Stats/player_ai.gd deleted file mode 100644 index a176ec4..0000000 --- a/src/Overlap/Stats/player_ai.gd +++ /dev/null @@ -1,97 +0,0 @@ -extends Node - -enum{ - BOSS, - TORCH, - MINION, - RED, - BLUE, - GREEN, - HEART, - BONFIRE, - BARREL, - TERMINAL_SYMBOL -} - -enum{ - LENGTH, - WAY -} - -var numbers = [0,0,0,0,0,0,0,0,0] -var prios = [7,6,5,4,3,2,0,0,4] - -var totalPrioTurn = 0 -var executesTurn = false -var abortProb = 0.01 - -func calcTotalPrio(): - var sum = 0 - var i = BOSS - while i != TERMINAL_SYMBOL: - if(numbers[i]>0): - sum += prios[i] - i=i+1 - return sum - -func calcRelPrio(index, sum): - return prios[index]/sum - -func calcPrioTable(): - var table = [0,0,0,0,0,0,0,0,0] - var lower = 0 - var sum = calcTotalPrio() - - var i = 0; - while i != TERMINAL_SYMBOL: - lower += calcRelPrio(i, sum) - table[i] = lower - i = i+1 - - return table - -func adjustPrio(currentHealth, maxHealth): - var prioVal = 10 - (currentHealth/maxHealth)*10 - var bonfire = prioVal - var hearts = prioVal -1 - if(hearts < 0): - hearts = 0 - prios[BONFIRE]=bonfire - prios[HEART]=hearts - -func calcEnemie(): - var table = calcPrioTable() - var number = randf() - var i = TERMINAL_SYMBOL-1 - while table[i] > number: - i=i-1 - return i - -func getMoveDescription(myPosition : Vector2, targetPositions): - var way = AStar(myPosition, targetPositions[0]) - - for i in range(1, targetPositions.size()): - var tmp_way = AStar(myPosition, targetPositions[i]) - if(tmp_way[LENGTH] < way[LENGTH]): - way = tmp_way - return way[WAY] - -func h(curr, targ): - return sqrt(pow(curr,2)+pow(targ,2)) - -func h(curr, position): - - -func AStar(source, target): - pass - -# Called when the node enters the scene tree for the first time. -func _ready(): - prios[BOSS] = 1 - - - - -# Called every frame. 'delta' is the elapsed time since the previous frame. -#func _process(delta): -# pass diff --git a/src/World.tscn b/src/World.tscn index 96dd2cf..0873cb6 100644 --- a/src/World.tscn +++ b/src/World.tscn @@ -92,19 +92,19 @@ position = Vector2( 8.00002, -96 ) position = Vector2( -128, 16 ) [node name="Barrel7" parent="YSort" instance=ExtResource( 10 )] -position = Vector2( -56, 16 ) +position = Vector2( -48, 16 ) [node name="Barrel8" parent="YSort" instance=ExtResource( 10 )] -position = Vector2( -72, 16 ) +position = Vector2( -64, 16 ) [node name="Barrel9" parent="YSort" instance=ExtResource( 10 )] -position = Vector2( -88, 16 ) +position = Vector2( -80, 16 ) [node name="Barrel10" parent="YSort" instance=ExtResource( 10 )] -position = Vector2( -104, 16 ) +position = Vector2( -96, 16 ) [node name="Barrel11" parent="YSort" instance=ExtResource( 10 )] -position = Vector2( -120, 16 ) +position = Vector2( -112, 16 ) [node name="Barrel2" parent="YSort" instance=ExtResource( 10 )] position = Vector2( 8.00002, -48 )