/* * Updates the board with a move. Assumes that the move is legal. */ void Board::doMove(Player p, Move m) { if (m == MOVE_PASS) return; int x = getX(m); int y = getY(m); assert(pieces[index(x, y)] == EMPTY); assert(chainID[index(x, y)] == 0); pieces[index(x, y)] = p; zobristKey ^= zobristTable[zobristIndex(p, x, y)]; Player victim = otherPlayer(p); Stone east = pieces[index(x+1, y)]; Stone west = pieces[index(x-1, y)]; Stone north = pieces[index(x, y+1)]; Stone south = pieces[index(x, y-1)]; int connectionCount = (east == p) + (west == p) + (north == p) + (south == p); // If the stone placed is a new chain if (connectionCount == 0) { // Record which chain this square is a part of chainID[index(x, y)] = nextID; // Add this chain to the list of chains Chain *cargo = new Chain(p, nextID); cargo->add(m); cargo->liberties = 0; if (east == EMPTY) cargo->addLiberty(coordToMove(x+1, y)); if (west == EMPTY) cargo->addLiberty(coordToMove(x-1, y)); if (north == EMPTY) cargo->addLiberty(coordToMove(x, y+1)); if (south == EMPTY) cargo->addLiberty(coordToMove(x, y-1)); chainList.add(cargo); nextID++; } // If the stone placed is added to an existing chain else if (connectionCount == 1) { // Find the ID of the chain we are adding this stone to int thisID; if (east == p) thisID = chainID[index(x+1, y)]; else if (west == p) thisID = chainID[index(x-1, y)]; else if (north == p) thisID = chainID[index(x, y+1)]; else thisID = chainID[index(x, y-1)]; chainID[index(x, y)] = thisID; Chain *node = nullptr; searchChainsByID(node, thisID); node->add(m); // The new stone occupies a previous liberty, but adds on however many // liberties it itself has node->removeLiberty(node->findLiberty(m)); updateLiberty(node, x, y); } // If the stone possibly connects two existing chains else { int eastID = (east == p) * chainID[index(x+1, y)]; int westID = (west == p) * chainID[index(x-1, y)]; int northID = (north == p) * chainID[index(x, y+1)]; int southID = (south == p) * chainID[index(x, y-1)]; Chain *node = nullptr; bool added = false; if (eastID) { chainID[index(x, y)] = eastID; searchChainsByID(node, eastID); node->add(m); node->removeLiberty(node->findLiberty(m)); updateLiberty(node, x, y); added = true; } if (westID) { if (added) { // If two stones from the same chain are adjacent, do nothing // If they are from different chains, we need to combine... if (westID != eastID) mergeChains(node, westID, m); } else { chainID[index(x, y)] = westID; searchChainsByID(node, westID); node->add(m); node->removeLiberty(node->findLiberty(m)); updateLiberty(node, x, y); added = true; } } if (northID) { if (added) { if (northID != eastID && northID != westID) mergeChains(node, northID, m); } else { chainID[index(x, y)] = northID; searchChainsByID(node, northID); node->add(m); node->removeLiberty(node->findLiberty(m)); updateLiberty(node, x, y); added = true; } } if (southID) { if (added) { if (southID != eastID && southID != westID && southID != northID) mergeChains(node, southID, m); } else { chainID[index(x, y)] = southID; searchChainsByID(node, southID); node->add(m); node->removeLiberty(node->findLiberty(m)); updateLiberty(node, x, y); added = true; } } } // Update opponent liberties int eastID = (east == victim) * chainID[index(x+1, y)]; int westID = (west == victim) * chainID[index(x-1, y)]; int northID = (north == victim) * chainID[index(x, y+1)]; int southID = (south == victim) * chainID[index(x, y-1)]; if (eastID) { Chain *node = nullptr; int nodeIndex = searchChainsByID(node, eastID); node->removeLiberty(node->findLiberty(m)); if (node->liberties == 0) captureChain(node, nodeIndex); } if (westID && westID != eastID) { Chain *node = nullptr; int nodeIndex = searchChainsByID(node, westID); node->removeLiberty(node->findLiberty(m)); if (node->liberties == 0) captureChain(node, nodeIndex); } if (northID && northID != eastID && northID != westID) { Chain *node = nullptr; int nodeIndex = searchChainsByID(node, northID); node->removeLiberty(node->findLiberty(m)); if (node->liberties == 0) captureChain(node, nodeIndex); } if (southID && southID != eastID && southID != westID && southID != northID) { Chain *node = nullptr; int nodeIndex = searchChainsByID(node, southID); node->removeLiberty(node->findLiberty(m)); if (node->liberties == 0) captureChain(node, nodeIndex); } // Check for a suicide int selfID = chainID[index(x, y)]; Chain *node = nullptr; int nodeIndex = searchChainsByID(node, selfID); if (node->liberties == 0) captureChain(node, nodeIndex); // A debugging check assert(!checkChains()); // Check if p captured any of the other player's stones with move m /* doCaptures<true>(victim, coordToMove(x+1, y)); doCaptures<true>(victim, coordToMove(x-1, y)); doCaptures<true>(victim, coordToMove(x, y+1)); doCaptures<true>(victim, coordToMove(x, y-1)); // Check if p suicided with move m doCaptures<true>(p, coordToMove(x, y)); */ }
// Performs a capture on a chain and updates the board, adjacent liberties, etc. // To be called on a chain that has no liberties void Board::captureChain(Chain *node, int nodeIndex) { Player victim = node->color; if (victim == BLACK) whiteCaptures += node->size; else blackCaptures += node->size; for (int i = 0; i < node->size; i++) { int rx = getX(node->squares[i]); int ry = getY(node->squares[i]); pieces[index(rx, ry)] = EMPTY; chainID[index(rx, ry)] = 0; zobristKey ^= zobristTable[zobristIndex(node->color, rx, ry)]; // Add this square to adjacent chains' liberties int addID = chainID[index(rx+1, ry)]; if (addID && addID != node->id) { Chain *temp = nullptr; searchChainsByID(temp, addID); if (temp->findLiberty(coordToMove(rx, ry)) == -1) temp->addLiberty(coordToMove(rx, ry)); } addID = chainID[index(rx-1, ry)]; if (addID && addID != node->id && addID != chainID[index(rx+1, ry)]) { Chain *temp = nullptr; searchChainsByID(temp, addID); if (temp->findLiberty(coordToMove(rx, ry)) == -1) temp->addLiberty(coordToMove(rx, ry)); } addID = chainID[index(rx, ry+1)]; if (addID && addID != node->id && addID != chainID[index(rx+1, ry)] && addID != chainID[index(rx-1, ry)]) { Chain *temp = nullptr; searchChainsByID(temp, addID); if (temp->findLiberty(coordToMove(rx, ry)) == -1) temp->addLiberty(coordToMove(rx, ry)); } addID = chainID[index(rx, ry-1)]; if (addID && addID != node->id && addID != chainID[index(rx+1, ry)] && addID != chainID[index(rx-1, ry)] && addID != chainID[index(rx, ry+1)]) { Chain *temp = nullptr; searchChainsByID(temp, addID); if (temp->findLiberty(coordToMove(rx, ry)) == -1) temp->addLiberty(coordToMove(rx, ry)); } } // Remove this chain since it has been captured delete node; chainList.removeFast(nodeIndex); }