Skip to content

Commit

Permalink
feat(king): implemented (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
ecattez authored Feb 5, 2020
1 parent 4564bdf commit 93e3615
Show file tree
Hide file tree
Showing 17 changed files with 612 additions and 30 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ In fact, the piece moves in a shape similar to the uppercase "L". Here are the s

![Knight moves](https://cdn11.bigcommerce.com/s-dlmdd/content/knight-moves.jpg)

## 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](https://cdn11.bigcommerce.com/s-dlmdd/content/king-moves.jpg)

## References

[http://www.chesscoachonline.com/chess-articles/chess-rules](http://www.chesscoachonline.com/chess-articles/chess-rules)
Expand Down
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package dev.ecattez.shahmat.domain.board.piece.king;

import dev.ecattez.shahmat.domain.board.Board;
import dev.ecattez.shahmat.domain.board.Direction;
import dev.ecattez.shahmat.domain.board.Orientation;
import dev.ecattez.shahmat.domain.board.piece.Piece;
import dev.ecattez.shahmat.domain.board.piece.move.AbstractMovingStrategy;
import dev.ecattez.shahmat.domain.board.piece.move.Capture;
import dev.ecattez.shahmat.domain.board.piece.move.MoveOnVacant;
import dev.ecattez.shahmat.domain.board.piece.move.Movement;
import dev.ecattez.shahmat.domain.board.square.Square;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class KingMovingStrategy extends AbstractMovingStrategy {

public static final Direction[] MOVING_DIRECTIONS = Direction.values();

@Override
public List<Movement> getAvailableMovements(Board board, Piece piece, Square from) {
Orientation orientation = piece.orientation();
return Stream.of(MOVING_DIRECTIONS)
.map(direction -> from.findNeighbour(direction, orientation))
.flatMap(Optional::stream)
.filter(neighbour -> !board.hasAlly(neighbour, piece))
.map(neighbour -> toMovement(board, piece, from, neighbour))
.flatMap(Optional::stream)
.collect(Collectors.toList());
}

private Optional<Movement> toMovement(Board board, Piece piece, Square from, Square location) {
if (board.isVacant(location)) {
return Optional.of(new MoveOnVacant(piece, from, location));
}
if (board.hasOpponent(location, piece)) {
return Optional.of(new Capture(piece, from, location, board.getPiece(location)));
}
return Optional.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
import dev.ecattez.shahmat.domain.board.piece.PieceTypeVisitor;
import dev.ecattez.shahmat.domain.board.piece.bishop.BishopMovingStrategy;
import dev.ecattez.shahmat.domain.board.piece.knight.KnightMovingStrategy;
import dev.ecattez.shahmat.domain.board.piece.king.KingMovingStrategy;
import dev.ecattez.shahmat.domain.board.piece.knight.KnightMovingStrategy;
import dev.ecattez.shahmat.domain.board.piece.pawn.PawnMovingStrategy;
import dev.ecattez.shahmat.domain.board.piece.queen.QueenMovingStrategy;
import dev.ecattez.shahmat.domain.board.piece.rook.RookMovingStrategy;
import dev.ecattez.shahmat.domain.board.violation.RuleNotImplemented;

public class MovingRules implements PieceTypeVisitor<MovingStrategy> {

Expand Down Expand Up @@ -48,7 +49,7 @@ public MovingStrategy visitQueen() {

@Override
public MovingStrategy visitKing() {
throw new RuleNotImplemented("King can not move yet");
return new KingMovingStrategy();
}

}
28 changes: 15 additions & 13 deletions src/main/java/dev/ecattez/shahmat/infra/BoardInitializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,23 @@ public BoardInitializer(PubSub pubSub) {

@PostConstruct
private void init() {
ChessGameId chessGameId = ChessGameId.newInstance();

pubSub.dispatch(
chessGameId,
0L,
ChessGame.initalizeBoard(
Collections.emptyList(),
new InitBoard(
GameType.CLASSICAL
for (int i=0; i < 10; i++) {
ChessGameId chessGameId = ChessGameId.newInstance();

pubSub.dispatch(
chessGameId,
0L,
ChessGame.initalizeBoard(
Collections.emptyList(),
new InitBoard(
GameType.CLASSICAL
)
)
)
);
);

Link urlToBoard = HalBoardResource.getBoardLink(IanaLinkRelations.SELF, chessGameId.value);
Link urlToBoard = HalBoardResource.getBoardLink(IanaLinkRelations.SELF, chessGameId.value);

LOGGER.info("Test board initialized - " + urlToBoard);
LOGGER.info("Test board initialized - " + urlToBoard);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package dev.ecattez.shahmat.infra;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.List;

@Configuration
public class CorsConfigurationAdapter extends WebSecurityConfigurerAdapter {

private List<String> allowedOrigins;

public CorsConfigurationAdapter(@Value("${cors.global.allowed-origins}") List<String> allowedOrigins) {
this.allowedOrigins = allowedOrigins;
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors(corsConfigurer -> corsConfigurer.configurationSource(corsConfigurationSource()))
.formLogin();
}

private CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(allowedOrigins);
configuration.setAllowedMethods(List.of("GET","POST", "PUT"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package dev.ecattez.shahmat.infra.controller;

import dev.ecattez.shahmat.infra.aggregate.ChessGameId;
import dev.ecattez.shahmat.infra.projection.BoardInfo;
import dev.ecattez.shahmat.infra.store.EventStore;
import org.springframework.hateoas.CollectionModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.stream.Collectors;

import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;

@RestController
public class RootResource {

private final EventStore eventStore;

public RootResource(EventStore eventStore) {
this.eventStore = eventStore;
}

@GetMapping(produces = "application/prs.hal-forms+json")
public CollectionModel<BoardInfo> listBoards() {
List<BoardInfo> boardsInfo = eventStore.aggregateIds()
.stream()
.map(this::toBoardInfo)
.collect(Collectors.toList());

return new CollectionModel<>(
boardsInfo,
linkTo(
methodOn(RootResource.class).listBoards()
).withSelfRel()
);
}

private BoardInfo toBoardInfo(ChessGameId id) {
return new BoardInfo(
id.value,
"<not_implemented>",
"<not_implemented>",
"<not_implemented>",
false
);
}

}
65 changes: 65 additions & 0 deletions src/main/java/dev/ecattez/shahmat/infra/projection/BoardInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package dev.ecattez.shahmat.infra.projection;

import dev.ecattez.shahmat.infra.controller.HalBoardResource;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.server.core.Relation;

import java.util.Objects;

@Relation(collectionRelation = "boards", itemRelation = "board")
public class BoardInfo extends RepresentationModel<BoardInfo> {

private String id;
private String white;
private String black;
private String turnOf;
private boolean over;

public BoardInfo(String id, String white, String black, String turnOf, boolean over) {
this.id = id;
this.white = white;
this.black = black;
this.turnOf = turnOf;
this.over = over;
this.add(HalBoardResource.getBoardLink(IanaLinkRelations.SELF, id));
}

public String getId() {
return id;
}

public String getWhite() {
return white;
}

public String getBlack() {
return black;
}

public String getTurnOf() {
return turnOf;
}

public boolean isOver() {
return over;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BoardInfo boardInfo = (BoardInfo) o;
return over == boardInfo.over &&
Objects.equals(id, boardInfo.id) &&
Objects.equals(white, boardInfo.white) &&
Objects.equals(black, boardInfo.black) &&
Objects.equals(turnOf, boardInfo.turnOf);
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, white, black, turnOf, over);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.tngtech.junit.dataprovider.DataProvider;
import com.tngtech.junit.dataprovider.DataProviderExtension;
import com.tngtech.junit.dataprovider.UseDataProviderExtension;
import dev.ecattez.shahmat.domain.board.square.Square;
import dev.ecattez.shahmat.domain.board.Rules;
import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith;
Expand Down Expand Up @@ -61,13 +60,13 @@ public void bishop_can_move_in_any_direction_diagonally_so_long_as_it_is_obstruc
public void bishop_can_not_move_beyond_an_obstructed_path(
String color,
String from,
Square obstructedSquare,
String obstructed,
int times,
String direction
) {
stage
.given().a_$_bishop_in_$(color, from)
.and().the_square_$_is_not_vacant(obstructedSquare)
.and().the_square_$_is_not_vacant(obstructed)
.when().the_bishop_is_moved_$_$(times, direction)
.then().the_move_is_refused();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,15 +105,15 @@ public void after() {
return self();
}

public BishopStage the_square_$_is_not_vacant(Square obstructedSquare) {
public BishopStage the_square_$_is_not_vacant(String obstructed) {
Piece anotherPiece = mock(Piece.class);
Mockito.when(anotherPiece.unicode())
.thenReturn("X");

history.add(
new PiecePositioned(
anotherPiece,
obstructedSquare
new Square(obstructed)
)
);
return self();
Expand Down
Loading

0 comments on commit 93e3615

Please sign in to comment.