int[] getChangedIndices(bool isWhite, int[] lastMove) { int colorIndex = isWhite ? 0 : 1; int oppositeColorIndex = isWhite ? 1 : 0; HashSet<int> retVal = new HashSet<int>(); BitboardLayer nums = new BitboardLayer(c.getDict(true)[pieceIndex.ALL_LOCATIONS].getLayerData() | c.getDict(true)[pieceIndex.ALL_LOCATIONS].getLayerData() | (pieceLocations[colorIndex].getLayerData() ^ c.getDict(isWhite)[pieceIndex.ALL_LOCATIONS].getLayerData())); foreach(int i in nums.getTrueIndicies()) { retVal.Add(i); } int[] arrayForm = new int[retVal.Count]; retVal.CopyTo(arrayForm); return arrayForm; }
public BitboardLayer(BitboardLayer b) { layerData = b.getLayerData(); trueIndicies = new HashSet<int>(); foreach (int i in b.getTrueIndicies()) { trueIndicies.Add(i); } }
//returns the indicies we need to change findAttackMove / getAttackedSquares for /* int[] getChangedIndices(bool isWhite, int[] lastMove) { int colorIndex = isWhite ? 0 : 1; int oppositeColorIndex = isWhite ? 1 : 0; HashSet<int> retVal = new HashSet<int>(); BitboardLayer oldAttackedSquares = new BitboardLayer(currAttackedSquares[colorIndex][lastMove[0]].getLayerData() | currValidMoves[colorIndex][lastMove[0]].getLayerData()); BitboardLayer changedIndicies = new BitboardLayer(pieceLocations[colorIndex].getLayerData() ^ c.getDict(isWhite)[pieceIndex.ALL_LOCATIONS].getLayerData()); int[] sidesInOrder; if (currCheckers[oppositeColorIndex].Count != 0) sidesInOrder = new int[] { oppositeColorIndex, colorIndex }; else sidesInOrder = new int[] { colorIndex, oppositeColorIndex }; int currColorIndex = sidesInOrder[0]; //int consideredIndex = 1 - currColorIndex; //consideredIndex is the index of the opposite side foreach (int index in c.getDict(currColorIndex == 0)[pieceIndex.ALL_LOCATIONS].getTrueIndicies()) { BitboardLayer valAttack = new BitboardLayer(currAttackedSquares[currColorIndex][index].getLayerData() | currValidMoves[currColorIndex][index].getLayerData()); //BitboardLayer valAttack = new BitboardLayer(currAttackedSquares[consideredIndex][index].getLayerData() | currValidMoves[consideredIndex][index].getLayerData()); foreach (int changedIndex in changedIndicies.getTrueIndicies()) { if (valAttack.trueAtIndex(changedIndex)) retVal.Add(index); //was attacking (opposite color) } } currColorIndex = 1 - currColorIndex; if (currCheckers[1 - currColorIndex].Count != 0) //if the first side was checking the second side { foreach (int index in c.getDict(currColorIndex == 0)[pieceIndex.ALL_LOCATIONS].getTrueIndicies()) { retVal.Add(index); } } else { foreach (int index in c.getDict(currColorIndex == 0)[pieceIndex.ALL_LOCATIONS].getTrueIndicies()) { BitboardLayer valAttack = new BitboardLayer(currAttackedSquares[currColorIndex][index].getLayerData() | currValidMoves[currColorIndex][index].getLayerData()); //BitboardLayer valAttack = new BitboardLayer(currAttackedSquares[consideredIndex][index].getLayerData() | currValidMoves[consideredIndex][index].getLayerData()); foreach (int changedIndex in changedIndicies.getTrueIndicies()) { if (valAttack.trueAtIndex(changedIndex)) retVal.Add(index); //was attacking (opposite color) } //if (valAttack.trueAtIndex(c.getDict(isWhite)[pieceIndex.KING].getTrueIndicies()[0])) retVal.Add(index); //is checking (opposite color) } } foreach (List<int[]> pinList in currPinnedPcs) { foreach (int[] pin in pinList) { retVal.Add(pin[0]); retVal.Add(pin[1]); } } retVal.Add(lastMove[1]); foreach (int i in changedIndicies.getTrueIndicies()) { retVal.Add(i); } int[] arrayForm = new int[retVal.Count]; retVal.CopyTo(arrayForm); return arrayForm; } */ //updates both black and white's attacked squares public void updatePosition(bool isWhite, int[] move) { int colorIndex = isWhite ? 0 : 1; int oppositeColorIndex = isWhite ? 1 : 0; //get changed indices before we update all locations int[] changedIndicies = getChangedIndices(isWhite, move); pieceLocations[colorIndex] = c.getDict(isWhite)[pieceIndex.ALL_LOCATIONS]; /* int oldLocation = move[0]; currAttackedSquares[colorIndex][oldLocation] = new BitboardLayer(); */ for (int i = 0; i < 2; i++) { kingAttackedSquares[i] = new BitboardLayer(); currCheckers[i] = new List<int[]>(); currPinnedPcs[i] = new List<int[]>(); } //if move was a capture, nullify all valid moves and attacked squares //pins and checks are cleared and re-revaluated every move, so no need to directly nullify them if (pieceLocations[oppositeColorIndex].trueAtIndex(move[1])) { currValidMoves[oppositeColorIndex][move[1]] = new BitboardLayer(); currAttackedSquares[oppositeColorIndex][move[1]] = new BitboardLayer(); } BitboardLayer allOccupiedSquares = new BitboardLayer(c.getDict(true)[pieceIndex.ALL_LOCATIONS].getLayerData() | c.getDict(false)[pieceIndex.ALL_LOCATIONS].getLayerData()); bool ftupdate = false; foreach (int location in changedIndicies) { numIterations++; /* if (numIterations == 244438) { Debug.Print("Found bug!"); } */ if (allOccupiedSquares.trueAtIndex(location)) { findAttackMove(pieceLocations[0].trueAtIndex(location), location); if (location == 57 && currValidMoves[0][57].getLayerData() == 10489856) { Debug.Print("Knight updated! New value: " + currAttackedSquares[0][52].getLayerData() + " numIterations: " + numIterations); } } else { for (int i = 0; i < 2; i++) { currAttackedSquares[i][location] = new BitboardLayer(); currValidMoves[i][location] = new BitboardLayer(); } } //update valid moves and attacked squares for piece at location } foreach (int[] pin in currPinnedPcs[colorIndex]) { //format: pinner, pinned piece, interval ulong vMoveLayer = 0uL; for (int i = pin[0]; checkCollision(oppositeColorIndex == 1, i) != 3; i += pin[2]) { vMoveLayer |= 1uL << (63 - i); } currValidMoves[oppositeColorIndex][pin[1]].setLayerData(currValidMoves[oppositeColorIndex][pin[1]].getLayerData() & vMoveLayer); } foreach (int[] pin in currPinnedPcs[oppositeColorIndex]) { ulong vMoveLayer = 0uL; for (int i = pin[0]; checkCollision(colorIndex == 1, i) != 3; i += pin[2]) { vMoveLayer |= 1uL << (63 - i); } currValidMoves[colorIndex][pin[1]].setLayerData(currValidMoves[oppositeColorIndex][pin[1]].getLayerData() & vMoveLayer); } //get all attacked squares so we can get king's valid moves for (int i = 0; i < 2; i++) { ulong fullAttackedSq = 0; foreach(BitboardLayer pieceAttackedSq in currAttackedSquares[i]) { fullAttackedSq |= pieceAttackedSq.getLayerData(); } allAttackedSq[i] = new BitboardLayer(fullAttackedSq); } //to make sure only valid moves are considered, bitwise-AND each non-king's valid moves with position of each piece attacking the king and their attack vector //if double-checked, this makes sure no positions will show up //otherwise will automatically limit to capture or block for (int i = 0; i < 2; i++) { int kingPos = c.getDict(i == 1)[pieceIndex.KING].getTrueIndicies()[0]; //if opponent is checking, limit valid moves foreach (int[] checker in currCheckers[1 - i]) { ulong vMoveMask = 0; for (int j = checker[0]; checkCollision(i == 1, j) != 3; j += checker[1]) { vMoveMask |= 1uL << (63 - j); } for(int j = 0; j < 64; j++) { currValidMoves[i][j].setLayerData(currValidMoves[i][j].getLayerData() & vMoveMask); } } //limit king's valid moves BitboardLayer kingVMoves = new BitboardLayer(currAttackedSquares[i][kingPos].getLayerData()); foreach (int possibleMove in kingVMoves.getTrueIndicies()) { if (checkCollision(i == 0, i) == 2) kingVMoves.setAtIndex(possibleMove, false); if (allAttackedSq[1 - i].trueAtIndex(possibleMove)) kingVMoves.setAtIndex(possibleMove, false); if (kingAttackedSquares[1 - i].trueAtIndex(possibleMove)) kingVMoves.setAtIndex(possibleMove, false); } //castling if (canCastle[i][1] && !allAttackedSq[1 - i].trueAtIndex(kingPos + 1) && !allAttackedSq[1 - i].trueAtIndex(kingPos + 2)) //can castle right { kingVMoves.setAtIndex(kingPos + 2, true); } if (canCastle[i][0] && !allAttackedSq[1 - i].trueAtIndex(kingPos - 1) && !allAttackedSq[1 - i].trueAtIndex(kingPos - 2)) { kingVMoves.setAtIndex(kingPos - 2, true); } currValidMoves[i][kingPos] = new BitboardLayer(kingVMoves); } for (int i = 0; i < 2; i++) { ulong fullValidMoves = 0; foreach (BitboardLayer pieceValidMoves in currValidMoves[i]) { fullValidMoves |= pieceValidMoves.getLayerData(); pieceValidMoves.setAtIndex(c.getDict(i == 1)[pieceIndex.KING].getTrueIndicies()[0], false); } allValidMoves[i] = new BitboardLayer(fullValidMoves); } }