This commit is contained in:
Dominik Moritz Roth 2022-04-14 11:38:08 +02:00
parent 5ba277a2aa
commit f9a5ba1964

View File

@ -2,6 +2,7 @@ import time
import random import random
import threading import threading
import torch import torch
from math import sqrt
#from multiprocessing import Event #from multiprocessing import Event
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from threading import Event from threading import Event
@ -86,12 +87,13 @@ class State(ABC):
return [] return []
# improveMe # improveMe
def getPriority(self, score): def getPriority(self, score, cascadeMemory=None):
# Used for ordering the priority queue # Used for ordering the priority queue
# Priority should not change for the same root # Priority should not change for the same root
# Lower prioritys get worked on first # Lower prioritys get worked on first
# Higher generations should have higher priority # Higher generations should have higher priority
return score + self.generation*0.5 # Higher cascadeMemory (more influence on higher-order-scores) should have lower priority
return score + self.generation*0.5 - cascadeMemory*0.35
@abstractmethod @abstractmethod
def checkWin(self): def checkWin(self):
@ -142,10 +144,14 @@ class Node():
self._scores = [None]*self.state.playersNum self._scores = [None]*self.state.playersNum
self._strongs = [None]*self.state.playersNum self._strongs = [None]*self.state.playersNum
self._alive = True self._alive = True
self._cascadeMemory = 0 # Used for our alternative to alpha-beta pruning
def kill(self): def kill(self):
self._alive = False self._alive = False
def revive(self):
self._alive = True
@property @property
def childs(self): def childs(self):
if self._childs == None: if self._childs == None:
@ -159,26 +165,28 @@ class Node():
newNode = Node(self.state.mutate(action), self.universe, self, action) newNode = Node(self.state.mutate(action), self.universe, self, action)
self._childs.append(self.universe.merge(newNode)) self._childs.append(self.universe.merge(newNode))
@property def getStrongFor(self, player):
def strongs(self): if self._strongs[player]!=None:
return self._strongs return self._strongs[player]
else:
return self.getScoreFor(player)
def _pullStrong(self): # Currently Expecti-Max def _pullStrong(self): # Currently Expecti-Max
strongs = [None]*self.playersNum strongs = [None]*self.playersNum
for p in range(self.playersNum): for p in range(self.playersNum):
cp = self.state.curPlayer cp = self.state.curPlayer
if cp == p: # P owns the turn; controlls outcome if cp == p: # P owns the turn; controlls outcome
best = 10000000 best = 1000000000
for c in self.childs: for c in self.childs:
if c._strongs[cp] < best: if c.getStrongFor(p) < best:
best = c._strongs[p] best = c.getStrongFor(p)
strongs[p] = best strongs[p] = best
else: else:
scos = [(c._strongs[cp], c._strongs[p]) for c in self.childs] scos = [(c.getStrongFor(p), c.getStrongFor(cp)) for c in self.childs]
scos.sort(key=lambda x: x[0]) scos.sort(key=lambda x: x[1])
betterHalf = scos[:max(3,int(len(scos)/2))] betterHalf = scos[:max(3,int(len(scos)/3))]
myScores = [bh[1] for bh in betterHalf] myScores = [bh[0]**2 for bh in betterHalf]
strongs[p] = sum(myScores)/len(myScores) strongs[p] = sqrt(myScores[0]*0.75 + sum(myScores)/(len(myScores)*4))
update = False update = False
for s in range(self.playersNum): for s in range(self.playersNum):
if strongs[s] != self._strongs[s]: if strongs[s] != self._strongs[s]:
@ -186,21 +194,32 @@ class Node():
break break
self._strongs = strongs self._strongs = strongs
if update: if update:
self.parent._pullStrong() if self.parent!=None:
cascade = self.parent._pullStrong()
else:
cascade = 2
self._cascadeMemory = self._cascadeMemory/2 + cascade
return cascade + 1
self._cascadeMemory /= 2
return 0
def forceStrong(self, depth=3): def forceStrong(self, depth=3):
if depth==0: if depth==0:
self.strongDecay() self.strongDecay()
else: else:
for c in self.childs: if len(self.childs):
c.forceStrong(depth-1) for c in self.childs:
c.forceStrong(depth-1)
else:
self.strongDecay()
def strongDecay(self): def strongDecay(self):
if self._strongs == [None]*self.playersNum: if self._strongs == [None]*self.playersNum:
if not self.scoresAvaible(): if not self.scoresAvaible():
self._calcScores() self._calcScores()
self._strongs = self._scores self._strongs = self._scores
self.parent._pullStrong() return self.parent._pullStrong()
return None
def getSelfScore(self): def getSelfScore(self):
return self.getScoreFor(self.curPlayer) return self.getScoreFor(self.curPlayer)
@ -219,6 +238,12 @@ class Node():
return False return False
return True return True
def strongScoresAvaible(self):
for p in self._strongs:
if p==None:
return False
return True
def _calcScores(self): def _calcScores(self):
for p in range(self.state.playersNum): for p in range(self.state.playersNum):
self._calcScore(p) self._calcScore(p)
@ -307,9 +332,10 @@ class Runtime():
return return
bot = c=='bot' bot = c=='bot'
if bot: if bot:
self.head.forceStrong(7)
opts = [] opts = []
for c in self.head.childs: for c in self.head.childs:
opts.append((c, c.getStrongScore(self.head.curPlayer, -1)[0])) opts.append((c, c.getStrongFor(self.head.curPlayer)))
opts.sort(key=lambda x: x[1]) opts.sort(key=lambda x: x[1])
print('[i] Evaluated Options:') print('[i] Evaluated Options:')
for o in opts: for o in opts: