public PawnPosition GetPXP(Position position) { PXPMemo.Counts.GetReads++; var qHashPawn = position.HashPawn; var found = PXPMemo[qHashPawn]; #if PawnPositionByValue var bDefault = (found.BlackPRP & PRPFlags.IsValid) == 0; #else var bDefault = found == default(PawnPosition); #endif if (!bDefault && found.HashPawn == qHashPawn) { PXPMemo.Counts.GetHits++; // Match, a.k.a. Get Hit return(found); } // // Position instance contains the specific Pawn configuration. // // Passer weight could be optimized out where PawnFeature Delta // is much less than the StaticDelta returned by staticEval(). // // Wrong Bishops will be determined by Passed Rook Pawns. // var uBlackCount = position.CountPawnFeatures(Black, out Plane qpBlackPassers, out PRPFlags fBlackPRP); var uWhiteCount = position.CountPawnFeatures(White, out Plane qpWhitePassers, out PRPFlags fWhitePRP); #if PawnPositionByValue if (bDefault) { PXPMemo.Counts.Added++; // Non-Match Case: Add new PawnPosition } found = new PawnPosition(qHashPawn, fBlackPRP, fWhitePRP, uBlackCount, uWhiteCount, qpBlackPassers, qpWhitePassers); PXPMemo[qHashPawn] = found; return(found); #else // PawnPositionByValue if (bDefault) { PXPMemo.Counts.Added++; // Non-Match Case: Add new PawnPosition found = new PawnPosition(qHashPawn, fBlackPRP, fWhitePRP, uBlackCount, uWhiteCount, qpBlackPassers, qpWhitePassers); PXPMemo[qHashPawn] = found; return(found); } else { found.Recycle(qHashPawn, fBlackPRP, fWhitePRP, uBlackCount, uWhiteCount, qpBlackPassers, qpWhitePassers); return(found); } #endif }
// //[ToDo]Add evaluation of practical Draws where helpmate is possible: // // KKNN or KNKNN // KBKB opposite color // KNKBN, KBKBN. KBKBB pair [Note: KNKBB pair can be won; but perhaps not in 50 moves] // // More Complex Draws, assuming weaker side in time to defend: // // KKP if weaker side maintains opposition // Distant Opposition vs. Key/Critical Squares vs Corresponding or Relative Squares!? // // KBKBP of opposite color // KPKQ if P to queen on ACFH-file and sronger K too far to help // // // Development [initial move per piece, delaying heavy pieces] // Control of the Center by Pawns // Control of Squares around King // Castling and King Safety [Corner Squares] vs King Activity in the Endgame // // Rooks on Open Files // Rook or Queen on 7th [or 2nd] Rank // Protected Piece and Connected Rook Bonus // Knight Scope and Outpost [free of Pawn harrassment] // Bishop Scope [and Bad Bishop Detection] // // Bonus for Bishop with color of Promotion Square for any Passed Pawns, especially // Rook Pawns. Applies to defense and Passed Opposing Pawns, as well as to offense. // // Attack Pawn Chains at the base // Bonus for Passed Pawn Couples // // Piece Values depending on Opening, Middle, End Game Phase and Relative Advantage: // Stronger side favors [vice versa Weaker side is averse to] // Bishops of Opposite Colors in Middle Game; and Bishops of Same Color in Endgame. // // // Technical and Tablebase Draws: // KRKRP if weaker side can attain Philidor Position // // EGTB Alternatives: Syzygy by Ronald de Man, Gaviota EGTB by Miguel A. Ballicora, // Nalimov by Eugene Nalimov. Syzygy is preferred by Houdini. It is compact; but // does not provide Distance to Mate (DTM). They provide Wind-Draw-Loss (WDL) and // Distance to Zero (DTZ). // // The Syzygy 6-man EGTB is available at http://tablebase.sesse.net/syzygy, where // the (290) 3-4-5-men files require 938 MB; and (730) 6-men files require 149 GB. // protected Eval staticEval(out PawnPosition pp) //[New]~9.666 MHz vs ~13.333 MHz w/o EvalRookBehindPasser { pp = default; if (IsInsufficient()) { return(contempt()); } GameState.AtomicIncrement(ref State.TotalEvals); // vs. FullEvaluations setEndGameFlags(); if (EvalUndefined < StaticDelta) { return(StaticDelta); } // // Retrieve material balance from the Composition: // getValue(out Eval mDelta, out Eval mTotal); if (Pawn != 0) // Else PawnHash == default(Hashcode) { pp = State.GetPXP(this); mDelta += pp.Delta; mTotal += pp.Total; #if EvalWrongBishop if (punishWrongBishop(pp.BlackPRP & PRPFlags.Both, Side[Black].FlagsHi)) { mDelta += mWrongBishopWeight; // Black has Wrong Bishop } if (punishWrongBishop(pp.WhitePRP & PRPFlags.Both, Side[White].FlagsHi)) { mDelta -= mWrongBishopWeight; // White has Wrong Bishop } #endif } #if TradePieces if (mTotal > 0) { // // The following provides an incentive for the stronger // side to exchange material and for the weaker side to // avoid such exchanges. The value is Zero in an equal // position, and grows to a maximum of one centipawn if // the weaker side has been stripped of all material. // // Intuitively: Exchanges reduce the Total material but // leave the Delta unaffected; and Delta can range from // Zero to the Total. Thus, their quotient ranges from // Zero to One. // //[Note]A refinement is needed to prefer trading Pieces // over Pawns in the endgame. // var mIncentive = (Eval)(mPawnWeight * mDelta / mTotal); mDelta += mIncentive; } #endif // //[Note]staticEval() prepares StaticTotal for any isEndgame() tests // StaticTotal = mTotal; // Update for isEndgame() StaticDelta = mDelta; return(mDelta); }
public async Task Move(Client client, Room room, PawnPosition @from, PawnPosition target) { var clientRoomsResult = await this.RoomService.Status(client); var clientRooms = clientRoomsResult.Match(x => x, e => throw e); if (clientRooms.FirstOrDefault(r => r.Name == room.Name) is Room r) { var actualGame = this.ApplicationDbContext.Games.FirstOrDefault(x => x.State == GameState.InPlay && x.RoomId == room.Id); if (actualGame == null) { var items = new List <MoveJsonEntity>(); actualGame = new GameEntity { PlayerOneId = client.Id, State = GameState.InPlay, RoomId = r.Id, Moves = items }; this.ApplicationDbContext.Add(actualGame); try { await this.ApplicationDbContext.SaveChangesAsync(); } catch (Exception) { throw; } } var player = actualGame.PlayerOneId == client.Id ? Player.One : actualGame.PlayerTwoId == client.Id ? Player.Two : throw new Exception("Player can be matched"); var board = Map(actualGame); var mje = new MoveJsonEntity { From = new PositionEntity { Column = @from.Col, Row = @from.Row }, To = new PositionEntity { Column = target.Col, Row = target.Row }, Player = (Data.Player)((int)player) }; board = UpdatePosition(board, mje); actualGame.Moves.Add(mje); actualGame.Moves = actualGame.Moves; if (board.Board.Values.Count(x => x is King) < 2) { actualGame.State = GameState.Finished; } await this.ApplicationDbContext.SaveChangesAsync(); } else { throw new Exception("Client hadn't subscribed current room."); } }