func continuedFraction(a float64, dSquaredFloorTimesTwo int) vector.IntVector { aFloor := int(math.Floor(a)) var ret vector.IntVector if dSquaredFloorTimesTwo == aFloor { return ret } ret.Push(aFloor) nextRet := continuedFraction(1/(a-float64(aFloor)), dSquaredFloorTimesTwo) ret.AppendVector(&nextRet) return ret }
// apply color to vertex, modifying board and updating liberties of any go_adj strings func (t *GoTracker) Play(color byte, vertex int) { if vertex != -1 { t.passes = 0 if t.koVertex != -1 { t.weights.Set(t.koColor, t.koVertex, INIT_WEIGHT) t.koVertex = -1 t.koColor = EMPTY } if t.superko { if t.history.Len() == 0 { t.history.Push(*NewHash(t.boardsize)) } cp := t.Copy() cp.(*GoTracker).superko = false cp.Play(color, vertex) t.history.Push(*MakeHash(cp)) } // modify the board t.board[vertex] = color // update parents and liberties of adjacent stones opp := Reverse(color) root := vertex for i := 0; i < 4; i++ { adj := t.adj[vertex][i] if adj != -1 && t.board[adj] == color { adj := find(adj, t.parent) // take adjacent chain out of atari (may be added back later) t.atari[color][adj] = 0, false // or in liberties to friendly chains new_root, old_root := union(root, adj, t.parent, t.rank) t.liberties[new_root][0] |= t.liberties[old_root][0] t.liberties[new_root][1] |= t.liberties[old_root][1] // xor out liberty from self t.liberties[new_root][0] &= ^t.mask[adj][0] t.liberties[new_root][1] &= ^t.mask[adj][1] root = new_root } else if adj != -1 && t.board[adj] == EMPTY { // xor out liberty from empty vertices t.liberties[adj][0] &= ^t.mask[vertex][0] t.liberties[adj][1] &= ^t.mask[vertex][1] } else if adj != -1 { // xor out liberties from enemy chains enemy := find(adj, t.parent) t.liberties[enemy][0] &= ^t.mask[vertex][0] t.liberties[enemy][1] &= ^t.mask[vertex][1] } } // xor out liberty from self t.liberties[root][0] &= ^t.mask[vertex][0] t.liberties[root][1] &= ^t.mask[vertex][1] // capture any adjacent enemies reduced to zero liberties var captured *vector.IntVector for i := 0; i < 4; i++ { adj := t.adj[vertex][i] if adj != -1 && t.board[adj] == opp { enemy := find(adj, t.parent) libs := t.libs(enemy) if libs == 0 { // take chain out of atari t.atari[opp][enemy] = 0, false if captured == nil { captured = t.capture(enemy) } else { captured.AppendVector(t.capture(enemy)) } } } } // check for suicide of affected empty points for i := 0; i < 4; i++ { adj := t.adj[vertex][i] if adj != -1 && t.board[adj] == EMPTY && t.libs(adj) == 0 { t.check_suicide(adj) } else if adj != -1 && (t.board[adj] == BLACK || t.board[adj] == WHITE) { adj = find(adj, t.parent) if t.libs(adj) == 1 { last_liberty := t.lastliberty(adj) if t.libs(last_liberty) == 0 { t.check_suicide(last_liberty) } } } } // ko check if captured != nil && captured.Len() == 1 { capture := captured.At(0) t.check_suicide(capture) if t.libs(root) == 1 { t.koColor = opp t.koVertex = capture } } // check if capture took adjacent chains out of atari // if so, check suicide status of their previous last liberty for i := 0; captured != nil && i < captured.Len(); i++ { capture := captured.At(i) for j := 0; j < 4; j++ { adj := t.adj[capture][j] if adj != -1 && t.board[adj] == color { adj = find(adj, t.parent) if last_liberty, exists := t.atari[color][adj]; exists { t.check_suicide(last_liberty) t.atari[color][adj] = 0, false } } } } // cannot play on occupied vertex t.weights.Set(BLACK, vertex, 0) t.weights.Set(WHITE, vertex, 0) // update atari status of adjacent chains for i := 0; i < 4; i++ { adj := t.adj[vertex][i] if adj != -1 && (t.board[adj] == BLACK || t.board[adj] == WHITE) { adj = find(adj, t.parent) if t.libs(adj) == 1 { t.atari[t.board[adj]][adj] = t.lastliberty(adj) } } } // update atari status of current chain if t.libs(root) == 1 { t.atari[color][root] = t.lastliberty(root) } // apply patterns neighbors := t.neighbors[1][vertex] for i := range neighbors { if neighbors[i] != -1 && t.board[neighbors[i]] == EMPTY { t.updateWeights(neighbors[i]) } } for i := 0; captured != nil && i < captured.Len(); i++ { t.updateWeights(captured.At(i)) } // mark vertex as played for AMAF if t.played[vertex] == EMPTY { t.played[vertex] = color } } else { t.passes++ } t.moves.Push(vertex) }