C# Performance

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

RoadWarrior
Posts: 73
Joined: Fri Jan 13, 2012 12:39 am
Location: London, England

Re: C# Performance

Post by RoadWarrior »

lucasart wrote:But even with those things (useless for pure perft), I still reach over 30 million nodes per seconds or so... on a laptop...
And there's no cheat (no perft hash table, or perft approximations).

You'll certainly be able to improve the performance of your code by a fair amount, but at some point you'll reach a stage where:
1/ you realize that the same code in C# is much slower than C
2/ you have to be careful never to use any of the nice object oriented crap of C#, make sure you never trust anything that the compiler does behind your back (like exceptions, memory allocation, garbage collection)
3/ your code will become C code really, but with C# syntax. and you'll spend more time and effort coding in C# than in plain C, because of 2/

All I can say is: rewrite it in plain C while it's not too late... And the same applies to Java, which IMO is total and utter crap
According to a very recent CCRL rating list [1], DoubleCheck 2.2.1 is 2373. The Java chess engine Mediocre 0.4 is 2363. That's a really impressive difference between C and Java. :lol:

My fledgling C# engine does about 15 million perft moves on a laptop, so about half the speed of your engine. Let's assume for the sake of argument that this speed difference is the same through the whole of the engine. My understanding is that a doubling in speed is worth about 50 Elo. Are you really saying that a C# expert should move to C/C++ for 50 Elo?

More interesting links:
[1] http://computerchess.org.uk/ccrl/4040/r ... t_all.html
[2] http://blogs.msdn.com/b/ricom/archive/2 ... 16151.aspx
[3] http://www.ibm.com/developerworks/java/ ... index.html
[4] http://blogs.oracle.com/dagastine/entry ... aster_than
There are two types of people in the world: Avoid them both.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: C# Performance

Post by Sven »

RoadWarrior wrote:
Sven Schüle wrote:Testing attacks to E8 is the same as testing whether the king is in check before castling. If you already do this within your perft() or search() prior to move generation then keeping an inCheck flag and accessing it in the move generator will save double work, since no castling generation needs to be tried at all if the king is in check.
I made this change in my move generator, and tested it across my perft suite (76 positions). The mean average slowdown was around 2%.

But I suspect I'll need this info for other reasons later, so I'm going to leave it in, but commented-out for the moment.
Just to be sure: did this change as I described it above cause 2% slowdown, or 2% speedup? I could not imagine how avoiding to test E8 (resp. E1) for attacks twice can slow down your engine. If it does indeed, then how did you implement it?

Sven
RoadWarrior
Posts: 73
Joined: Fri Jan 13, 2012 12:39 am
Location: London, England

Re: C# Performance

Post by RoadWarrior »

Sven Schüle wrote: Just to be sure: did this change as I described it above cause 2% slowdown, or 2% speedup? I could not imagine how avoiding to test E8 (resp. E1) for attacks twice can slow down your engine. If it does indeed, then how did you implement it?
I added IsInCheck before generating any moves. That appears to have cost more time than it saved in avoiding the generation of castling moves. Mind you, I haven't profiled it yet, but those are the only 2 changes I made.
There are two types of people in the world: Avoid them both.
RoadWarrior
Posts: 73
Joined: Fri Jan 13, 2012 12:39 am
Location: London, England

Re: C# Performance

Post by RoadWarrior »

RoadWarrior wrote:
lucasart wrote:But even with those things (useless for pure perft), I still reach over 30 million nodes per seconds or so... on a laptop...
And there's no cheat (no perft hash table, or perft approximations).

You'll certainly be able to improve the performance of your code by a fair amount, but at some point you'll reach a stage where:
1/ you realize that the same code in C# is much slower than C
2/ you have to be careful never to use any of the nice object oriented crap of C#, make sure you never trust anything that the compiler does behind your back (like exceptions, memory allocation, garbage collection)
3/ your code will become C code really, but with C# syntax. and you'll spend more time and effort coding in C# than in plain C, because of 2/

All I can say is: rewrite it in plain C while it's not too late... And the same applies to Java, which IMO is total and utter crap
According to a very recent CCRL rating list [1], DoubleCheck 2.3.1 is 2373. The Java chess engine Mediocre 0.4 is 2363. That's a really impressive difference between C and Java. :lol:
Even better, CuckooChess 1.12 is also written in Java. And according to CCRL, it's rated at 2681, some 300 points higher than DoubleCheck.
CCRL: http://computerchess.org.uk/ccrl/4040/r ... t_all.html
CuckooChess: http://web.comhem.se/petero2home/javachess/index.html

So I think it's quite clear that language choice is far from the most important factor when creating a chess engine. Above all, I suspect that developer knowledge and skill is what counts.
There are two types of people in the world: Avoid them both.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: C# Performance

Post by Sven »

RoadWarrior wrote:
Sven Schüle wrote: Just to be sure: did this change as I described it above cause 2% slowdown, or 2% speedup? I could not imagine how avoiding to test E8 (resp. E1) for attacks twice can slow down your engine. If it does indeed, then how did you implement it?
I added IsInCheck before generating any moves. That appears to have cost more time than it saved in avoiding the generation of castling moves. Mind you, I haven't profiled it yet, but those are the only 2 changes I made.
Well, it is clear that calling IsInCheck at every node costs much more than avoiding castling generation, since there are several reasons why castling can be not available that are cheaper to test than testing attacks to the king. But that is not a fair comparison ...

My proposal was meant as:
a) IF you already have the IsInCheck prior to move generation then there is no need to test for attacks to E8 (E1) in castling move generation, just test the inCheck flag, and
b) if you don't have IsInCheck and you don't want to use that information in the move generator then you can still save time by not testing attacks to E8 (E1) twice, for two castle types per color. You might need an additional flag like "attacksToE8WereTested" in the castling generation function to achieve that.

Since in fact you did not have IsInCheck before, the only change where you can compare speed is b).

For perft you do not strictly need IsInCheck, depending on your legality checking strategy of course. But for real search you will very likely need it anyway. I see perft as a tool to validate (or debug) the "real" move generator that will be part of your searching engine, so I would build the move generator exactly in the way it is meant to work in the real engine (including information that was collected in advance), and then base "perft" on that. The "perft" validation shall still work the same way when you have your search up and running, in my opinion the target is not to make "perft" as fast as it can be, or you lose the ability to test any later changes to board representation, make/unmake, or move generator by running "perft".

Sven
RoadWarrior
Posts: 73
Joined: Fri Jan 13, 2012 12:39 am
Location: London, England

Re: C# Performance

Post by RoadWarrior »

Sven Schüle wrote:For perft you do not strictly need IsInCheck, depending on your legality checking strategy of course. But for real search you will very likely need it anyway. I see perft as a tool to validate (or debug) the "real" move generator that will be part of your searching engine, so I would build the move generator exactly in the way it is meant to work in the real engine (including information that was collected in advance), and then base "perft" on that. The "perft" validation shall still work the same way when you have your search up and running, in my opinion the target is not to make "perft" as fast as it can be, or you lose the ability to test any later changes to board representation, make/unmake, or move generator by running "perft".
Absolutely agreed, that's why I'm keeping the IsInCheck code around. I will also look at a way of not checking E1/E8 twice during castling move generation.

I distinguish between pure bare-bones perft and real move gen / make / unmake with a compile-time flag so that I can always test both.
There are two types of people in the world: Avoid them both.
User avatar
lucasart
Posts: 3232
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: C# Performance

Post by lucasart »

RoadWarrior wrote: Even better, CuckooChess 1.12 is also written in Java. And according to CCRL, it's rated at 2681, some 300 points higher than DoubleCheck.
CCRL: http://computerchess.org.uk/ccrl/4040/r ... t_all.html
CuckooChess: http://web.comhem.se/petero2home/javachess/index.html
Actually the most recent version of DoubleCheck is somewhat stronger than v2.3.1. But probably still significantly weaker than CuckooChess. But that doesn't prove a point of Java versus C, does it ? Needless to remind you that all the strong engines (above 3000 CCRL let's say) are written in C or C++, and a good 95% of the total are written in C or C++. The fact is that CuckooChess' algorithms and evaluation functions are just better than DoubleCheck's, and this is certainly not attributable to the superiority of Java...
RoadWarrior wrote: So I think it's quite clear that language choice is far from the most important factor when creating a chess engine. Above all, I suspect that developer knowledge and skill is what counts.
Yes that is true. But the point of the original post was to figure out how to make C# efficient. And the reality is that you'll never be able to make it as efficient as C, and the only way to get "anywhere close" (say three times slower...) is to make your code even more complicated and harder to write/read than plain C. Kind of kills the whole point os using a high level language in the first place, doesn't it ?

But I persist and say that Java is total and utter crap. If you want to use a high level language, at least use a proper one like Python. I have no particular opinion on C#, as I don't know the language enough. But at least C# is a proper compiled language, and doesn't run in some stupid Java VM, and isn't a trap for developpers to then get sued by Oracle for enfringment of their software patents over Java.
RoadWarrior
Posts: 73
Joined: Fri Jan 13, 2012 12:39 am
Location: London, England

Re: C# Performance

Post by RoadWarrior »

lucasart wrote:Needless to remind you that all the strong engines (above 3000 CCRL let's say) are written in C or C++, and a good 95% of the total are written in C or C++.
There is a small set of developers with the skill, knowledge, and time to create a world-class chess engine. There is a small set of people who are performance experts in a relatively new JIT-compiled language like C#. The intersection between these two sets of people is vanishingly small. That (combined with the fact that a significant number of the very strong engines are derived from each other) is why you haven't seen any world-class engines in C# (yet).
lucasart wrote:But the point of the original post was to figure out how to make C# efficient. And the reality is that you'll never be able to make it as efficient as C, and the only way to get "anywhere close" (say three times slower...) is to make your code even more complicated and harder to write/read than plain C. Kind of kills the whole point os using a high level language in the first place, doesn't it ?
If you assume that in the esoteric world of chess programming, well-written C is roughly twice as fast as well-written C# (and I suspect that's an over-estimate), that gives you just 50 Elo: 50 Elo! And I can assure you that my C wouldn't be twice as fast as my C#, because I'm a novice with C, but I teach and do presentations about C#.

Don't get me wrong. I love the fact that C gives me all the power of assembly together with all the ease-of-use of assembly :D. But if I really wanted a ferocious badass speed demon, I would write significant parts of my code using inline assembly. I know assembly much better than I know C, and inline assembly is almost as easy to do in C# as it is in C.
lucasart wrote:But I persist and say that Java is total and utter crap. If you want to use a high level language, at least use a proper one like Python. I have no particular opinion on C#, as I don't know the language enough. But at least C# is a proper compiled language, and doesn't run in some stupid Java VM, and isn't a trap for developpers to then get sued by Oracle for enfringment of their software patents over Java.


I'm sorry to disappoint you, but at compile-time C# source code is compiled to a bytecode language (IL) just like Java. The IL is then JIT-executed at runtime just like Java. The CLR is an implementation of a stack-based virtual machine, with no notion of x86/64 registers. Just as with Java, it's the JIT compiler that's responsible for "enregistration" of bytecode operations, scheduling the cpu registers to contain operands and results.

Enough of these silly language wars. Let's get back to helping Richard with his C# performance. I thought your algorithm suggestions were really useful.
There are two types of people in the world: Avoid them both.
Richard Allbert
Posts: 792
Joined: Wed Jul 19, 2006 9:58 am

Re: C# Performance

Post by Richard Allbert »

Hi Mark, Lucas,

Three posts coming up with the basic structure of the whole thing.

After an couple of days of frustration, I'm not really any further. I spent a lot of time testing the functions on their own using structs, references, anything I could think of,
but saw no improvement. In fact, when I changed the board class to a struct, and accessed the pieces without using a method, the perft went from ca. 2300knps to 1800knps.

This was despite single function tests suggesting that fweer method calls and structs by reference was faster.

I'm not sure if I am doing something working with IsAttacked() as pointed out previously, or if I'm missing something generally with the way C# works. I've also spent
a lot of time browsing online documentation, but it hasn't really helped. (apart from making this C++ vs C# discussion look very tame ;))

MoveGeneration is as follows: (shortened where code is repeated):

Code: Select all

public static void GenerateMoves&#40;Board board, List<Move> moveList&#41;
&#123;
	int pceStartIndex = 0;
	int pceSq = 0;
	if &#40;board.sideToMove == Colour.Dark&#41;
	&#123;
		// bP
		pceStartIndex = BoardConstants.StartIndex&#91;Pieces.bP&#93;;
		pceSq = board.pceLst&#91;pceStartIndex++&#93;;

		while &#40;pceSq != Squares.OffBoard&#41;
		&#123;
			GenerateBlackPawnMoves&#40;board, moveList, pceSq&#41;;
			pceSq = board.pceLst&#91;pceStartIndex++&#93;;
		&#125;

		// bN
		pceStartIndex = BoardConstants.StartIndex&#91;Pieces.bN&#93;;
		pceSq = board.pceLst&#91;pceStartIndex++&#93;;

		while &#40;pceSq != Squares.OffBoard&#41;
		&#123;
			GenerateNonSlideMoves&#40;board, moveList, Pieces.NDirections, pceSq, Pieces.bN&#41;;
			pceSq = board.pceLst&#91;pceStartIndex++&#93;;
		&#125;

		// bB
		pceStartIndex = BoardConstants.StartIndex&#91;Pieces.bB&#93;;
		pceSq = board.pceLst&#91;pceStartIndex++&#93;;

		while &#40;pceSq != Squares.OffBoard&#41;
		&#123;
			GenerateSliderMoves&#40;board, moveList, Pieces.BDirections, pceSq, Pieces.bB&#41;;
			pceSq = board.pceLst&#91;pceStartIndex++&#93;;
		&#125;
		
		// ...........etc for other pieces, then
		
		
		//bK				
		pceStartIndex = BoardConstants.StartIndex&#91;Pieces.bK&#93;;
		pceSq = board.pceLst&#91;pceStartIndex&#93;;

		Debug.Assert&#40;pceSq != Squares.OffBoard&#41;;

		GenerateNonSlideMoves&#40;board, moveList, Pieces.QDirections, pceSq, Pieces.bK&#41;;
		if (&#40;board.currentCastlePermission & BoardConstants.permk&#41; != 0&#41;
			GenerateBKSCAMoves&#40;board, moveList&#41;;
		if (&#40;board.currentCastlePermission & BoardConstants.permq&#41; != 0&#41;
			GenerateBQSCAMoves&#40;board, moveList&#41;;
	
	
	
//................
&#125;
private static void GenerateNonSlideMoves&#40;Board board, List<Move> moveList, int&#91;&#93; moveArray, int from, int pce&#41;
&#123;	
	int moves = 0;
	int toSq = 0;
	int inc = 0;
	while &#40;moveArray&#91;moves&#93; != 0&#41;
	&#123;
		inc = moveArray&#91;moves&#93;;
		toSq = from + inc;
		if &#40;CanLandOrTake&#40;board, pce, toSq&#41; == true&#41;
		&#123;
			moveList.Add&#40;new Move&#40;from, toSq, Pieces.NoPiece, board.GetPiece&#40;toSq&#41;, Moves.FlagNone&#41;);
		&#125;
		moves++;
	&#125;
&#125;

private static void GenerateSliderMoves&#40;Board board, List<Move> moveList, int&#91;&#93; moveArray, int from, int pce&#41;
&#123;
	Debug.Assert&#40;Pieces.PieceIsValid&#40;pce&#41;);
	Debug.Assert&#40;Pieces.PieceSlides&#40;pce&#41;);

	int moves = 0;
	int toSq = 0;
	int inc = 0;
	while &#40;moveArray&#91;moves&#93; != 0&#41;
	&#123;
		inc = moveArray&#91;moves&#93;;
		toSq = from + inc;
		while &#40;CanLandOrTake&#40;board, pce, toSq&#41; == true&#41;
		&#123;
			moveList.Add&#40;new Move&#40;from, toSq, Pieces.NoPiece, board.GetPiece&#40;toSq&#41;, Moves.FlagNone&#41;);
			if &#40;board.GetPiece&#40;toSq&#41; != Pieces.NoPiece&#41; break;
			toSq += inc;
		&#125;

		moves++;
	&#125;
&#125;

// one of the castle gen moves

private static void GenerateWKSCAMoves&#40;Board board, List<Move> list&#41;
&#123;
	if &#40;board.GetPiece&#40;Squares.G1&#41; == Pieces.NoPiece && board.GetPiece&#40;Squares.F1&#41; == Pieces.NoPiece&#41;
	&#123;                
	   list.Add&#40;new Move&#40;Squares.E1, Squares.G1, Pieces.NoPiece, Pieces.NoPiece, Moves.FlagCastled&#41;);
	&#125;
&#125;

private static void GenerateWhitePawnMoves&#40;Board board, List<Move> moveList, int frSq&#41;
&#123;
	// one and two squares
	if &#40;board.GetPiece&#40;frSq + Squares.dirN&#41; == Pieces.NoPiece&#41;
	&#123;
		AddWhitePawnMove&#40;frSq, frSq + Squares.dirN, Pieces.NoPiece, moveList&#41;;

		if &#40;Ranks.RankBoard&#91;frSq&#93; == Ranks.Rank2 && board.GetPiece&#40;frSq + Squares.dirN + Squares.dirN&#41; == Pieces.NoPiece&#41;
		&#123;
			moveList.Add&#40;new Move&#40;frSq, frSq + Squares.dirN + Squares.dirN, Pieces.NoPiece, Pieces.NoPiece, Moves.FlagNone&#41;);
		&#125;
	&#125;

	if &#40;Pieces.PieceColourIs&#40;board.GetPiece&#40;frSq + Squares.dirNW&#41;) == Colour.Dark&#41;
	&#123;
		AddWhitePawnMove&#40;frSq, frSq + Squares.dirNW, board.GetPiece&#40;frSq + Squares.dirNW&#41;, moveList&#41;;
	&#125;

	if &#40;Pieces.PieceColourIs&#40;board.GetPiece&#40;frSq + Squares.dirNE&#41;) == Colour.Dark&#41;
	&#123;
		AddWhitePawnMove&#40;frSq, frSq + Squares.dirNE, board.GetPiece&#40;frSq + Squares.dirNE&#41;, moveList&#41;;
	&#125;

	if &#40;board.enPassantSqaure == &#40;frSq + Squares.dirNW&#41; && board.enPassantSqaure != Squares.OffBoard&#41;
	&#123;
		moveList.Add&#40;new Move&#40;frSq, frSq + Squares.dirNW, Pieces.NoPiece, Pieces.NoPiece, Moves.FlagEnPassant&#41;);
	&#125;

	if &#40;board.enPassantSqaure == &#40;frSq + Squares.dirNE&#41; && board.enPassantSqaure != Squares.OffBoard&#41;
	&#123;
		moveList.Add&#40;new Move&#40;frSq, frSq + Squares.dirNE, Pieces.NoPiece, Pieces.NoPiece, Moves.FlagEnPassant&#41;);
	&#125;

&#125;

private static void AddWhitePawnMove&#40;int frSq, int tosq, int cap, List<Move> list&#41;
&#123;
	if &#40;Ranks.RankBoard&#91;tosq&#93; == Ranks.Rank8&#41;
	&#123;
		list.Add&#40;new Move&#40;frSq, tosq, Pieces.wQ, cap, Moves.FlagNone&#41;);
		list.Add&#40;new Move&#40;frSq, tosq, Pieces.wR, cap, Moves.FlagNone&#41;);
		list.Add&#40;new Move&#40;frSq, tosq, Pieces.wB, cap, Moves.FlagNone&#41;);
		list.Add&#40;new Move&#40;frSq, tosq, Pieces.wN, cap, Moves.FlagNone&#41;);
	&#125;
	else
	&#123;
		list.Add&#40;new Move&#40;frSq, tosq, Pieces.NoPiece, cap, Moves.FlagNone&#41;);
	&#125;
&#125;
				
And, if that wasn't enough for sore eyes, some of the is attacked()....

Code: Select all

public static bool SqIsAttackedBySide&#40;int sq, int side, Board board&#41;
&#123;
	if &#40;side == Colour.Light&#41;
	&#123;
		return AttackedByLight&#40;sq, board&#41;;
	&#125;
	else
	&#123;
		return AttackedByDark&#40;sq, board&#41;;
	&#125;
&#125;      

private static bool AttackedByDark&#40;int sq, Board board&#41;
&#123;
int pceStartIndex = 0;
int deltaFromTo = 0;
int attackersSq = 0;
int defSq = 0;
int inc = 0;

// bP
pceStartIndex = BoardConstants.StartIndex&#91;Pieces.bP&#93;;
attackersSq = board.pceLst&#91;pceStartIndex++&#93;;

while &#40;attackersSq != Squares.OffBoard&#41;
&#123;
	deltaFromTo = sq - attackersSq;
	if (&#40;AttackConstants.AttackBitArray&#91;deltaFromTo + AttackConstants.DeltaShift&#93; & AttackConstants.bP_Bit&#41; != 0&#41;
	&#123;
		return true;
	&#125;
	attackersSq = board.pceLst&#91;pceStartIndex++&#93;;
&#125;

// bN
pceStartIndex = BoardConstants.StartIndex&#91;Pieces.bN&#93;;
attackersSq = board.pceLst&#91;pceStartIndex++&#93;;

while &#40;attackersSq != Squares.OffBoard&#41;
&#123;
	deltaFromTo = sq - attackersSq;

	if (&#40;AttackConstants.AttackBitArray&#91;deltaFromTo + AttackConstants.DeltaShift&#93; & AttackConstants.N_Bit&#41; != 0&#41;
	&#123;
		return true;
	&#125;
	attackersSq = board.pceLst&#91;pceStartIndex++&#93;;
&#125;

// bB
pceStartIndex = BoardConstants.StartIndex&#91;Pieces.bB&#93;;
attackersSq = board.pceLst&#91;pceStartIndex++&#93;;

while &#40;attackersSq != Squares.OffBoard&#41;
&#123;
	deltaFromTo = sq - attackersSq;

	if (&#40;AttackConstants.AttackBitArray&#91;deltaFromTo + AttackConstants.DeltaShift&#93; & AttackConstants.B_Bit&#41; != 0&#41;
	&#123;
		inc = AttackConstants.AttackStepArray&#91;deltaFromTo + AttackConstants.DeltaShift&#93;;

		defSq = attackersSq + inc;
		Debug.Assert&#40;Squares.SquareOnBoard&#40;defSq&#41;);

		while &#40;defSq != sq&#41;
		&#123;
			if &#40;board.GetPiece&#40;defSq&#41; != Pieces.NoPiece&#41; break;
			defSq += inc;
		&#125;

		if &#40;defSq == sq&#41; return true;
	&#125;
	attackersSq = board.pceLst&#91;pceStartIndex++&#93;;
&#125;
.. which used the attack delta lookup to see if an attack can occure, before looping between the pcesq and target squares to see if the
attacking piece reaches it target

Next post, the makemove..
Richard Allbert
Posts: 792
Joined: Wed Jul 19, 2006 9:58 am

Re: C# Performance

Post by Richard Allbert »

the makemove..

Code: Select all


public static class MoveMake
&#123;
	public static bool MakeMoveOnBoard&#40;Board board, List<MoveHistory> history, Move move&#41;
	&#123;         
		int from = move.from;
		int to = move.to;

		if &#40;move.flag == Moves.FlagEnPassant&#41;
		&#123;
			if &#40;board.sideToMove == Colour.Light&#41;
			&#123;
				board.RemovePieceFromBoard&#40;to + Squares.dirS&#41;;
			&#125;
			else
			&#123;
				board.RemovePieceFromBoard&#40;to + Squares.dirN&#41;;
			&#125;
		&#125;
		else if &#40;move.flag == Moves.FlagCastled&#41;
		&#123;
			switch &#40;to&#41;
			&#123;
				case Squares.C1&#58;
					if (
						GetAttacks.SqIsAttackedBySide&#40;Squares.E1, Colour.Dark, board&#41; == true ||
						GetAttacks.SqIsAttackedBySide&#40;Squares.D1, Colour.Dark, board&#41; == true&#41;
					&#123;
						return false;
					&#125;
					else
					&#123;
						board.MovePieceOnBoard&#40;Squares.A1, Squares.D1&#41;;
					&#125;
					break;
				case Squares.C8&#58;
					if (
						GetAttacks.SqIsAttackedBySide&#40;Squares.E8, Colour.Light, board&#41; == true ||
						GetAttacks.SqIsAttackedBySide&#40;Squares.D8, Colour.Light, board&#41; == true&#41;
					&#123;
						return false;
					&#125;
					else
					&#123;
						board.MovePieceOnBoard&#40;Squares.A8, Squares.D8&#41;;
					&#125;
					break;
				case Squares.G1&#58;
					if (
						GetAttacks.SqIsAttackedBySide&#40;Squares.F1, Colour.Dark, board&#41; == true ||
						GetAttacks.SqIsAttackedBySide&#40;Squares.E1, Colour.Dark, board&#41; == true&#41;
					&#123;
						return false;
					&#125;
					else
					&#123;
						board.MovePieceOnBoard&#40;Squares.H1, Squares.F1&#41;;
					&#125;
					break;
				case Squares.G8&#58;
					if (
						GetAttacks.SqIsAttackedBySide&#40;Squares.F8, Colour.Light, board&#41; == true ||
						GetAttacks.SqIsAttackedBySide&#40;Squares.E8, Colour.Light, board&#41; == true&#41;
					&#123;
						return false;
					&#125;
					else
					&#123;
						board.MovePieceOnBoard&#40;Squares.H8, Squares.F8&#41;;
					&#125;
					break;
			&#125;
		&#125;

		history.Add&#40;new MoveHistory&#40;)
		&#123;
			m = move,
			fifty = board.currentFiftyMoveRule,
			enPassant = board.enPassantSqaure,
			castelPerm = board.currentCastlePermission
		&#125;);


		board.currentCastlePermission &= BoardConstants.CastlePerm&#91;from&#93;;
		board.currentCastlePermission &= BoardConstants.CastlePerm&#91;to&#93;;
		board.enPassantSqaure = Squares.OffBoard;

		if &#40;move.captured != Pieces.NoPiece&#41;
		&#123;
			board.RemovePieceFromBoard&#40;to&#41;;
			board.currentFiftyMoveRule = 0;
		&#125;

		if&#40;Pieces.PieceIsPawn&#40;board.GetPiece&#40;from&#41;) == true&#41;
		&#123;
			board.currentFiftyMoveRule = 0;
			if&#40; to - from == 2 * Squares.dirN&#41; board.enPassantSqaure = from + Squares.dirN;
			else if ( to - from == 2 * Squares.dirS&#41; board.enPassantSqaure = from + Squares.dirS;
		&#125;

		board.MovePieceOnBoard&#40;from, to&#41;;

		if &#40;move.promotedTo != Pieces.NoPiece&#41;
		&#123;
			board.RemovePieceFromBoard&#40;to&#41;;
			board.AddPieceToBoard&#40;move.promotedTo, to&#41;;
		&#125;
					

		board.ChangeSide&#40;);

		if &#40;GetAttacks.SqIsAttackedBySide&#40;board.KingSQ&#40;board.sideToMove ^ 1&#41;, board.sideToMove, board&#41; == true&#41;
		&#123;
			TakeMoveOnBoard&#40;board, history&#41;;
			return false;
		&#125;;

		return true;

	&#125; //makeonboard&#40;)

	public static void TakeMoveOnBoard&#40;Board board, List<MoveHistory> history&#41;
	&#123;
		int lastIndex = history.Count - 1;
		MoveHistory moveHis = history&#91;lastIndex&#93;;
		Move move = moveHis.m;


		int from = move.from;
		int to = move.to;

		board.currentFiftyMoveRule = moveHis.fifty;
		board.currentCastlePermission = moveHis.castelPerm;
		board.enPassantSqaure = moveHis.enPassant;
		board.ChangeSide&#40;);

		if &#40;move.flag == Moves.FlagEnPassant&#41;
		&#123;
			if &#40;board.sideToMove == Colour.Light&#41;
			&#123;
				board.AddPieceToBoard&#40;Pieces.bP, to + Squares.dirS&#41;;
			&#125;
			else
			&#123;
				board.AddPieceToBoard&#40;Pieces.wP, to + Squares.dirN&#41;;
			&#125;
		&#125;
		else if &#40;move.flag == Moves.FlagCastled&#41;
		&#123;
			switch &#40;to&#41;
			&#123;
				case Squares.C1&#58;
					board.MovePieceOnBoard&#40;Squares.D1, Squares.A1&#41;;
					break;
				case Squares.C8&#58;
					board.MovePieceOnBoard&#40;Squares.D8, Squares.A8&#41;;
					break;
				case Squares.G1&#58;
					board.MovePieceOnBoard&#40;Squares.F1, Squares.H1&#41;;
					break;
				case Squares.G8&#58;
					board.MovePieceOnBoard&#40;Squares.F8, Squares.H8&#41;;
					break;
				default&#58; break;
			&#125;
		&#125;

		board.MovePieceOnBoard&#40;to, from&#41;;

		if &#40;move.captured != Pieces.NoPiece&#41;
		&#123;
			board.AddPieceToBoard&#40;move.captured, to&#41;;
		&#125;            

		if &#40;move.promotedTo != Pieces.NoPiece&#41;
		&#123;
			board.RemovePieceFromBoard&#40;from&#41;;
			int pwn = board.sideToMove == Colour.Dark ? Pieces.bP &#58; Pieces.wP;
			board.AddPieceToBoard&#40;pwn, from&#41;;
		&#125;            

		history.RemoveAt&#40;lastIndex&#41;;

	&#125; //takeonboard&#40;)
&#125;