/// <summary> /// Increments a killers count at the specified depth. /// </summary> /// <param name="color">The killer color.</param> /// <param name="depth">The killer depth.</param> /// <param name="move">The killer move.</param> public void AddKiller(Color color, int depth, Move move) { var fromIndex = BitPositionConverter.ToBitIndex(move.From); var toIndex = BitPositionConverter.ToBitIndex(move.To); _table[(int)color][fromIndex][toIndex] += depth * depth; }
/// <summary> /// Adds en passant to Zobrist hash. /// </summary> /// <param name="color">The piece color.</param> /// <param name="field">The field bitboard.</param> /// <param name="bitboard">The bitboard.</param> public static void AddEnPassant(Color color, ulong field, Bitboard bitboard) { var fieldIndex = BitOperations.GetBitIndex(field); var fieldPosition = BitPositionConverter.ToPosition(fieldIndex); bitboard.Hash ^= ZobristContainer.EnPassant[fieldPosition.X - 1]; }
/// <summary> /// Gets the killers count for the specified move. /// </summary> /// <param name="move">The move</param> /// <returns>The killers count for the specified move.</returns> public int GetKillersCount(Move move) { var fromIndex = BitPositionConverter.ToBitIndex(move.From); var toIndex = BitPositionConverter.ToBitIndex(move.To); return(_table[(int)move.Color][fromIndex][toIndex]); }
/// <summary> /// Calculates a castling. /// </summary> /// <param name="bitboard">The bitboard.</param> public override void CalculateMove(Bitboard bitboard) { var from = BitPositionConverter.ToULong(From); var to = BitPositionConverter.ToULong(To); var rookFrom = 0ul; var rookTo = 0ul; switch (CastlingType) { case CastlingType.Short: { rookFrom = Color == Color.White ? CastlingConstants.InitialRightRookBitboard : CastlingConstants.InitialRightRookBitboard << 56; rookTo = rookFrom << 2; break; } case CastlingType.Long: { rookFrom = Color == Color.White ? CastlingConstants.InitialLeftRookBitboard : CastlingConstants.InitialLeftRookBitboard << 56; rookTo = rookFrom >> 3; break; } } CalculatePieceMove(bitboard, from, to); CalculatePieceMove(bitboard, PieceType.Rook, rookFrom, rookTo); RemoveCastlingPossibility(bitboard); bitboard.ReversibleMoves = 0; }
/// <summary> /// Calculates a quiet move. /// </summary> /// <param name="bitboard">The bitboard.</param> public override void CalculateMove(Bitboard bitboard) { var from = BitPositionConverter.ToULong(From); var to = BitPositionConverter.ToULong(To); CalculatePieceMove(bitboard, from, to); CalculateEnPassant(bitboard); }
/// <summary> /// Calculates en passant move. /// </summary> /// <param name="bitboard">The bitboard.</param> public override void CalculateMove(Bitboard bitboard) { var from = BitPositionConverter.ToULong(From); var to = BitPositionConverter.ToULong(To); var enemyColor = ColorOperations.Invert(Color); RemoveEnPassantPiece(bitboard, enemyColor, to); CalculatePieceMove(bitboard, from, to); }
/// <summary> /// Gets a pieces array (for bitboards). /// </summary> /// <returns>The pieces array.</returns> public ulong[] GetPiecesArray() { var pieces = new ulong[12]; foreach (var piece in Pieces) { var bitPosition = BitPositionConverter.ToULong(piece.Position); pieces[FastArray.GetPieceIndex(piece.Color, piece.Type)] |= bitPosition; } return(pieces); }
/// <summary> /// Calculates diagonal attacks (and moves if possible). /// </summary> /// <param name="leftAttackShift">The left attack shift.</param> /// <param name="rightAttackShift">The right attacks shift.</param> /// <param name="ignoreFields">The bitboard with fields to ignore (white and black pieces will have different ones).</param> /// <param name="opt">The generator parameters.</param> private static void CalculateDiagonalAttacks(int leftAttackShift, int rightAttackShift, ulong ignoreFields, GeneratorParameters opt) { var piecesToParse = opt.Bitboard.Pieces[FastArray.GetPieceIndex(opt.FriendlyColor, PieceType.Pawn)]; var validPieces = piecesToParse & ~ignoreFields; var pattern = opt.FriendlyColor == Color.White ? validPieces << leftAttackShift : validPieces >> rightAttackShift; var promotionLine = GetPromotionLine(opt.FriendlyColor); while (pattern != 0) { var patternLSB = BitOperations.GetLSB(pattern); pattern = BitOperations.PopLSB(pattern); var patternIndex = BitOperations.GetBitIndex(patternLSB); var pieceLSB = opt.FriendlyColor == Color.White ? patternLSB >> leftAttackShift : patternLSB << rightAttackShift; var pieceIndex = BitOperations.GetBitIndex(pieceLSB); if ((opt.Mode & GeneratorMode.CalculateMoves) != 0) { var piecePosition = BitPositionConverter.ToPosition(pieceIndex); var enPassantField = opt.Bitboard.EnPassant[(int)opt.EnemyColor] & patternLSB; if ((patternLSB & opt.EnemyOccupancy) != 0 || enPassantField != 0) { var to = BitPositionConverter.ToPosition(patternIndex); if (enPassantField != 0) { opt.Bitboard.Moves.AddLast(new EnPassantMove(piecePosition, to, PieceType.Pawn, opt.FriendlyColor)); } else if ((patternLSB & promotionLine) != 0) { opt.Bitboard.Moves.AddLast(new PromotionMove(piecePosition, to, PieceType.Pawn, opt.FriendlyColor, PieceType.Queen, true)); opt.Bitboard.Moves.AddLast(new PromotionMove(piecePosition, to, PieceType.Pawn, opt.FriendlyColor, PieceType.Rook, true)); opt.Bitboard.Moves.AddLast(new PromotionMove(piecePosition, to, PieceType.Pawn, opt.FriendlyColor, PieceType.Bishop, true)); opt.Bitboard.Moves.AddLast(new PromotionMove(piecePosition, to, PieceType.Pawn, opt.FriendlyColor, PieceType.Knight, true)); } else { opt.Bitboard.Moves.AddLast(new KillMove(piecePosition, to, PieceType.Pawn, opt.FriendlyColor)); } } } if ((opt.Mode & GeneratorMode.CalculateAttacks) != 0) { opt.Bitboard.Attacks[patternIndex] |= pieceLSB; opt.Bitboard.AttacksSummary[(int)opt.FriendlyColor] |= patternLSB; } } }
/// <summary> /// Calculates en passant fields if current piece type is pawn. /// </summary> /// <param name="bitboard">The bitboard.</param> private void CalculateEnPassant(Bitboard bitboard) { if (Piece == PieceType.Pawn) { var enPassantPosition = GetEnPassantPosition(); if (enPassantPosition.HasValue) { var enPassantLSB = BitPositionConverter.ToULong(enPassantPosition.Value); bitboard.EnPassant[(int)Color] |= enPassantLSB; IncrementalZobrist.AddEnPassant(Color, enPassantLSB, bitboard); } } }
/// <summary> /// Gets a en passant position from the specified bitboard. /// </summary> /// <param name="enPassant">The en passant bitboard.</param> /// <returns>The en passant position (null if en passant bitboard is equal to zero)</returns> private Position?GetEnPassantPosition(ulong enPassant) { if (enPassant == 0) { return(null); } var lsb = BitOperations.GetLSB(enPassant); BitOperations.PopLSB(enPassant); var bitIndex = BitOperations.GetBitIndex(lsb); return(BitPositionConverter.ToPosition(bitIndex)); }
/// <summary> /// Clears en passant from Zobrist hash. /// </summary> /// <param name="color">The piece color.</param> /// <param name="bitboard">The bitboard.</param> public static void ClearEnPassant(Color color, Bitboard bitboard) { var enPassantToParse = bitboard.EnPassant[(int)color]; while (enPassantToParse != 0) { var fieldLSB = BitOperations.GetLSB(enPassantToParse); enPassantToParse = BitOperations.PopLSB(enPassantToParse); var fieldIndex = BitOperations.GetBitIndex(fieldLSB); var fieldPosition = BitPositionConverter.ToPosition(fieldIndex); bitboard.Hash ^= ZobristContainer.EnPassant[fieldPosition.X - 1]; } }
/// <summary> /// Calculates a promotion move. /// </summary> /// <param name="bitboard">The bitboard.</param> public override void CalculateMove(Bitboard bitboard) { var from = BitPositionConverter.ToULong(From); var to = BitPositionConverter.ToULong(To); if (KillMove) { CalculateKill(bitboard, ColorOperations.Invert(Color), to); } CalculatePieceMove(bitboard, Piece, from, PromotionPiece, to); IncrementalMaterial.RemovePiece(bitboard, Color, Piece); IncrementalMaterial.AddPiece(bitboard, Color, PromotionPiece); }
/// <summary> /// Calculates moves for the specified piece. /// </summary> /// <param name="pieceType">The piece type.</param> /// <param name="pieceBitboard">The bitboard with set bit at piece position.</param> /// <param name="opt">The generator parameters.</param> /// <returns>The bitboard with available moves for the specified piece.</returns> private static ulong CalculateMoves(PieceType pieceType, ulong pieceBitboard, GeneratorParameters opt) { if ((opt.Mode & GeneratorMode.CalculateMoves) == 0) { return(0); } var pieceIndex = BitOperations.GetBitIndex(pieceBitboard); var piecePosition = BitPositionConverter.ToPosition(pieceIndex); var pattern = MagicContainer.GetRookAttacks(pieceIndex, opt.OccupancySummary); pattern &= ~opt.FriendlyOccupancy; if (opt.QuiescenceSearch) { pattern &= opt.EnemyOccupancy; } var excludeFromAttacks = pattern; while (pattern != 0) { var patternLSB = BitOperations.GetLSB(pattern); pattern = BitOperations.PopLSB(pattern); var patternIndex = BitOperations.GetBitIndex(patternLSB); var to = BitPositionConverter.ToPosition(patternIndex); if ((patternLSB & opt.EnemyOccupancy) == 0) { opt.Bitboard.Moves.AddLast(new QuietMove(piecePosition, to, pieceType, opt.FriendlyColor)); } else { opt.Bitboard.Moves.AddLast(new KillMove(piecePosition, to, pieceType, opt.FriendlyColor)); } if ((opt.Mode & GeneratorMode.CalculateAttacks) != 0) { opt.Bitboard.Attacks[patternIndex] |= pieceBitboard; opt.Bitboard.AttacksSummary[(int)opt.FriendlyColor] |= patternLSB; } } return(excludeFromAttacks); }
/// <summary> /// Gets a en passant array (for bitboards). /// </summary> /// <returns>The en passant array.</returns> public ulong[] GetEnPassantArray() { var enPassant = new ulong[2]; if (EnPassant.WhiteEnPassant != null) { enPassant[(int)Color.White] = BitPositionConverter.ToULong(EnPassant.WhiteEnPassant.Value); } if (EnPassant.BlackEnPassant != null) { enPassant[(int)Color.Black] = BitPositionConverter.ToULong(EnPassant.BlackEnPassant.Value); } return(enPassant); }
/// <summary> /// Calculates pattern for the specified field and shift. /// </summary> /// <param name="fieldIndex">The index field.</param> /// <param name="shift">The shift (the direction in which the calculating is made).</param> /// <returns>The pattern for the specified field.</returns> public ulong CalculatePattern(int fieldIndex, Position shift) { var attacks = 0ul; var currentPosition = BitPositionConverter.ToPosition(fieldIndex); currentPosition += shift; while (currentPosition.IsValid()) { var positionBitIndex = BitPositionConverter.ToBitIndex(currentPosition); var bit = 1ul << positionBitIndex; attacks |= bit; currentPosition += shift; } return(attacks); }
/// <summary> /// Calculates X-Ray attacks when friendly pawn is on bishop way. /// </summary> /// <param name="pieceIndex">The field index with the specified bishop.</param> /// <param name="pattern">The bishop moves pattern.</param> /// <param name="opt">The generator parameters.</param> /// <returns>The attacks bitboard with pawn X-Ray attacks.</returns> private static ulong CalculatePawnBlockers(int pieceIndex, ulong pattern, GeneratorParameters opt) { var patternWithFriendlyBlockers = pattern; var allowedBlockers = opt.Bitboard.Pieces[FastArray.GetPieceIndex(opt.FriendlyColor, PieceType.Pawn)]; var piecePosition = BitPositionConverter.ToPosition(pieceIndex); var friendlyBlockers = pattern & opt.FriendlyOccupancy & allowedBlockers; while (friendlyBlockers != 0) { var friendlyBlockerLSB = BitOperations.GetLSB(friendlyBlockers); friendlyBlockers = BitOperations.PopLSB(friendlyBlockers); var friendlyBlockerIndex = BitOperations.GetBitIndex(friendlyBlockerLSB); var friendlyBlockerPosition = BitPositionConverter.ToPosition(friendlyBlockerIndex); switch (opt.FriendlyColor) { case Color.White when friendlyBlockerPosition.X > piecePosition.X && friendlyBlockerPosition.Y > piecePosition.Y && (friendlyBlockerLSB & (BitConstants.HFile | BitConstants.HRank)) == 0: { patternWithFriendlyBlockers |= friendlyBlockerLSB << 7; break; } case Color.White when friendlyBlockerPosition.X <piecePosition.X && friendlyBlockerPosition.Y> piecePosition.Y && (friendlyBlockerLSB & (BitConstants.AFile | BitConstants.HRank)) == 0: { patternWithFriendlyBlockers |= friendlyBlockerLSB << 9; break; } case Color.Black when friendlyBlockerPosition.X > piecePosition.X && friendlyBlockerPosition.Y < piecePosition.Y && (friendlyBlockerLSB & (BitConstants.HFile | BitConstants.ARank)) == 0: { patternWithFriendlyBlockers |= friendlyBlockerLSB >> 9; break; } case Color.Black when friendlyBlockerPosition.X < piecePosition.X && friendlyBlockerPosition.Y < piecePosition.Y && (friendlyBlockerLSB & (BitConstants.AFile | BitConstants.ARank)) == 0: { patternWithFriendlyBlockers |= friendlyBlockerLSB >> 7; break; } } } return(patternWithFriendlyBlockers); }
/// <summary> /// Generates rook patterns for every field. /// </summary> /// <returns>The 64-element array with patterns.</returns> public ulong[] Generate() { var predefinedMoves = new ulong[64]; for (var i = 0; i < 64; i++) { var fieldBit = 1ul << i; var position = BitPositionConverter.ToPosition(i); var filePattern = GetFilePattern(position) & ~BitConstants.TopBottomEdge; var rankPattern = GetRankPattern(position) & ~BitConstants.RightLeftEdge; predefinedMoves[i] = ~fieldBit & (filePattern | rankPattern); } return(predefinedMoves); }
/// <summary> /// Generates available moves for the specified bitboard and shift. /// </summary> /// <param name="initialFieldIndex">The initial field index.</param> /// <param name="occupancy">The bitboard occupancy.</param> /// <param name="shift">The shift (direction of available moves generating).</param> /// <returns>The available moves bitboard (where 1 means possible position, otherwise 0).</returns> public ulong Calculate(int initialFieldIndex, ulong occupancy, Position shift) { var attacks = 0ul; var bit = 0ul; var currentPosition = BitPositionConverter.ToPosition(initialFieldIndex); currentPosition += shift; while (currentPosition.IsValid() && (bit & occupancy) == 0) { var positionBitIndex = BitPositionConverter.ToBitIndex(currentPosition); bit = 1ul << positionBitIndex; attacks |= bit; currentPosition += shift; } return(attacks); }
/// <summary> /// Generates available moves. /// </summary> /// <param name="opt">The generator parameters.</param> public static void Generate(GeneratorParameters opt) { var piecesToParse = opt.Bitboard.Pieces[FastArray.GetPieceIndex(opt.FriendlyColor, PieceType.Knight)]; while (piecesToParse != 0) { var pieceLSB = BitOperations.GetLSB(piecesToParse); piecesToParse = BitOperations.PopLSB(piecesToParse); var pieceIndex = BitOperations.GetBitIndex(pieceLSB); var piecePosition = BitPositionConverter.ToPosition(pieceIndex); var pattern = PatternsContainer.KnightPattern[pieceIndex]; while (pattern != 0) { var patternLSB = BitOperations.GetLSB(pattern); pattern = BitOperations.PopLSB(pattern); var patternIndex = BitOperations.GetBitIndex(patternLSB); if ((opt.Mode & GeneratorMode.CalculateMoves) != 0 && (patternLSB & opt.FriendlyOccupancy) == 0) { var to = BitPositionConverter.ToPosition(patternIndex); if ((patternLSB & opt.EnemyOccupancy) == 0 && !opt.QuiescenceSearch) { opt.Bitboard.Moves.AddLast(new QuietMove(piecePosition, to, PieceType.Knight, opt.FriendlyColor)); } else if ((patternLSB & opt.EnemyOccupancy) != 0) { opt.Bitboard.Moves.AddLast(new KillMove(piecePosition, to, PieceType.Knight, opt.FriendlyColor)); } } if ((opt.Mode & GeneratorMode.CalculateAttacks) != 0) { opt.Bitboard.Attacks[patternIndex] |= pieceLSB; opt.Bitboard.AttacksSummary[(int)opt.FriendlyColor] |= patternLSB; } } } }
/// <summary> /// Calculates double push moves. /// </summary> /// <param name="opt">The generator parameters.</param> private static void CalculateMovesForDoublePush(GeneratorParameters opt) { if ((opt.Mode & GeneratorMode.CalculateMoves) == 0 || opt.QuiescenceSearch) { return; } var piecesToParse = opt.Bitboard.Pieces[FastArray.GetPieceIndex(opt.FriendlyColor, PieceType.Pawn)]; ulong validPieces; ulong pattern; if (opt.FriendlyColor == Color.White) { validPieces = piecesToParse & BitConstants.BRank; validPieces &= ~opt.OccupancySummary >> 8; pattern = validPieces << 16; } else { validPieces = piecesToParse & BitConstants.GRank; validPieces &= ~opt.OccupancySummary << 8; pattern = validPieces >> 16; } pattern &= ~opt.OccupancySummary; while (pattern != 0) { var patternLSB = BitOperations.GetLSB(pattern); pattern = BitOperations.PopLSB(pattern); var patternIndex = BitOperations.GetBitIndex(patternLSB); var pieceLSB = opt.FriendlyColor == Color.White ? patternLSB >> 16 : patternLSB << 16; var pieceIndex = BitOperations.GetBitIndex(pieceLSB); var from = BitPositionConverter.ToPosition(pieceIndex); var to = BitPositionConverter.ToPosition(patternIndex); opt.Bitboard.Moves.AddLast(new QuietMove(from, to, PieceType.Pawn, opt.FriendlyColor)); } }
/// <summary> /// Initializes a new instance of the <see cref="FriendlyAttacksList"/> class. /// </summary> /// <param name="attacks">The array of attack bitboards (where index means field index (source piece position), /// and set bits are the destination attack positions.</param> /// <param name="pieces">The list of pieces.</param> public FriendlyAttacksList(ulong[] attacks, FriendlyPiecesList pieces) { for (var i = 0; i < 64; i++) { var fieldAttackers = attacks[i]; var targetPosition = BitPositionConverter.ToPosition(i); while (fieldAttackers != 0) { var attackerLSB = BitOperations.GetLSB(fieldAttackers); fieldAttackers = BitOperations.PopLSB(fieldAttackers); var attackerIndex = BitOperations.GetBitIndex(attackerLSB); var attackerPosition = BitPositionConverter.ToPosition(attackerIndex); var attackerColor = pieces.First(p => p.Position == attackerPosition).Color; Add(new FriendlyAttack(attackerColor, attackerPosition, targetPosition)); } } }
/// <summary> /// Calculates Zobrist hash for en passant. /// </summary> /// <param name="hash">The current hash.</param> /// <param name="enPassant">The array of en passant.</param> /// <returns>The updated Zobrist hash.</returns> private static ulong CalculateEnPassant(ulong hash, ulong[] enPassant) { for (var colorIndex = 0; colorIndex < 2; colorIndex++) { var enPassantToParse = enPassant[colorIndex]; while (enPassantToParse != 0) { var pieceLSB = BitOperations.GetLSB(enPassantToParse); enPassantToParse = BitOperations.PopLSB(enPassantToParse); var fieldIndex = BitOperations.GetBitIndex(pieceLSB); var fieldPosition = BitPositionConverter.ToPosition(fieldIndex); hash ^= ZobristContainer.EnPassant[fieldPosition.X - 1]; } } return(hash); }
/// <summary> /// Calculates single push moves. /// </summary> /// <param name="opt">The generator parameters.</param> private static void CalculateMovesForSinglePush(GeneratorParameters opt) { if ((opt.Mode & GeneratorMode.CalculateMoves) == 0) { return; } var piecesToParse = opt.Bitboard.Pieces[FastArray.GetPieceIndex(opt.FriendlyColor, PieceType.Pawn)]; var promotionLine = GetPromotionLine(opt.FriendlyColor); var pattern = opt.FriendlyColor == Color.White ? piecesToParse << 8 : piecesToParse >> 8; pattern &= ~opt.OccupancySummary; while (pattern != 0) { var patternLSB = BitOperations.GetLSB(pattern); pattern = BitOperations.PopLSB(pattern); var patternIndex = BitOperations.GetBitIndex(patternLSB); var pieceLSB = opt.FriendlyColor == Color.White ? patternLSB >> 8 : patternLSB << 8; var pieceIndex = BitOperations.GetBitIndex(pieceLSB); var from = BitPositionConverter.ToPosition(pieceIndex); var to = BitPositionConverter.ToPosition(patternIndex); if ((patternLSB & promotionLine) == 0 && !opt.QuiescenceSearch) { opt.Bitboard.Moves.AddLast(new QuietMove(from, to, PieceType.Pawn, opt.FriendlyColor)); } else if ((patternLSB & promotionLine) != 0) { opt.Bitboard.Moves.AddLast(new PromotionMove(from, to, PieceType.Pawn, opt.FriendlyColor, PieceType.Queen, false)); opt.Bitboard.Moves.AddLast(new PromotionMove(from, to, PieceType.Pawn, opt.FriendlyColor, PieceType.Rook, false)); opt.Bitboard.Moves.AddLast(new PromotionMove(from, to, PieceType.Pawn, opt.FriendlyColor, PieceType.Bishop, false)); opt.Bitboard.Moves.AddLast(new PromotionMove(from, to, PieceType.Pawn, opt.FriendlyColor, PieceType.Knight, false)); } } }
/// <summary> /// Initializes a new instance of the <see cref="FriendlyPiecesList"/> class. /// </summary> /// <param name="pieces">The array of pieces.</param> public FriendlyPiecesList(ulong[] pieces) { for (var i = 0; i < 12; i++) { var pieceArray = pieces[i]; while (pieceArray != 0) { var lsb = BitOperations.GetLSB(pieceArray); pieceArray = BitOperations.PopLSB(pieceArray); var bitIndex = BitOperations.GetBitIndex(lsb); var position = BitPositionConverter.ToPosition(bitIndex); var pieceType = (PieceType)(i % 6); var pieceColor = (Color)(i / 6); Add(new FriendlyPiece(position, pieceType, pieceColor)); } } }
/// <summary> /// Calculates SEE for the specified field and initial attacker. /// </summary> /// <param name="field">The field to analyze.</param> /// <param name="initialAttacker">The initial attacker.</param> /// <param name="attackers">The bitboard with all attackers that will be a part of SEE.</param> /// <param name="initialColor">The color of the first attacker.</param> /// <param name="bitboard">The bitboard.</param> /// <returns>The SEE result with the score and other data.</returns> private SEEResult CalculateScoreForField(ulong field, ulong initialAttacker, ulong attackers, Color initialColor, Bitboard bitboard) { var enemyColor = ColorOperations.Invert(initialColor); var seeResult = new SEEResult { InitialAttackerFrom = BitPositionConverter.ToPosition(BitOperations.GetBitIndex(initialAttacker)), InitialAttackerTo = BitPositionConverter.ToPosition(BitOperations.GetBitIndex(field)), InitialAttackerType = GetPieceType(initialAttacker, initialColor, bitboard), AttackedPieceType = GetPieceType(field, enemyColor, bitboard) }; seeResult.Score = MaterialValues.PieceValues[(int)seeResult.AttackedPieceType]; attackers &= ~initialAttacker; var currentColor = enemyColor; var currentSign = -1; var currentPieceOnField = seeResult.InitialAttackerType; while (attackers != 0) { var leastValuablePieceType = GetAndPopLeastValuablePiece(ref attackers, currentColor, bitboard); if (!leastValuablePieceType.HasValue) { break; } seeResult.Score += currentSign * MaterialValues.PieceValues[(int)currentPieceOnField]; currentPieceOnField = leastValuablePieceType.Value; currentColor = ColorOperations.Invert(currentColor); currentSign *= -1; } return(seeResult); }