I am writing a chess engine, and I need an efficient way to merge several lists into a single list, ordered by the smallest value.
Each list is, in fact, a group of chess pieces that are already ordered in a perfect attack order. For example, I have a white queen on a2, a white bishop on b3, a white rook on f1, and a white rook on f2. Now say that I have a black pawn on f7, then all four white pieces converge on square f7 from two different discrete directions - in the northeast (queen and bishop) and in the north (rooks).
These two groups will be arranged as follows:
Group A) 1st-Bishop (b3); 2nd Queen (a2)
Group B) 1st rook (f2); 2nd - Rook (f1)
Now, using the point system below, I expect both lists to be combined into one list in the following order (lowest value to highest value): Bishop (b3), Rook (f2), Rook (f1) and finally Queen ( A2).
Queen = 900 points
Rook = 500 points
Bishop = 375 points
Knight = 350 points
Pawn = 100 points
Some codes:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SO_22015528
{
public enum eRayDirection
{
North,
NorthEast,
East,
SouthEast,
South,
SouthWest,
West,
NorthWest
}
public enum ePieceType
{
Empty = 0,
Pawn = 1,
Knight = 2,
Bishop = 3,
Rook = 4,
Queen = 5,
King = 6
}
public struct BoardPosition : IComparable<BoardPosition>
{
public int File;
public int Rank;
public int Square;
public BoardPosition( int square )
{
Square = square;
File = square % 7;
Rank = 8 - ( square >> 3 );
}
public static Boolean operator >( BoardPosition b1, BoardPosition b2 )
{
return ( b1.Rank > b2.Rank ) || ( b1.Rank == b2.Rank && b1.File < b2.File );
}
public static Boolean operator <( BoardPosition b1, BoardPosition b2 )
{
return ( b1.Rank < b2.Rank ) || ( b1.Rank == b2.Rank && b1.File > b2.File );
}
public int CompareTo( BoardPosition obj )
{
if ( this < obj ) return 1;
else if ( this > obj ) return -1;
else return 0;
}
}
public class ChessPiece
{
public int Value { get; set; }
public ePieceType Type { get; set; }
public int Square { get; set; }
public BoardPosition XY
{
get
{
return new BoardPosition( this.Square );
}
}
public ChessPiece( ePieceType type, int value, int square )
{
Value = value;
Type = type;
Square = square;
}
}
public class Constraint
{
public ChessPiece Piece { get; set; }
public eRayDirection Ray { get; set; }
public Constraint( ChessPiece piece, eRayDirection ray )
{
Piece = piece;
Ray = ray;
}
public override string ToString()
{
return String.Format( "{0} {1} {2}", Piece.Square, Piece.Type, Ray );
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SO_22015528
{
class Program
{
static void Main( string[] args )
{
ChessPiece a2 = new ChessPiece( ePieceType.Queen, 900, 48 );
ChessPiece b3 = new ChessPiece( ePieceType.Bishop, 375, 41 );
ChessPiece f1 = new ChessPiece( ePieceType.Rook, 500, 61 );
ChessPiece f2 = new ChessPiece( ePieceType.Rook, 500, 53 );
List<Constraint> f7 = new List<Constraint>();
f7.Add( new Constraint( b3, eRayDirection.NorthEast ) );
f7.Add( new Constraint( a2, eRayDirection.NorthEast ) );
f7.Add( new Constraint( f1, eRayDirection.North ) );
f7.Add( new Constraint( f2, eRayDirection.North ) );
List<eRayDirection> positiveRayDirections = new List<eRayDirection>();
positiveRayDirections.Add( eRayDirection.North );
positiveRayDirections.Add( eRayDirection.NorthEast );
positiveRayDirections.Add( eRayDirection.NorthWest );
positiveRayDirections.Add( eRayDirection.West );
var groups = f7
.GroupBy( g => g.Ray )
.Select( a =>
new
{
Key = a.Key,
Results = positiveRayDirections.Contains( a.Key ) ? a.OrderBy( x => x.Piece.XY ).ToList() : a.OrderByDescending( x => x.Piece.XY ).ToList()
} ).ToList();
List<Constraint> attackOrder = new List<Constraint>();
List<Int32> groupIndicies = new List<Int32>( groups.Count() );
for ( int n = 0; n < groups.Count(); n++ )
groupIndicies.Add( 0 );
while ( true )
{
Int32 value = Int32.MaxValue;
Int32 groupIndex = -1;
for ( int n = 0; n < groups.Count(); n++ )
{
var g = groups[ n ];
int gIndex = groupIndicies[ n ];
if ( gIndex < g.Results.Count && g.Results[ gIndex ].Piece.Value < value )
{
value = g.Results[ gIndex ].Piece.Value;
groupIndex = n;
}
}
if ( groupIndex < 0 )
break;
attackOrder.Add( groups[ groupIndex ].Results[ groupIndicies[ groupIndex ] ] );
groupIndicies[ groupIndex ]++;
}
foreach ( var ao in attackOrder )
Console.WriteLine( ao.ToString() );
Console.ReadKey();
}
}
}
I don't think the last bit is very efficient, and I would appreciate it if someone could find a much simpler way to do this.