Without any prior experience with hex chess, and not tons with regular chess anyways, in retrospect, I would not have started developing three versions at the start. But I did: Glinski, McCooey and Shafran. Shafran's version proved to be the biggest issue, thanks to the different board size, file/rank determination and extra moves such as castling.
Board Components
1: private GameVariant variant;
2: public GameVariant Variant
3: {
4: get { return variant; }
5: }
6: private Tile[,] tiles; // Exist in FileRank format. Can be accessed: Tile t = tiles[(int)File.F, (int)Rank.Eleven];
7: public Tile[,] Tiles
8: {
9: get { return tiles; }
10: }
11: public Player[] players;
12:
13: private PieceColor CurrentTurn = PieceColor.White;
14:
15: public List<ChessPiece> WhitePieces = new List<ChessPiece>();
16: public List<ChessPiece> BlackPieces = new List<ChessPiece>();
17: public ChessPiece WhiteKing;
18: public ChessPiece BlackKing;
19:
The king pieces are given a shortcut, for quick referencing.
Creating the tiles and positions
The tiles are held in a two dimensional array, with extra spaces just held as null. For Glinsky and McCooey, the tiles are placed in a similar fashion:
1: // Assign tiles to the array, incrementing Rank then File into FileRank format
2: // We have 11 files and 11 ranks
3: for (int i = 0; i < 11; i++)
4: {
5: // If our ranks are ranged 1 - 6, inclusive...
6: if (i < 6)
7: {
8: // then we have 11 files
9: for (int j = 0; j < 11; j++)
10: {
11: tiles[j, i] = new Tile((File)j, (Rank)i, null);
12: }
13: }
Shafran has a special, and much easier to create, tile layout:
1: // Assign tiles to the array, File then Rank
2: // We have 9 files and 10 ranks, starting with files first.
3: // Construct the first 5 files (A - E inclusive) with all their ranks (increasing to 10 max)...
4: for (int i = 0; i < 5; i++)
5: {
6: for (int j = 0; j < 6 + i; j++)
7: {
8: tiles[i, j] = new Tile((File)i, (Rank)j, null);
9: }
10: }
We then continue in like manner to finish the rest of the tiles.
Placing the pieces
Placing the pieces at this point is easy. Since we've created the tile array to be addressable by file and rank for each version, we can simply:
1: tiles[(int)File.G, (int)Rank.Ten].piece = new ChessPiece(PieceType.King, PieceColor.Black, ref tiles[(int)File.G, (int)Rank.Ten], false, false, true, false, false, false);
Why did I use classes?
Each tile is a class, and each piece is a class - a piece points to a tile points to a piece, ad nauseum. Initially, this was done simply because it was easier. Structs, as value types, would not be as easy to compare as classes, requiring rank and file checks for each check of a piece or tile. This also generated some concern looking forward to the AI (not yet even begun) when considering the size of the heap when looking forward in multiple plys, but it was assuaged somewhat by looking through MSDN documentation on structs and recommending that structs are used in the majority of times for types less than 16 bytes; my classes were larger than that, with their position in space, type, available moves, etc.
If the performance is terrible, I may consider removing the chess piece class entirely, and simply having the tile class with chess piece type and side. This, however, would be a very time consuming change.