GithubHelp home page GithubHelp logo

ecattez / shahmat Goto Github PK

View Code? Open in Web Editor NEW
3.0 1.0 0.0 992 KB

A Chess implementation with the Domain Driven Design

Home Page: https://ecattez.github.io/shahmat/

License: GNU General Public License v3.0

Java 100.00%

shahmat's Introduction

Shahmat

A Chess implementation with the Domain Driven Design

The Game

The ultimate aim in the chess game is delivering a checkmate – trapping your opponent´s king. The term checkmate is an alteration of the Persian phrase "Shah Mat", meaning literally, "the King is ambushed".

Each side starts out with 16 pieces, consisting of 8 pawns, 2 rooks, 2 knights, 2 bishops, 1 queen and 1 king, all in the same color.

White always goes first.

Pawn moves

Pawns are both simple and complex in their movements.

The pawn piece has the fewest options of any chess piece on the board in where it can move and it can only move forward until it reaches the other side of the board. Here are a few things to know about how a pawn chess piece moves:

  • It can only directly forward one square;
  • It can move directly forward two squares on their first move only;
  • It can move diagonally forward when capturing an opponent's chess piece;
  • If there is another piece in front of it, the pawn is stuck, unless there is a piece ahead on the capturing diagonals;
  • Once it reaches the other side of the chess board, the player may promote the pawn in for any other chess piece if they choose, except another king.

Pawn moves

En passant

En passant (French: [ɑ̃ paˈsɑ̃], lit. in passing) is a move in chess. It is a special pawn capture that can only occur immediately after a pawn makes a move of two squares from its starting square, and it could have been captured by an enemy pawn had it advanced only one square. The opponent captures the just-moved pawn "as it passes" through the first square. The result is the same as if the pawn had advanced only one square and the enemy pawn had captured it normally.

En passant is a unique privilege of pawns, other pieces cannot capture en passant. It is the only capture in chess in which the capturing piece does not replace the captured piece on its square.

En passant

Promotion

Promotion in chess is a rule that requires a pawn that reaches its eighth rank to be replaced by the player's choice of a queen, knight, rook, or bishop of the same color.

The new piece replaces the pawn within the same move. The choice of new piece is not limited to pieces previously captured, thus promotion can result in a player owning, for example, two or more queens despite starting the game with one.

Pawn promotion, or the threat of it, often decides the result in an endgame. Since the queen is the most powerful piece, the vast majority of promotions are to a queen. Promotion to a queen is also called queening; promotion to any other piece is referred to as underpromotion.

Rook

The rooks are the most simple-moving chess pieces on the board. Their movements are only straight, moving forward, backward or side to side. At any point in the game, the piece can move in any direction that is straight ahead, behind or to the side. Here are a few things to know about how the Rook chess piece moves:

  • It can move forward, backward, left or right at any time;
  • It can move anywhere from 1 to 7 squares in any direction, so long as it is not obstructed by any other piece;
  • It can capture an opponent piece that obstruct its way.

Rook moves

Bishop

The bishop chess piece is stuck moving in diagonals. Each player starts out with two bishop pieces, each one residing on its own color of square. Between both pieces, you can cover the entire board, but one piece can only cover one half of the board, only the colors of squares it started the game on.

  • It can move in any direction diagonally, so long as it is not obstructed by another piece.
  • It cannot move past any piece that is obstructing its path.
  • It can take any other piece on the board that is within its bounds of movement.

Bishop moves

Queen

The queen chess piece is like a combination of the Rook and Bishop chess pieces.

  • It queen can move in any direction on a straight or diagonal path.
  • It cannot move past any piece that is obstructing its path.
  • It can be used to capture any of your opponent's pieces on the board.

Queen moves

Knight

The Knight chess piece moves in a very mysterious way. Unlike Rooks, Bishops or Queens, the Knight is limited in the number of squares it can move across.

In fact, the piece moves in a shape similar to the uppercase "L". Here are the specifics:

  • it can move forward, backward, left or right two squares and must then move one square in either perpendicular direction.
  • it can only move to one of up to eight positions on the board.
  • it can move to any position not already inhabited by another piece of the same color.
  • it can skip over any other pieces to reach its destination position.

Knight moves

King

King chess pieces are somewhat limited in their movement. They cannot go riding across the chess board as quickly as most other pieces and they are easier to contain than most chess pieces from an opponent's perspective. Here are a few rules to note:

  • The king piece can move one single square in any direction.
  • The king cannot move onto a square that is currently occupied by a piece from its own team.

King moves

References

http://www.chesscoachonline.com/chess-articles/chess-rules https://www.wholesalechess.com/pages/new-to-chess/pieces.html https://en.wikipedia.org/wiki/Algebraic_notation_(chess)

shahmat's People

Contributors

ecattez avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar

shahmat's Issues

Feature: Checkmate

Feature: Checkmate

Scenario: a king is checkmate after an opposing move

WHEN a king is put in check because of an opposing move
AND the king's player cannot make any legal move
THEN the king is checkmate
AND the game is over
WITH the player's opponent as winner

Scenario: a king is checkmate after an opposing promotion

WHEN a king is put in check because of an opposing promotion
AND the king's player cannot make any legal move
THEN the king is checkmate
AND the game is over
WITH the player's opponent as winner

Visual chess board

The idea is to create a visual chess board, available through the web browser.

  • square should be colored
    • a square should be of the opposite color of the previous one: for example white become black and black become white
  • pieces should be displayed using their unicode values
  • select a piece should display its available moves
    • square is highlighted if it is an available move
    • if a piece is present on an available move, it is highlighted
  • the last move is highlighted by a green square

chess board

Turn is implicit

Current behavior:

TurnChanged{color=WHITE}
a3
TurnChanged{color=BLACK}
b6
TurnChanged{color=WHITE}

Expected behavior:

Turn is implicit because of move series. See https://en.wikipedia.org/wiki/Algebraic_notation_(chess)#Notation_for_a_series_of_moves

In fact, a game or series of moves is generally written in n two columns, as White/Black pairs, preceded by the move number and a period:

    1. e4 e5
    1. Nf3 Nc6
    1. Bb5 a6

Whoever has to play can be deducted from this series.

White play first. It moves. Black move, White move, etc. Turn is implicit.

TurnChanged{color=WHITE}
a3
TurnChanged{color=BLACK}
b6
TurnChanged{color=WHITE}

should be

a3
b6

Feature: Classical Chess

Feature: Classical Chess

Scenario: a classical board game initialization

GIVEN a classical chess game
WHEN the board is initialized
THEN a white rook is in A1
AND a white knight is is B1
AND a white bishop is in C1
AND a white queen is in D1
AND a white king is in E1
AND a white bishop is in F1
AND a white knight is in G1
AND a white rook is in H1
AND a white pawn is in A2
AND a white pawn is in B2
AND a white pawn is in C2
AND a white pawn is in D2
AND a white pawn is in E2
AND a white pawn is in F2
AND a white pawn is in G2
AND a white pawn is in H2
AND a black rook is in A8
AND a black knight is is B8
AND a black bishop is in C8
AND a black queen is in D8
AND a black king is in E8
AND a black bishop is in F8
AND a black knight is in G8
AND a black rook is in H8
AND a black pawn is in A7
AND a black pawn is in B7
AND a black pawn is in C7
AND a black pawn is in D7
AND a black pawn is in E7
AND a black pawn is in F7
AND a black pawn is in G7
AND a black pawn is in H7
AND the board is ready to play with

Scenario: a board already initialized can not be initialized again

GIVEN a classical chess game
AND the board is already initialized
WHEN the board is initialized
THEN the initialization is refused

Feature: Turn of White and Black

Feature: Turn of White and Black

The player controlling the white pieces is named "White"; the player controlling the black pieces is named "Black". White moves first, then players alternate moves. Making a move is required.

Scenario: White moves first

GIVEN an initialized board
WHEN a chess game starts
THEN it is the turn of White

Scenario: Turn changes after a move

GIVEN a ready to play chess game
AND <current_player> is playing
WHEN <current_player> moves one of its piece
THEN it is the turn of <next_player>

Example:
        | current_player | next_player |
        | WHITE | BLACK |
        | BLACK | WHITE |

Scenario: A player can not move its opponent's piece

GIVEN a ready to play chess game
AND <color> is playing
WHEN <color> moves a <opponent_color> piece
THEN the move is refused

Example:
        | color | opponent_color |
        | WHITE | BLACK |
        | BLACK | WHITE |

Scenario: Turn does not change when a promotion is proposed

GIVEN a <color> pawn in the other side of the chess board
AND <color> is playing
WHEN a promotion is proposed for the pawn
THEN turn stays for <color>

Example:
        | color |
        | WHITE |
        | BLACK |

Scenario: Turn changes after promoting a pawn

GIVEN a <color> pawn in the other side of the chess board
AND <color> is playing
WHEN the pawn is promoted
THEN it is the turn of <opponent_color>

Example:
        | color | opponent_color |
        | WHITE | BLACK |
        | BLACK | WHITE |

Feature: Knight

Feature: Knight

Scenario: A knight can move forward, backward, left or right two squares and must then move one square in either perpendicular direction

GIVEN a <color> knight in <from>
WHEN the knight is moved to <direction> two times
AND then moved <perpendicular> one square
THEN the knight is in <to>

Example:
        | color | from | direction | perpendicular | to |
        | WHITE | D5 | FORWARD | SHIFT_LEFT | C7 |
        | WHITE | D5 | FORWARD | SHIFT_RIGHT | E7 |
        | WHITE | D5 | SHIFT_LEFT | FORWARD | B6 |
        | WHITE | D5 | SHIFT_RIGHT | FORWARD | F6 |
        | WHITE | D5 | SHIFT_LEFT | BACKWARD | B4 |
        | WHITE | D5 | SHIFT_RIGHT | BACKWARD | F4 |
        | WHITE | D5 | BACKWARD | SHIFT_LEFT | C3 |
        | WHITE | D5 | BACKWARD | SHIFT_RIGHT | E3 |
        | BLACK | E4 | BACKWARD | SHIFT_LEFT | F2 |
        | BLACK | E4 | BACKWARD | SHIFT_RIGHT | D2 |
        | BLACK | E4 | SHIFT_LEFT | FORWARD | G3 |
        | BLACK | E4 | SHIFT_RIGHT | FORWARD | C3 |
        | BLACK | E4 | SHIFT_LEFT | BACKWARD | G5 |
        | BLACK | E4 | SHIFT_RIGHT | BACKWARD | C5 |
        | BLACK | E4 | BACKWARD | SHIFT_LEFT | F6 |
        | BLACK | E4 | BACKWARD | SHIFT_RIGHT | D6 |

Scenario: A knight can not take the place of any of its allies on the board that is within its bounds of movement

GIVEN a <color> knight in <from>
AND an allied piece in <to>
WHEN the knight is moved to <to>
THEN the move is refused

Example:
        | color | from | to |
        | WHITE | D5 | C7 |
        | WHITE | D5 | E7 |
        | WHITE | D5 | B6 |
        | WHITE | D5 | F6 |
        | WHITE | D5 | B4 |
        | WHITE | D5 | F4 |
        | WHITE | D5 | C3 |
        | WHITE | D5 | E3 |
        | BLACK | E4 | D6 |
        | BLACK | E4 | F6 |
        | BLACK | E4 | C5 |
        | BLACK | E4 | G5 |
        | BLACK | E4 | C3 |
        | BLACK | E4 | G3 |
        | BLACK | E4 | D2 |
        | BLACK | E4 | F2 |

Scenario: A knight can take any opposing piece on the board that is within its bounds of movement

GIVEN a <color> knight in <from>
AND an opposing piece in <to>
WHEN the knight is moved to <to>
THEN the knight captures the opposing piece

Example:
        | color | from | to |
        | WHITE | D5 | C7 |
        | WHITE | D5 | E7 |
        | WHITE | D5 | B6 |
        | WHITE | D5 | F6 |
        | WHITE | D5 | B4 |
        | WHITE | D5 | F4 |
        | WHITE | D5 | C3 |
        | WHITE | D5 | E3 |
        | BLACK | E4 | D6 |
        | BLACK | E4 | F6 |
        | BLACK | E4 | C5 |
        | BLACK | E4 | G5 |
        | BLACK | E4 | C3 |
        | BLACK | E4 | G3 |
        | BLACK | E4 | D2 |
        | BLACK | E4 | F2 |

Scenario: A knight can skip over any other pieces to reach its destination position

GIVEN a <color> knight in <from>
AND the square <obstructed> is not vacant
WHEN the knight is moved to <to>
THEN the knight is in <to>

Example:
        | color | from | obstructed | to |
        | WHITE | D5 | D6 | C7 |
        | WHITE | D5 | D7 | E7 |
        | WHITE | D5 | C5 | B6 |
        | WHITE | D5 | F5 | F6 |
        | WHITE | D5 | B5 | B4 |
        | WHITE | D5 | E5 | F4 |
        | WHITE | D5 | D4 | C3 |
        | WHITE | D5 | D3 | E3 |
        | BLACK | E4 | E5 | D6 |
        | BLACK | E4 | E6 | F6 |
        | BLACK | E4 | D4 | C5 |
        | BLACK | E4 | F4 | G5 |
        | BLACK | E4 | D4 | C3 |
        | BLACK | E4 | G4 | G3 |
        | BLACK | E4 | E3 | D2 |
        | BLACK | E4 | E2 | F2 |

Feature: Stalemate

Feature: Stalemate

Stalemate is a situation in the game of chess where the player whose turn it is to move is not in check but has no legal move. The rules of chess provide that when stalemate occurs, the game ends as a draw.

Scenario: a player is stalemate

WHEN a king is not in check
AND the king's player cannot make any legal move
THEN the player is stalemate
AND the game ends as a draw

Feature: En passant

Feature: En Passant

Scenario: a pawn can immediately capture an opposing pawn that moved forward two squares on a neighbouring file

GIVEN a <color> pawn in <from>
AND an opposing pawn that moved forward two squares on a neighbouring file <file>
WHEN the opposing pawn is immediately captured en passant
THEN the pawn is in <to>
AND the opposing pawn is removed from the game

Example:
    | color | from | file | to |
    | WHITE | C5 | B | B6 |
    | WHITE | C5 | D | D6 |
    | BLACK | C4 | D | B3 |
    | BLACK | C4 | B | D3 |

Scenario: a pawn can not capture en passant if it is not immediately after the move of the opposing pawn

GIVEN a <color> pawn in <from>
AND an opposing pawn that moved forward two squares on a neighbouring file <file>
AND an other opposing piece as moved since
WHEN the opposing pawn is captured en passant
THEN the capture is refused

Example:
    | color | from | file |
    | WHITE | C5 | B |
    | BLACK | C4 | D |

Feature: Notation of Move

Feature: Notation for moves

Each move of a piece is indicated by the piece's uppercase letter, plus the coordinate of the destination square. For example, Be5 (move a bishop to e5), Nf3 (move a knight to f3). For pawn moves, a letter indicating pawn is not used, only the destination square is given. For example, c5 (move a pawn to c5).

Captures

When a piece makes a capture, an "x" is inserted immediately before the destination square. For example, Bxe5 (bishop captures the piece on e5). When a pawn makes a capture, the ''file'' from which the pawn departed is used to identify the pawn. For example, exd5 (pawn on the e-file captures the piece on d5).

En passant captures are indicated by specifying the capturing pawn's file of departure, the "x", the destination square (not the square of the captured pawn), and (optionally) the suffix "e.p." indicating the capture was ''en passant''. For example, exd6e.p..

Disambiguating moves

When two (or more) identical pieces can move to the same square, the moving piece is uniquely identified by specifying the piece's letter, followed by (in descending order of preference):

  • the file of departure (if they differ); or
  • the rank of departure (if the files are the same but the ranks differ); or
  • both the file and rank (if neither alone is sufficient to identify the piece; which occurs only in rare cases where one or more pawns have promotion, resulting in a player having three or more identical pieces able to reach the same square).

For example, in the diagram, Bb8 would be ambiguous, as either of the bishops on a7 and d6 could legally move to b8. The move of the d6 bishop is therefore specified as Bdb8, indicating that it was the bishop on the d file which moved. Although they could also be differentiated by their ranks, the file letter takes precedence.

For the black rooks both on the 8th rank, both could potentially move to f8, so the move of the d8 rook to f8 is disambiguated as Rdf8. For the white rooks both on the a file which could both move to a3, it is necessary to provide the ''rank'' of the moving piece, i.e. R1a3.

In the case of the white queen on h4 moving to e1, neither the rank nor file alone are sufficient to disambiguate from the other white queens. As such, this move is written Qh4e1.

As above, an "x" can be inserted to indicate a capture, for example if the final case were a capture it would be written Qh4xe1.

Pawn promotion

When a pawn moves to the last rank and promotes, the piece promoted to is indicated at the end of the move notation, for example: e8Q (promoting to queen). Sometimes an equals sign or parentheses are used: '''e8=Q''' or '''e8(Q)''', but neither format is a [[FIDE]] standard. In [[Portable Game Notation]] (PGN), pawn promotion is always indicated using the equals sign format ('''e8=Q''').

In older books, pawn promotions can be found using a forward slash: '''e8/Q'''.

Draw offer

In FIDE Laws of Chess, an equals sign with parentheses, "(=)", is used to write the offer of a draw on the score next to a move, but this is not part of algebraic notation.

Castling

Castling is indicated by the special notations 0-0 (for kingside castling) and 0-0-0(queenside castling).

Check

A move that places the opponent's king in check usually has the symbol "+" appended.

Checkmate

Checkmate at the completion of moves can be represented by the symbol "#".

End of game

The notation '''1–0''' at the completion of moves indicates that White won, '''0–1''' indicates that Black won, and '''½–½''' indicates a draw.

Often there is no indication regarding how a player won or lost (other than checkmate, see above), so simply 1–0 or 0–1 may be written to show that one player resigned or lost due to time control. (Similarly, there is more than one way for a game to end in a draw.) Sometimes direct information is given by the words "White resigns" or "Black resigns", though this is not considered part of the notation but rather a return to the surrounding narrative text.

Feature: King

Feature: King

Scenario: A king moves exactly one square horizontally, vertically, or diagonally.

GIVEN a <color> king in <from>
AND the one square <direction> is vacant
WHEN the king is moved <direction>
THEN the king is in <to>

Example:
        | color | from | to | direction |
        | WHITE | E4 | E5 | FORWARD |
        | WHITE | E6 | D7 | FORWARD_LEFT |
        | WHITE | C3 | D4 | FORWARD_RIGHT |
        | WHITE | B6 | B5 | BACKWARD |
        | WHITE | B5 | A4 | BACKWARD_LEFT |
        | WHITE | A5 | B4 | BACKWARD_RIGHT |
        | WHITE | E5 | D5 | SHIFT_LEFT |
        | WHITE | F6 | G6 | SHIFT_RIGHT |
        | BLACK | E5 | E4 | FORWARD |
        | BLACK | D5 | E4 | FORWARD_LEFT |
        | BLACK | E5 | D4 | FORWARD_RIGHT |
        | BLACK | D5 | D6 | BACKWARD |
        | BLACK | G6 | H7 | BACKWARD_LEFT |
        | BLACK | G5 | F6 | BACKWARD_RIGHT |
        | BLACK | E4 | F4 | SHIFT_LEFT |
        | BLACK | G6 | F6 | SHIFT_RIGHT |

Scenario: A king cannot move beyond an obstructed path

GIVEN a <color> king in <from>
AND the one square <direction> is not vacant
WHEN the king is moved <direction>
THEN the move is refused

Example:
        | color | from | direction |
        | WHITE | E4 | FORWARD |
        | WHITE | E6 | FORWARD_LEFT |
        | WHITE | C3 | FORWARD_RIGHT |
        | WHITE | B6 | BACKWARD |
        | WHITE | B5 | BACKWARD_LEFT |
        | WHITE | A5 | BACKWARD_RIGHT |
        | WHITE | E5 | SHIFT_LEFT |
        | WHITE | F6 | SHIFT_RIGHT |
        | BLACK | E5 | FORWARD |
        | BLACK | D5 | FORWARD_LEFT |
        | BLACK | E5 | FORWARD_RIGHT |
        | BLACK | D5 | BACKWARD |
        | BLACK | G6 | BACKWARD_LEFT |
        | BLACK | G5 | BACKWARD_RIGHT |
        | BLACK | E4 | SHIFT_LEFT |
        | BLACK | F6 | SHIFT_RIGHT |

Scenario: A king can capture any opposing piece on the board that is within its bounds of movement

GIVEN a <color> king in <from>
AND an opposing piece in <to>
WHEN the king is moved to <to>
THEN the king captures the opposing piece

Example:
        | color | from | to |
        | WHITE | E4 | D3 |
        | WHITE | E4 | D4 |
        | WHITE | E4 | D5 |
        | WHITE | E4 | E3 |
        | WHITE | E4 | E5 |
        | WHITE | E4 | F3 |
        | WHITE | E4 | F4 |
        | WHITE | E4 | F5 |
        | BLACK | D5 | E6 |
        | BLACK | D5 | E5 |
        | BLACK | D5 | E4 |
        | BLACK | D5 | D6 |
        | BLACK | D5 | D4 |
        | BLACK | D5 | C6 |
        | BLACK | D5 | C5 |
        | BLACK | D5 | C4 |

Board Projection : HAL Representation

For HTTP Clients, we should send a representation such as below (preferred hal-forms format).

{
  "turnOf": "WHITE",
  "number-of-living-black-pieces": 0,
  "number-of-living-white-pieces": 0,
  "_embedded": {
    "squares": [
      {
        "location": "a1",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/a1"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "a2",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/a2"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "a3",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/a3"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "a4",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/a4"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "a5",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/a5"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "a6",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/a6"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "a7",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/a7"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "a8",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/a8"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "b1",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/b1"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "b2",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/b2"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "b3",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/b3"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "b4",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/b4"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "b5",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/b5"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "b6",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/b6"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "b7",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/b7"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "b8",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/b8"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "c1",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/c1"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "c2",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/c2"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "c3",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/c3"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "c4",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/c4"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "c5",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/c5"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "c6",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/c6"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "c7",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/c7"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "c8",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/c8"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "d1",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/d1"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "d2",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/d2"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "d3",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/d3"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "d4",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/d4"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "d5",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/d5"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "d6",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/d6"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "d7",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/d7"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "d8",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/d8"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "e1",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/e1"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "e2",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/e2"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "e3",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/e3"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "e4",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/e4"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "e5",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/e5"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "e6",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/e6"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "e7",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/e7"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "e8",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/e8"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "f1",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/f1"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "f2",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/f2"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "f3",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/f3"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "f4",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/f4"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "f5",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/f5"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "f6",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/f6"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "f7",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/f7"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "f8",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/f8"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "g1",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/g1"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "g2",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/g2"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "g3",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/g3"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "g4",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/g4"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "g5",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/g5"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "g6",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/g6"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "g7",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/g7"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "g8",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/g8"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "h1",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/h1"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "h2",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/h2"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "h3",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/h3"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "h4",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/h4"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "h5",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/h5"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "h6",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/h6"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "h7",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/h7"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      },
      {
        "location": "h8",
        "vacant": true,
        "_links": [
          {
            "self": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c/squares/h8"
            }
          },
          {
            "related": {
              "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
            }
          }
        ]
      }
    ]
  },
  "_links": [
    {
      "self": {
        "href": "http://localhost:8080/boards/3feeafdf02b4c76c"
      }
    }
  ]
}

Feature: Queen

Feature: Queen

Scenario: A queen can move in any direction on a straight or diagonal path

GIVEN a <color> queen in <from>
AND the squares between <from> and <to> are vacant
WHEN the queen is moved <times> <direction>
THEN the queen is in <to>

Example:
        | color | from | times | direction | to |
        | WHITE | A1 | 4 | FORWARD | A5 |
        | WHITE | A5 | 2 | SHIFT_RIGHT | C5 |
        | WHITE | C5 | 2 | SHIFT_LEFT | A5 |
        | WHITE | A5 | 4 | BACKWARD | A1 |
        | WHITE | E5 | 3 | FORWARD_LEFT | B8 |
        | WHITE | B8 | 2 | BACKWARD_RIGHT | D6 |
        | WHITE | D6 | 1 | FORWARD_RIGHT | E7 |
        | WHITE | E7 | 4 | BACKWARD_LEFT | A3 |
        | BLACK | A8 | 4 | FORWARD | A4 |
        | BLACK | A4 | 2 | SHIFT_LEFT | C4 |
        | BLACK | C4 | 2 | SHIFT_RIGHT | A4 |
        | BLACK | A4 | 4 | BACKWARD | A8 |
        | BLACK | D5 | 3 | FORWARD_LEFT | G2 |
        | BLACK | G2 | 2 | BACKWARD_RIGHT | E4 |
        | BLACK | E4 | 2 | FORWARD_RIGHT | C2 |
        | BLACK | C2 | 4 | BACKWARD_LEFT | G6 |

Scenario: A queen cannot move beyond an obstructed path

GIVEN a <color> queen in <from>
AND the square <obstructed> is not vacant
WHEN the queen is moved <time> <direction>
THEN the move is refused

Example:
        | color | from | obstructed | times | direction |
        | WHITE | A1 | C3 | 4 | FORWARD_RIGHT |
        | WHITE | E6 | B3 | 4 | BACKWARD_LEFT |
        | WHITE | C3 | B4 | 1 | FORWARD_LEFT |
        | WHITE | B6 | C5 | 2 | BACKWARD_RIGHT |
        | WHITE | A1 | A3 | 4 | FORWARD |
        | WHITE | A5 | C5 | 2 | SHIFT_RIGHT |
        | WHITE | E5 | C5 | 2 | SHIFT_LEFT |
        | WHITE | A5 | A3 | 4 | BACKWARD |
        | BLACK | E5 | C3 | 3 | FORWARD_RIGHT |
        | BLACK | D5 | E6 | 2 | BACKWARD_LEFT |
        | BLACK | E5 | G3 | 3 | FORWARD_LEFT |
        | BLACK | D5 | B7 | 2 | BACKWARD_RIGHT |
        | BLACK | A8 | A6 | 4 | FORWARD |
        | BLACK | A4 | C4 | 2 | SHIFT_LEFT |
        | BLACK | E4 | C4 | 2 | SHIFT_RIGHT |
        | BLACK | A4 | A6 | 2 | BACKWARD |

Scenario: A queen can capture any opposing piece on the board that is within its bounds of movement

GIVEN a <color> queen in <from>
AND an opposing piece in <to>
WHEN the queen is moved to <to>
AND the queen captures the opposing piece

Example:
        | color | from | to |
        | WHITE | A1 | A3 |
        | WHITE | A5 | C5 |
        | WHITE | E5 | C5 |
        | WHITE | A5 | A3 |
        | WHITE | E5 | B2 |
        | WHITE | C4 | D3 |
        | WHITE | C6 | E8 |
        | WHITE | H1 | A8 |
        | BLACK | A8 | A6 |
        | BLACK | A4 | C4 |
        | BLACK | E4 | C4 |
        | BLACK | A4 | A6 |
        | BLACK | E5 | B2 |
        | BLACK | C4 | D3 |
        | BLACK | C6 | E8 |
        | BLACK | H1 | A8 |

Promotion is a move

Current behavior:

a2
...
a1
PromotionProposed{location=a8}
a1=Q

Expected behavior:

Promotion is the move of a pawn from the penultimate rank (2 for black, 7 for white) to the last rank with a promotion type (queen, rook, bishop, knight).

For example, a white pawn can not move from rank 2 to 1 without specifying in witch piece it would be promoted.

So event flow would be as below :

a2 [...]
a1=Q [...]

PromotionProposed should be removed. Promotion feature should be reopened with a scenario about moving a pawn to the last rank without promoting it (should raise an error).

Promotion can also happen when capturing.

Feature: Check

Feature: Check

A check is a condition that occurs when a player's king is under threat of capture on their opponent's next turn. A king so threatened is said to be in check. A player must get out of check, if possible, by interposing a piece between the threatening piece and the king, capturing the threatening piece, or moving the king to a square where it is no longer in check. Players cannot make any move that puts their own king in check.

If the king is in check and the checked player has no legal move to get out of check, the king is checkmated and the player loses. When the king is not in check and it is the last living piece of its color, if the player has no legal move to get out of check, the game results in Pat.

Scenario: a king becomes threatened

GIVEN a king in <king-location>
AND an opposing <opponent-type> in <opposing-location>
WHEN the opposing piece is moved to <to>
THEN the king is in the bounds of movement of the opposing piece
AND the king is in check

Example:
        | king-location | opponent-type | opponent-location | to |
        | G4 | QUEEN | D8 | D4 |
        | F4 | BISHOP | F8 | D6 |
        | E4 | ROOK | A8 | A4 |
        | D5 | KNIGHT | G8 | F6 |
        | D5 | PAWN | C7 | C6 |

Scenario: a king can not move to a square where it could be in check

GIVEN a king in <king-location>
AND an opposing <opponent-type> in <opposing-location>
WHEN the king is moved to <to>
THEN the move is refused

Example:
        | king-location | opponent-type | opponent-location | to |
        | D3 | QUEEN | D8 | D4 |
        | D5 | BISHOP | F8 | D6 |
        | B3 | ROOK | A8 | A4 |
        | E7 | KNIGHT | G8 | F6 |
        | D4 | PAWN | C6 | D5 |

Scenario: a king can move to a square where it could escape from check

GIVEN a king in check in <king-location>
AND an opposing <opponent-type> in <opposing-location>
WITH the square <to> not in its bounds of movement
WHEN the king is moved to <to>
THEN the king is no longer in check

Example:
        | king-location | opponent-type | opponent-location | to |
        | D3 | QUEEN | D8 | C3 |
        | E6 | BISHOP | C4 | F6 |
        | E3 | ROOK | B3 | E4 |
        | E5 | KNIGHT | G6 | E6 |
        | E3 | PAWN | D4 | D3 |
        | D7 | QUEEN | D8 | D8 |
        | B4 | BISHOP | C4 | C4 |
        | B2 | ROOK | B3 | B3 |
        | E3 | PAWN | D4 | D4 |

Scenario: king's allies can move to help the king escaping from check

GIVEN a king in check in <king-location>
AND an opposing <opponent-type> in <opposing-location>
AND a <ally-type>, ally of the king in <ally-location>
WHEN the ally is moved to <to>
THEN the king is no longer in check

Example:
        | king-location | opponent-type | opponent-location | ally-type | ally-location | to |
        | E1 | QUEEN | E8 | BISHOP | D3 | E4 |
        | E1 | BISHOP | B4 | QUEEN | D1 | D2 |
        | E1 | ROOK | E8 | KNIGHT | D2 | E4 |
        | E1 | KNIGHT | D3 | ROOK | H3 | D3 |
        | E2 | PAWN | F3 | PAWN | G2 | F3 |
        | E1 | QUEEN | E8 | BISHOP | A4 | E8 |
        | E1 | BISHOP | B4 | ROOK | B1 | B4 |
        | E1 | ROOK | E8 | KNIGHT | D6 | E8 |

Scenario: king's ally can not move from a square that could make the king in check if vacant

GIVEN a king in <king-location>
AND an opposing <opponent-type> in <opposing-location>
AND a <ally-type>, ally of the king in <ally-location>
WHEN the ally is moved to <to>
THEN the move is refused

Scenario: a king can be put in check because of pawn promotion

GIVEN a king in <king-location>
AND an opposing pawn in the other side of the board
WHEN the opposing pawn is promoted to <promotion-type>
THEN the king is in check

Example:
        | king-location | promotion-location | promotion-type |
        | E1 | B1 | ROOK |
        | E1 | B1 | QUEEN |
        | E2 | F1 | BISHOP |
        | E2 | G1 | KNIGHT |

Feature: Promotion

Feature: Promotion

Scenario: Promotion is proposed when a pawn reaches the other side of the chess board

GIVEN a <color> pawn in <from>
WHEN the pawn is moved forward
THEN a promotion is proposed in <to>

Example:
    | color | from | to |
    | WHITE | A7 | A8 |
    | WHITE | B7 | B8 |
    | WHITE | C7 | C8 |
    | WHITE | D7 | D8 |
    | WHITE | E7 | E8 |
    | WHITE | F7 | F8 |
    | WHITE | G7 | G8 |
    | WHITE | H7 | H8 |
    | BLACK | A2 | A1 |
    | BLACK | B2 | B1 |
    | BLACK | C2 | C1 |
    | BLACK | D2 | D1 |
    | BLACK | E2 | E1 |
    | BLACK | F2 | F1 |
    | BLACK | G2 | G1 |
    | BLACK | H2 | H1 |

Scenario: Pawn can not be promoted for pawn nor a king

GIVEN a pawn in the other side of the chess board
WHEN the pawn is promoted to a <promotion-type>
THEN the promotion is refused
WITH "Piece can not promote" as reason

Example:
    | promotion-type |
    | PAWN |
    | KING |

Scenario: Pawn may be promoted for a non king piece

GIVEN a pawn in the other side of the chess board
WHEN the pawn is promoted to a <promotion-type>
THEN a <promotion-type> replaces the pawn

Example:
    | promotion-type |
    | QUEEN |
    | KNIGHT |
    | ROOK |
    | BISHOP |

Scenario: Pawn can not be promoted if it has not been offered to it

GIVEN a pawn not in the other side of the chess board
WHEN the pawn is promoted to a valid piece
THEN the promotion is refused
WITH "Piece can not be promoted" as reason

Scenario: No piece can be moved while a pawn is promoted

GIVEN a pawn in the other side of the chess board
AND the promotion is proposed
WHEN an other piece is moved
THEN the move is refused

Feature: Pawn

Feature: Pawn

Scenario: Pawn can only move directly forward one square

GIVEN a <color> pawn in <from>
AND <to> is vacant
WHEN the pawn is moved forward
THEN the pawn is in <to>

Example:
    | color | from | to |
    | WHITE | A2 | A3 |
    | BLACK | A7 | A6

Scenario: Pawn is stuck when the square is not vacant

GIVEN a <color> pawn in <from>
AND <to> is not vacant
WHEN the pawn is moved forward
THEN the pawn stays in <from>

Example:
    | color | from | to |
    | WHITE | A2 | A3 |
    | BLACK | A7 | A6

Scenario: Pawn can move directly forward two squares on their first move only

GIVEN a <color> pawn in <from>
AND <forward> is vacant
AND <to> is vacant
WHEN the pawn is moved forward two squares
THEN the pawn is in <to>

Example:
    | color | from | forward | to |
    | WHITE | A2 | A3 | A4 |
    | WHITE | B2 | B3 | B4 |
    | WHITE | C2 | C3 | C4 |
    | WHITE | D2 | D3 | D4 |
    | WHITE | E2 | E3 | E4 |
    | WHITE | F2 | F3 | F4 |
    | WHITE | G2 | G3 | G4 |
    | WHITE | H2 | H3 | H4 |
    | BLACK | A7 | A6 | A5 |
    | BLACK | B7 | B6 | B5 |
    | BLACK | C7 | C6 | C5 |
    | BLACK | D7 | D6 | D5 |
    | BLACK | E7 | E6 | E5 |
    | BLACK | F7 | F6 | F5 |
    | BLACK | G7 | G6 | G5 |
    | BLACK | H7 | H6 | H5 |

Scenario: Pawn can move diagonally forward when capturing an opposing piece

GIVEN a <color> pawn in <from>
AND an opposing piece in <opponent-location>
WHEN the pawn is moved to <opponent-location>
THEN the pawn captures the opposing piece

Example:
    | color | from | opponent-location |
    | WHITE | B3 | A4 |
    | WHITE | B3 | C4 |
    | BLACK | B5 | C4 |
    | BLACK | B5 | A4 |

Use of Spring Event instead of Guava

Spring has an Event Publisher and allow to create custom events. There is no need to use Guava.

Domain events should be mapped as published events (infra) with stream id, timestamp etc..

Published events can then be added to EventStore and handled by Event Handlers.

Feature: Promotion (rewritten)

Feature: Promotion (rewritten)

Scenario: A pawn must be promoted when it reaches the other side of the chess board

GIVEN a <color> pawn in the penultimate rank (<penultimate-rank>)
WHEN the pawn reaches the other side of the chess board (<last-rank>)
AND the pawn's owner does not promote the pawn
THEN the move is refused because promotion must be done

Example:
    | color | penultimate-rank | last-rank |
    | WHITE | 7 | 8 |
    | BLACK | 2 | 1 |

Scenario: A pawn can not be promoted for pawn nor a king

GIVEN a <color> pawn in the penultimate rank (<penultimate-rank>)
WHEN the pawn reaches the other side of the chess board (<last-rank>)
AND the pawn's owner has chosen to promote it with a <promotion-type>
THEN the promotion is refused because <promotion-type> can not promote

Example:
    | color | penultimate-rank | last-rank | promotion-type |
    | WHITE | 7 | 8 | KING |
    | WHITE | 7 | 8 | PAWN |
    | BLACK | 2 | 1 | KING |
    | BLACK | 2 | 1 | PAWN |

Scenario: A pawn may be promoted for a queen, a rook, a bishop or a knight

GIVEN a <color> pawn in the penultimate rank (<penultimate-rank>)
WHEN the pawn reaches the other side of the chess board (<last-rank>)
AND the pawn's owner has chosen to promote it with a <promotion-type>
THEN a <promotion-type> of the same color replaces the pawn

Example:
    | color | penultimate-rank | last-rank | promotion-type |
    | WHITE | 7 | 8 | QUEEN |
    | WHITE | 7 | 8 | ROOK |
    | WHITE | 7 | 8 | BISHOP |
    | WHITE | 7 | 8 | KNIGHT |
    | BLACK | 2 | 1 | QUEEN |
    | BLACK | 2 | 1 | ROOK |
    | BLACK | 2 | 1 | BISHOP |
    | BLACK | 2 | 1 | KNIGHT |

Scenario: A pawn is promoted when capturing an opposing piece

GIVEN a <color> pawn in <from>
AND an opposing piece in <opponent-location>
WHEN the pawn moves to <opponent-location>
AND the pawn's owner has chosen a valid promotion type
THEN the pawn captures the opposing piece
AND the promotion piece replaces the pawn

Example:
    | color | from | opponent-location |
    | WHITE | B7 | A8 |
    | BLACK | E2 | F1 |

Scenario: Only a pawn can be promoted

WHEN a <type> is promoted (<from> to <to>)
THEN the promotion is refused
WITH "Piece can not be promoted" as reason

Example:
    | type | from | to |
    | KING | B2 | A1 |
    | QUEEN | A3 | A1 |
    | ROOK | A3 | A1 |
    | BISHOP | A3 | C1 |
    | KNIGHT | D2 | F1 |

Feature: Bishop

Feature: Bishop

Scenario: A bishop can move in any direction diagonally, so long as it is not obstructed by another piece

GIVEN a <color> bishop in <from>
AND the diagonal squares between <from> and <to> are vacant
WHEN the bishop is moved <times> <direction>
THEN the bishop is in <to>

Example:
        | color | from | times | direction | to |
        | WHITE | E5 | 3 | FORWARD_LEFT | B8 |
        | WHITE | B8 | 2 | BACKWARD_RIGHT | D6 |
        | WHITE | D6 | 1 | FORWARD_RIGHT | E7 |
        | WHITE | E7 | 4 | BACKWARD_LEFT | A3 |
        | BLACK | D5 | 3 | FORWARD_LEFT | G2 |
        | BLACK | G2 | 2 | BACKWARD_RIGHT | E4 |
        | BLACK | E4 | 2 | FORWARD_RIGHT | C2 |
        | BLACK | C2 | 4 | BACKWARD_LEFT | G6 |

Scenario: A bishop cannot move beyond an obstructed path

GIVEN a <color> bishop in <from>
AND the square <obstructed> is not vacant
WHEN the bishop is moved <time> <direction>
THEN the move is refused

Example:
        | color | from | obstructed | times | direction |
        | WHITE | A1 | C3 | 4 | FORWARD_RIGHT |
        | WHITE | E6 | B3 | 4 | BACKWARD_LEFT |
        | WHITE | C3 | B4 | 1 | FORWARD_LEFT |
        | WHITE | B6 | C5 | 2 | BACKWARD_RIGHT |
        | BLACK | E5 | C3 | 3 | FORWARD_RIGHT |
        | BLACK | D5 | E6 | 2 | BACKWARD_LEFT |
        | BLACK | E5 | G3 | 3 | FORWARD_LEFT |
        | BLACK | D5 | B7 | 2 | BACKWARD_RIGHT |

Scenario: A bishop can capture any opposing piece on the board that is within its bounds of movement

GIVEN a <color> bishop in <from>
AND an opposing piece in <to>
WHEN the bishop is moved to <to>
THEN the bishop captures the opposing piece
Example:
        | color | from | to |
        | WHITE | E5 | B2 |
        | WHITE | C4 | D3 |
        | WHITE | C6 | E8 |
        | WHITE | H1 | A8 |
        | BLACK | E5 | B2 |
        | BLACK | C4 | D3 |
        | BLACK | C6 | E8 |
        | BLACK | H1 | A8 |

Feature: Rook

Feature: Rook

Scenario: A rook can move horizontally and vertically while it is not obstructed

GIVEN a <color> rook in <from>
AND the squares between <from> and <to> are vacant
WHEN the rook is moved <times> <direction>
THEN the rook is in <to>

Example:
        | color | from | times | direction | to |
        | WHITE | A1 | 4 | FORWARD | A5 |
        | WHITE | A5 | 2 | SHIFT_RIGHT | C5 |
        | WHITE | C5 | 2 | SHIFT_LEFT | A5 |
        | WHITE | A5 | 4 | BACKWARD | A1 |
        | BLACK | A8 | 4 | FORWARD | A4 |
        | BLACK | A4 | 2 | SHIFT_LEFT | C4 |
        | BLACK | C4 | 2 | SHIFT_RIGHT | A4 |
        | BLACK | A4 | 4 | BACKWARD | A8 |

Scenario: Rook can not move beyond an obstructed path

GIVEN a <color> rook in <from>
AND the square <obstructed> is not vacant
WHEN the rook is moved <time> <direction>
THEN the move is refused

Example:
        | color | from | obstructed | times | direction |
        | WHITE | A1 | A3 | 4 | FORWARD |
        | WHITE | A5 | C5 | 2 | SHIFT_RIGHT |
        | WHITE | E5 | C5 | 2 | SHIFT_LEFT |
        | WHITE | A5 | A3 | 4 | BACKWARD |
        | BLACK | A8 | A6 | 4 | FORWARD |
        | BLACK | A4 | C4 | 2 | SHIFT_LEFT |
        | BLACK | E4 | C4 | 2 | SHIFT_RIGHT |
        | BLACK | A4 | A6 | 2 | BACKWARD |

Scenario: Rook can capture an opposing piece that obstruct its way

GIVEN a <color> rook in <from>
AND an opposing piece in <to>
WHEN the rook is moved to <to>
THEN the rook captures the opposing piece

Example:
        | color | from | to |
        | WHITE | A1 | A3 |
        | WHITE | A5 | C5 |
        | WHITE | E5 | C5 |
        | WHITE | A5 | A3 |
        | BLACK | A8 | A6 |
        | BLACK | A4 | C4 |
        | BLACK | E4 | C4 |
        | BLACK | A4 | A6 |

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.