One alternative to embedding complex decision logic directly into your code is to build up a custom data structure which represents the complex series/collection of decisions and/or states which you might otherwise be wiring into your code.
This technique is sometimes known as Rule-based programming, which has some association with weak forms of AI, where the structures which encapsulate your logic/decisions are known as "Rules".
The rationale for doing this is that data structures are declarative rather than procedural; sometimes it is much easier (and more expressive/idiomatic) to represent complex decisions in a declarative data structure than it is to represent those same decisions in procedural code.
Using some of the rules of a chess as per your question; consider an XML-based structure for the various different kinds of move patterns allowed for different pieces:
<ChessPieceMoves>
<Piece type="Rook">
<Moves capture="true" move="true">
<CanMove pattern="Horizontal" />
<CanMove pattern="Vertical" />
</Moves>
</Piece>
<Piece type="King">
<Moves capture="true" move="true">
<CanMove pattern="Horizontal" rangeLimit="1" />
<CanMove pattern="Vertical" rangeLimit="1" />
<CanMove pattern="ForwardDiagonal" rangeLimit="1" />
<CanMove pattern="BackwardDiagonal" rangeLimit="1" />
</Moves>
<Moves capture="false" move="true">
<CanMove pattern="Castle" firstMoveOnly="true" />
</Moves>
</Piece>
<Piece type="Pawn">
<Moves capture="true" move="false">
<CanMove pattern="ForwardDiagonal" rangeLimit="1" />
</Moves>
<Moves capture="false" move="true">
<CanMove pattern="Forward" firstMoveOnly="true" rangeLimit="2" />
<CanMove pattern="Forward" rangeLimit="1" />
</Moves>
</Piece>
</ChessPieceMoves>
(Note - the above may or may not be a good structure for chess moves; I spent less than 5 minutes thinking about it).
Of course, then you need to write the code which binds those 'rules' into your code (i.e. code which reads the XML and represent the procedural code for each different behaviour/decision in that data); and this isn't necessarily a trivial task (Although something like C#'s XmlSerializer
makes it a lot easier). The binding code should be significantly less complex than the logic to embed those decisions/rules into procedural code however.
Also, there are existing declarative logic languages and various kinds of rules engines already in existence; so you might choose to learn a logic language such as Prolog.
If the code logic ends up being more complex, then the data structure is probably bad and needs re-thinking; chances are that it would need more information (elements/attributes) to cover all the different possible moves in chess, and would probably need restructuring too.