SebLague / Chess-Challenge

Create your own tiny chess bot!
https://www.youtube.com/watch?v=Ne40a5LkK6A
MIT License
1.77k stars 1.06k forks source link

Is it possible to check if a piece is protecting a pawn? #176

Closed YesilHiyar closed 1 year ago

YesilHiyar commented 1 year ago

Self-explanatory, the code i have so far is:

PieceList pieces = board.GetPieceList(PieceType.Pawn, piece.IsWhitePieceList);

for (int index = 0; index < pieces.Count(); index++)
{
    Piece pawn = pieces.GetPiece(index);

    if (ChessChallenge.Chess.BitBoardUtility.ContainsSquare(pieceBitboard, pawn.Square.Index))
    {
        Console.WriteLine("Supporting pieces!");
        extraMg += 75;
        extraEg += 75;
    }
}

extraMg and extraEg are a way of keeping score and the value 75 has 0 correlation, the console does not print "Supporting pieces!" either. (which it should)

Jakabi107 commented 1 year ago

I don't get what you mean with protecting a pawn. Could you descripe it a litle bit thurter? I would really like to help you!

And becuase your snippet is not working properly but, firstly pieces.Count is not a method but a variable so it wont work if you call it. After this change it worked flawlessly (Expect I had to define the "piece" and "pieceBitboard" variable as you don't set them in the snippet). If I doesn't work with this change you may have taken the wrong bitboard - it should match the colour from the piece or conatin both.

Jakabi107 commented 1 year ago

Note - my Code:

    public Move Think(Board board, Timer timer)
    {   
        // set true for testing purpose - in your case would be piece.IsWhite - (there is also no IsWhitePieceList method which class do you use?)
        PieceList pieces = board.GetPieceList(PieceType.Pawn, true);

        // used foreach to not have define the pawn extra (less Tokens)
        foreach (Piece pawn in pieces)
        {
                 if (ChessChallenge.Chess.BitBoardUtility.ContainsSquare(board.AllPiecesBitboard, pawn.Square.Index)) {
                 Console.WriteLine("Supporting pieces!");
                 }
        }

        return board.GetLegalMoves()[0];
    }
YesilHiyar commented 1 year ago

I want to basically check if a pawn is protecting another pawn, if so reward that.

YesilHiyar commented 1 year ago

also literally did not realize count was not a method, i have no idea how it did not error.

YesilHiyar commented 1 year ago

Also your solution worked thank you

Jakabi107 commented 1 year ago

I have came up with this Idea - It requires around 80 Tokens without the base (built in your algorithem propably a little bit less) and a Time complexity of approximitly O( p(2n) ) where p are number of pawns and n are number of possible captures. I have optimised it as much as I can.

It basicly looks how many captures are possible before your move. Then it checks for each pawn move if the possible captures contains the pos the pawn would move to - to ensure he "sacrifices" and if the count of captures stayed at least the same (to determine if he actually safed someone). It protects every piece so not only other pawns but also the others pieces. It would quite an amount of extra calculation to only protect them. I hope that's okay. Also it doesn't work while check but it shouldn't be a problem as you are forced to protect the king anyways.

I've made two versions. One safes 7 Tokens but I'm not sure if it increases Time Complexity a little bit(but I think it doesn't...) and where I'm sure. I'll append them.

PS: The version I sent you wasn't a working one but just fixing your errors in the snippet...

Jakabi107 commented 1 year ago

Solution Token effezient:

  public Move Think(Board board, Timer timer)
  {
    Boolean iAmWhite = board.IsWhiteToMove;

    int possibleCapturesBeforeInt = 0;
    // trying to Skip turn - fails when you are check 
    if (board.TrySkipTurn())
    {
      // calculating how many captures your opponennt could make without move
      possibleCapturesBeforeInt = board.GetLegalMoves(true).Length;
      board.UndoSkipTurn();
    }

    // make your move with the pawn eg.
    foreach (Move move in board.GetLegalMoves())
    {
      board.MakeMove(move);

      // checks if pawn so only they protect other pieces
      if (move.MovePieceType == PieceType.Pawn)
      {
        // checks if self could be captured but amount of captures doesn't increases
        // what means that he secured at least one other piece
        if (board.GetLegalMoves(true).Any(moveOpponent => moveOpponent.TargetSquare == move.TargetSquare)
          && board.GetLegalMoves(true).Length <= possibleCapturesBeforeInt)
        {
          // give points :)
          System.Console.WriteLine("Supporting pieces!");
          return move;
        }
      }
      board.UndoMove(move);
    }

    return board.GetLegalMoves()[0];
  }
Jakabi107 commented 1 year ago

Sloution (not quite sure) more time effizient:

  public Move Think(Board board, Timer timer)
  {
    Boolean iAmWhite = board.IsWhiteToMove;

    int possibleCapturesBeforeInt = 0;
    // trying to Skip turn - fails when you are check

    if (board.TrySkipTurn())
    {
      // calculating how many captures your opponennt could make without move
      possibleCapturesBeforeInt = board.GetLegalMoves(true).Length;
      board.UndoSkipTurn();
    }

    // make your move with the pawn eg.
    foreach (Move move in board.GetLegalMoves())
    {
      board.MakeMove(move);

      // checks if pawn so only they protect other pieces
      if (move.MovePieceType == PieceType.Pawn)
      {
        // checks out how pieces that could be captured now
        Square[] possibleCapturesNow = board.GetLegalMoves(true).Select(move => move.TargetSquare).ToArray();

        // checks if self could be captured but amount of captures doesn't increases
        // what means that he secured at least one other piece
        if (possibleCapturesNow.Contains(move.TargetSquare)
          && possibleCapturesNow.Length <= possibleCapturesBeforeInt)
        {
          // give points :)
          System.Console.WriteLine("Supporting pieces!");
          return move;
        }
      }
      board.UndoMove(move);
    }

    return board.GetLegalMoves()[0];
  }
Jakabi107 commented 1 year ago

Oh and make sure to write using System.Linq; at the begining as I use comments from there.

Jakabi107 commented 1 year ago

And you have to keep care of what namespaces you are using: Quote from (Docs): Only the following namespaces are allowed: ChessChallenge.API System System.Numerics System.Collections.Generic System.Linq You may not use the AsParallel() function

Because your where using ChessChallenge.Chess.BitBoardUtility.ContainsSquare in your project which isn't included in this list.

Thank you for bringing up this problem, had quite a bit fun solving it the best and most effizient way :)