Files
@ 0cb3fbe06b5d
Branch filter:
Location: OneEye/src/statebag.py - annotation
0cb3fbe06b5d
2.8 KiB
text/x-python
Go, Engine: some tests and numerous bugfixes
3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 077600f0c5f8 7f1984280936 7f1984280936 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 7f1984280936 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 7f1984280936 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 7f1984280936 077600f0c5f8 7f1984280936 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 7f1984280936 3cce3db6d4cc 3cce3db6d4cc 7f1984280936 077600f0c5f8 7f1984280936 3cce3db6d4cc b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe 3cce3db6d4cc 7f1984280936 7f1984280936 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc 3cce3db6d4cc | """Theory:
We have a sequence S of valid board states s_1, ..., s_n.
We search for a picked subsequence S_p of length k and m additional moves M such that:
- S_p augmented by M forms a valid sequence of moves
- k-m is maximal for S_p picked from S
It is relatively cheap to add new items to S.
User can change detector parameters, presumably in case the previous don't fit the (current) situation.
In such a case we assume the new parameters are correct from the current position onwards.
But the change might have been appropriate even earlier (before the user detected and fixed an error).
So we try to find the correct crossover point like this:
- construct a sequence S' = s'_i, ..., s'_n by reanalyzing the positions with a new set of parameters, where s_i is the point of previous user intervention or s_0
- for each s'_j:
- try to append it to S[:j]
- try to append it to S'[:j]
- remember the better variant
- linearize the fork back by discarding s'_j-s preceding the crossover and s_j-s following the crossover
"""
from util import EMPTY, hashBoard
from go.engine import transitionSequence
## Crude lower bound on edit distance between states.
def estimateDistance(diff):
# lot of room for improvements
additions=sum(1 for d in diff if d[2]=="+")
deletions=sum(1 for d in diff if d[2]=="-")
replacements=len(diff)-additions-deletions
if additions>0: return additions+replacements
elif replacements==0 and deletions>0: return 2 # take n, return 1
return replacements+1 # ???
class BoardState:
def __init__(self,board):
self._board=tuple(tuple(x for x in row) for row in board)
self.prev=None
self._next=None
self.moves=[]
self.weight=0
self.diff2Prev=None
def hash(self):
return hashBoard(self._board)
def __iter__(self): return iter(self._board)
def __getitem__(self,key): return self._board[key]
def __sub__(self,x):
res=[]
for (r,(row1,row2)) in enumerate(zip(self._board,x)):
for (c,(item1,item2)) in enumerate(zip(row1,row2)):
if item1==item2: continue
elif item2==EMPTY: res.append((r,c,"+",item1))
elif item1==EMPTY: res.append((r,c,"-",item2))
else: res.append((r,c,"*",item1)) # ->to
return res
def __eq__(self,x):
return self.hash()==x.hash()
class StateBag:
def __init__(self):
self._states=[]
def pushState(self,board):
sn=BoardState(board)
if self._states and sn==self._states[-1]: return # no change
for s in reversed(self._states):
diff=sn-s
distEst=estimateDistance(diff)
if distEst>3: continue # we couldn't find every such move sequence anyway without a clever algorithm
weightEst=s.weight-distEst
if weightEst<=sn.weight: continue
moves=transitionSequence(s,sn,diff)
weight=s.weight-len(moves)
if weight<=sn.weight: continue
sn.prev=s
sn.diff2Prev=diff
sn.moves=moves
sn.weight=weight
self._states.append(sn)
def merge(self,branch):
pass
|