public ParticleSwarms(string PgnFilename, int ParticleSwarms, int ParticlesPerSwarm, int WinPercentScale, Delegates.DisplayStats DisplayStats, Delegates.WriteMessageLine WriteMessageLine) { _displayStats = DisplayStats; _writeMessageLine = WriteMessageLine; // Load games. WriteMessageLine("Loading games."); var stopwatch = new Stopwatch(); stopwatch.Start(); var board = new Board(WriteMessageLine); var pgnGames = new PgnGames(); pgnGames.Load(board, PgnFilename); stopwatch.Stop(); // Count positions. long positions = 0; for (var gameIndex = 0; gameIndex < pgnGames.Count; gameIndex++) { var pgnGame = pgnGames[gameIndex]; positions += pgnGame.Moves.Count; } var positionsPerSecond = (int)(positions / stopwatch.Elapsed.TotalSeconds); WriteMessageLine($"Loaded {pgnGames.Count:n0} games with {positions:n0} positions in {stopwatch.Elapsed.TotalSeconds:0.000} seconds ({positionsPerSecond:n0} positions per second)."); stopwatch.Restart(); WriteMessageLine("Creating data structures."); // Create parameters and particle swarms. var parameters = CreateParameters(); for (var index = 0; index < ParticleSwarms; index++) { var particleSwarm = new ParticleSwarm(pgnGames, parameters, ParticlesPerSwarm, WinPercentScale); Add(particleSwarm); // Set parameter values of all particles in swarm to known best. foreach (var particle in particleSwarm.Particles) { SetDefaultParameters(particle.Parameters); } } var stats = new Stats(); var cache = new Cache(1, stats, board.ValidateMove); var killerMoves = new KillerMoves(Search.MaxHorizon); var moveHistory = new MoveHistory(); var evaluation = new Evaluation(stats, board.IsRepeatPosition, () => false, WriteMessageLine); var search = new Search(stats, cache, killerMoves, moveHistory, evaluation, () => false, DisplayStats, WriteMessageLine); var firstParticleInFirstSwarm = this[0].Particles[0]; firstParticleInFirstSwarm.CalculateEvaluationError(board, search, WinPercentScale); _originalEvaluationError = firstParticleInFirstSwarm.EvaluationError; stopwatch.Stop(); WriteMessageLine($"Created data structures in {stopwatch.Elapsed.TotalSeconds:0.000} seconds."); }
public void Load(Board board, string filename, Delegates.WriteMessageLine writeMessageLine) { using (var pgnReader = File.OpenText(filename)) { var gameNumber = 1; PgnGame pgnGame; do { pgnGame = GetNextGame(board, pgnReader, gameNumber); if ((pgnGame != null) && (pgnGame.Result != GameResult.Unknown)) { Add(pgnGame); } gameNumber++; if ((gameNumber % 1000) == 0) { writeMessageLine($"Loaded {gameNumber:n0} games."); } } while (pgnGame != null); } GC.Collect(); }
public void FindMagicMultipliers(ColorlessPiece colorlessPiece, Delegates.WriteMessageLine writeMessageLine = null) { Direction[] directions; ulong[] unoccupiedMoveMasks; ulong[] relevantOccupancyMasks; ulong[] magicMultipliers; int[] shifts; ulong[][] moveMasks; // ReSharper disable SwitchStatementHandlesSomeKnownEnumValuesWithDefault switch (colorlessPiece) { case ColorlessPiece.Bishop: directions = new[] { Direction.NorthEast, Direction.SouthEast, Direction.SouthWest, Direction.NorthWest }; unoccupiedMoveMasks = Board.BishopMoveMasks; relevantOccupancyMasks = _bishopRelevantOccupancyMasks; magicMultipliers = _bishopMagicMultipliers; shifts = _bishopShifts; moveMasks = _bishopMoveMasks; break; case ColorlessPiece.Rook: directions = new[] { Direction.North, Direction.East, Direction.South, Direction.West }; unoccupiedMoveMasks = Board.RookMoveMasks; relevantOccupancyMasks = _rookRelevantOccupancyMasks; magicMultipliers = _rookMagicMultipliers; shifts = _rookShifts; moveMasks = _rookMoveMasks; break; default: throw new ArgumentException($"{colorlessPiece} piece not supported."); } // ReSharper restore SwitchStatementHandlesSomeKnownEnumValuesWithDefault // Generate moves mask on each square. var occupancyToMovesMask = new Dictionary <ulong, ulong>(); var uniqueMovesMasks = new HashSet <ulong>(); for (var square = Square.A8; square < Square.Illegal; square++) { occupancyToMovesMask.Clear(); uniqueMovesMasks.Clear(); var moveDestinations = unoccupiedMoveMasks[(int)square]; var relevantMoveDestinations = moveDestinations & relevantOccupancyMasks[(int)square]; var uniqueOccupancies = (int)Math.Pow(2, Bitwise.CountSetBits(relevantMoveDestinations)); occupancyToMovesMask.EnsureCapacity(uniqueOccupancies); // Generate moves mask for every permutation of occupancy of the relevant destination squares. var occupancyPermutations = Bitwise.GetAllPermutations(relevantMoveDestinations); for (var occupancyIndex = 0; occupancyIndex < occupancyPermutations.Count; occupancyIndex++) { var occupancy = occupancyPermutations[occupancyIndex]; var movesMask = Board.CreateMoveDestinationsMask(square, occupancy, directions); occupancyToMovesMask.Add(occupancy, movesMask); if (!uniqueMovesMasks.Contains(movesMask)) { uniqueMovesMasks.Add(movesMask); } } Debug.Assert(occupancyToMovesMask.Count == uniqueOccupancies); // Determine bit shift that produces number >= unique occupancies. // A stricter condition is number >= unique moves but this requires more computing time to find magic multipliers. var shift = 64 - (int)Math.Ceiling(Math.Log(uniqueOccupancies, 2d)); shifts[(int)square] = shift; var magicMultiplier = magicMultipliers[(int)square]; var knownMagicMultiplier = magicMultiplier == 0 ? null : (ulong?)magicMultiplier; (magicMultipliers[(int)square], moveMasks[(int)square]) = FindMagicMultiplier(occupancyToMovesMask, shift, knownMagicMultiplier); writeMessageLine?.Invoke($"{Board.SquareLocations[(int)square],6} {PieceHelper.GetName(colorlessPiece),6} {shift,5} {occupancyToMovesMask.Count,18} {uniqueMovesMasks.Count,12} {magicMultipliers[(int)square],16:X16}"); } }
public void FindMagicMultipliers(int Piece, Delegates.WriteMessageLine WriteMessageLine = null) { Direction[] directions; ulong[] unoccupiedMoveMasks; ulong[] relevantOccupancyMasks; ulong[] magicMultipliers; int[] shifts; ulong[][] moveMasks; switch (Piece) { case Engine.Piece.WhiteBishop: case Engine.Piece.BlackBishop: directions = new[] { Direction.NorthEast, Direction.SouthEast, Direction.SouthWest, Direction.NorthWest }; unoccupiedMoveMasks = Board.BishopMoveMasks; relevantOccupancyMasks = _bishopRelevantOccupancyMasks; magicMultipliers = _bishopMagicMultipliers; shifts = _bishopShifts; moveMasks = _bishopMoveMasks; break; case Engine.Piece.WhiteRook: case Engine.Piece.BlackRook: directions = new[] { Direction.North, Direction.East, Direction.South, Direction.West }; unoccupiedMoveMasks = Board.RookMoveMasks; relevantOccupancyMasks = _rookRelevantOccupancyMasks; magicMultipliers = _rookMagicMultipliers; shifts = _rookShifts; moveMasks = _rookMoveMasks; break; default: throw new ArgumentException($"{Piece} piece not supported."); } // Generate moves mask on each square. var occupancyToMovesMask = new Dictionary <ulong, ulong>(); var uniqueMovesMasks = new HashSet <ulong>(); for (var square = 0; square < 64; square++) { occupancyToMovesMask.Clear(); uniqueMovesMasks.Clear(); var moveDestinations = unoccupiedMoveMasks[square]; var relevantMoveDestinations = moveDestinations & relevantOccupancyMasks[square]; var uniqueOccupancies = (int)Math.Pow(2, Bitwise.CountSetBits(relevantMoveDestinations)); occupancyToMovesMask.EnsureCapacity(uniqueOccupancies); // Generate moves mask for every permutation of relevant occupancy bits. using (var occupancyPermutations = Bitwise.GetAllPermutations(relevantMoveDestinations).GetEnumerator()) { while (occupancyPermutations.MoveNext()) { var occupancy = occupancyPermutations.Current; if (!occupancyToMovesMask.ContainsKey(occupancy)) { // Have not yet generated moves for this occupancy mask. var movesMask = Board.CreateMoveDestinationsMask(square, occupancy, directions); occupancyToMovesMask.Add(occupancy, movesMask); if (!uniqueMovesMasks.Contains(movesMask)) { uniqueMovesMasks.Add(movesMask); } } } } // Validate enumerator found all permutations of relevant occupancy bits. Debug.Assert(occupancyToMovesMask.Count == uniqueOccupancies); // Determine bit shift that produces number >= unique occupancies. // A stricter condition is number >= unique moves but this requires more computing time to find magic multipliers. var shift = 64 - (int)Math.Ceiling(Math.Log(uniqueOccupancies, 2d)); shifts[square] = shift; var magicMultiplier = magicMultipliers[square]; if (magicMultiplier == 0) { (magicMultipliers[square], moveMasks[square]) = FindMagicMultiplier(occupancyToMovesMask, shift, null); } else { (magicMultipliers[square], moveMasks[square]) = FindMagicMultiplier(occupancyToMovesMask, shift, magicMultiplier); } WriteMessageLine?.Invoke($"{Board.SquareLocations[square],6} {Engine.Piece.GetName(Piece),6} {shift,5} {occupancyToMovesMask.Count,18} {uniqueMovesMasks.Count,12} {magicMultipliers[square],16:X16}"); } }