GameBoard: naive MOVE implementation
This commit is contained in:
parent
8971462c74
commit
1f2ff242e4
@ -85,21 +85,18 @@ public class CordaClient {
|
||||
.getResponce(requestBody);
|
||||
}
|
||||
|
||||
public GameState gameStateGet(HoldingIdentity holdingIdentity, UUID gameStateUuid) {
|
||||
public GameState gameStateGet(HoldingIdentity holdingIdentity, UUID gameUuid) {
|
||||
final RequestBody requestBody = new RequestBody(
|
||||
"gs.get-" + UUID.randomUUID(),
|
||||
"djmil.cordacheckers.gamestate.GetFlow",
|
||||
gameStateUuid);
|
||||
gameUuid);
|
||||
|
||||
return cordaFlowExecute(holdingIdentity, requestBody, RspGameState.class)
|
||||
.getResponce(requestBody);
|
||||
}
|
||||
|
||||
public GameState gameProposalCreate(
|
||||
HoldingIdentity issuer,
|
||||
HoldingIdentity acquier,
|
||||
Piece.Color acquierColor,
|
||||
String message
|
||||
public GameState gameProposalCreate(HoldingIdentity issuer, HoldingIdentity acquier, Piece.Color acquierColor,
|
||||
String message
|
||||
) {
|
||||
final RequestBody requestBody = new RequestBody(
|
||||
"gp.create-" + UUID.randomUUID(),
|
||||
@ -113,53 +110,53 @@ public class CordaClient {
|
||||
.getResponce(requestBody);
|
||||
}
|
||||
|
||||
public GameState gameProposalReject(HoldingIdentity holdingIdentity, UUID gameProposalUuid) {
|
||||
public GameState gameProposalReject(HoldingIdentity holdingIdentity, UUID gameUuid) {
|
||||
final RequestBody requestBody = new RequestBody(
|
||||
"gp.reject-" +UUID.randomUUID(),
|
||||
"djmil.cordacheckers.gameproposal.RejectFlow",
|
||||
gameProposalUuid);
|
||||
gameUuid);
|
||||
|
||||
return cordaFlowExecute(holdingIdentity, requestBody, RspGameState.class)
|
||||
.getResponce(requestBody);
|
||||
}
|
||||
|
||||
public GameState gameProposalCancel(HoldingIdentity holdingIdentity, UUID gameProposalUuid) {
|
||||
public GameState gameProposalCancel(HoldingIdentity holdingIdentity, UUID gameUuid) {
|
||||
final RequestBody requestBody = new RequestBody(
|
||||
"gp.reject-" +UUID.randomUUID(),
|
||||
"djmil.cordacheckers.gameproposal.CancelFlow",
|
||||
gameProposalUuid);
|
||||
gameUuid);
|
||||
|
||||
return cordaFlowExecute(holdingIdentity, requestBody, RspGameState.class)
|
||||
.getResponce(requestBody);
|
||||
}
|
||||
|
||||
public GameState gameProposalAccept(HoldingIdentity holdingIdentity, UUID gameProposalUuid) {
|
||||
public GameState gameProposalAccept(HoldingIdentity holdingIdentity, UUID gameUuid) {
|
||||
final RequestBody requestBody = new RequestBody(
|
||||
"gp.accept-" +UUID.randomUUID(),
|
||||
"djmil.cordacheckers.gameproposal.AcceptFlow",
|
||||
gameProposalUuid);
|
||||
gameUuid);
|
||||
|
||||
return cordaFlowExecute(holdingIdentity, requestBody, RspGameState.class)
|
||||
.getResponce(requestBody);
|
||||
}
|
||||
|
||||
public GameState gameBoardSurrender(HoldingIdentity holdingIdentity, UUID gameBoardUuid) {
|
||||
public GameState gameBoardSurrender(HoldingIdentity holdingIdentity, UUID gameUuid) {
|
||||
final RequestBody requestBody = new RequestBody(
|
||||
"gb.surrender-" +UUID.randomUUID(),
|
||||
"djmil.cordacheckers.gameboard.SurrenderFlow",
|
||||
gameBoardUuid);
|
||||
gameUuid);
|
||||
|
||||
return cordaFlowExecute(holdingIdentity, requestBody, RspGameState.class)
|
||||
.getResponce(requestBody);
|
||||
}
|
||||
|
||||
public GameState gameBoardMove(HoldingIdentity holdingIdentity, UUID gameBoardUuid, List<Integer> move) {
|
||||
public GameState gameBoardMove(HoldingIdentity holdingIdentity, UUID gameUuid, List<Integer> move,
|
||||
String message) {
|
||||
final RequestBody requestBody = new RequestBody(
|
||||
"gb.move-" +UUID.randomUUID(),
|
||||
"djmil.cordacheckers.gameboard.CommandFlow",
|
||||
"djmil.cordacheckers.gameboard.MoveFlow",
|
||||
new ReqGameBoardMove(
|
||||
gameBoardUuid,
|
||||
move));
|
||||
move, gameUuid, message));
|
||||
|
||||
return cordaFlowExecute(holdingIdentity, requestBody, RspGameState.class)
|
||||
.getResponce(requestBody);
|
||||
|
@ -42,4 +42,20 @@ public class Piece {
|
||||
return color +"." +type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Piece other = (Piece) obj;
|
||||
if (color != other.color)
|
||||
return false;
|
||||
if (type != other.type)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,8 +4,9 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public record ReqGameBoardMove(
|
||||
UUID gameBoardUuid,
|
||||
List<Integer> move
|
||||
List<Integer> move,
|
||||
UUID gameUuid,
|
||||
String message
|
||||
) {
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,9 @@ package djmil.cordacheckers.cordaclient;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@ -23,6 +26,11 @@ public class GameBoardTests {
|
||||
final String whitePlayerName = "alice";
|
||||
final String blackPlayerName = "bob";
|
||||
|
||||
final static Piece WHITE_MAN = new Piece(Piece.Color.WHITE, Piece.Type.MAN);
|
||||
final static Piece WHITE_KING = new Piece(Piece.Color.WHITE, Piece.Type.KING);
|
||||
final static Piece BLACK_MAN = new Piece(Piece.Color.BLACK, Piece.Type.MAN);
|
||||
final static Piece BLACK_KING = new Piece(Piece.Color.BLACK, Piece.Type.KING);
|
||||
|
||||
@Test
|
||||
void testSurrender() {
|
||||
final var hiWhite = holdingIdentityResolver.getByUsername(whitePlayerName);
|
||||
@ -60,4 +68,37 @@ public class GameBoardTests {
|
||||
assertThat(winnerGameView.status()).isEqualByComparingTo(Status.GAME_RESULT_YOU_WON);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMove() {
|
||||
final var hiWhite = holdingIdentityResolver.getByUsername(whitePlayerName);
|
||||
final var hiBlack = holdingIdentityResolver.getByUsername(blackPlayerName);
|
||||
final String message = "GameBoard MOVE test";
|
||||
|
||||
final GameState game = cordaClient.gameProposalCreate(
|
||||
hiWhite, hiBlack, Piece.Color.BLACK, message);
|
||||
System.out.println("Game UUID " +game.uuid());
|
||||
|
||||
final var m0 = cordaClient.gameProposalAccept(hiBlack, game.uuid());
|
||||
|
||||
assertThatThrownBy(() -> {
|
||||
cordaClient.gameBoardMove(hiBlack, game.uuid(), move(12, 16),
|
||||
"Black can not move, since it is opponent's turn");
|
||||
});
|
||||
|
||||
assertThatThrownBy(() -> {
|
||||
cordaClient.gameBoardMove(hiWhite, game.uuid(), move(17, 14),
|
||||
"Trying to move an empty tile");
|
||||
});
|
||||
|
||||
final var m1 = cordaClient.gameBoardMove(hiWhite, game.uuid(), move(22, 18), null);
|
||||
assertThat(m0.board().get(22)).isEqualTo(WHITE_MAN);
|
||||
assertThat(m0.board().get(18)).isNull();
|
||||
assertThat(m1.board().get(22)).isNull();
|
||||
assertThat(m1.board().get(18)).isEqualTo(WHITE_MAN);
|
||||
assertThat(m1.status()).isEqualByComparingTo(Status.GAME_BOARD_WAIT_FOR_OPPONENT);
|
||||
}
|
||||
|
||||
ArrayList<Integer> move(int from, int to) {
|
||||
return new ArrayList<Integer>(Arrays.asList(from, to));
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import djmil.cordacheckers.cordaclient.dao.GameState;
|
||||
import djmil.cordacheckers.cordaclient.dao.GameState.Status;
|
||||
import djmil.cordacheckers.cordaclient.dao.Piece;
|
||||
import djmil.cordacheckers.cordaclient.dao.Rank;
|
||||
import djmil.cordacheckers.user.HoldingIdentityResolver;
|
||||
@ -25,6 +24,8 @@ public class RankingTests {
|
||||
@Test
|
||||
void testGlobalRanking() {
|
||||
final var hiCustodian = holdingIdentityResolver.getCustodian();
|
||||
assertThat(hiCustodian).isNotNull();
|
||||
|
||||
final List<Rank> liderboard1 = cordaClient.fetchRanking(hiCustodian);
|
||||
|
||||
final var hiWinner = holdingIdentityResolver.getByUsername("Charlie");
|
||||
|
@ -3,12 +3,34 @@ package djmil.cordacheckers.contracts;
|
||||
import static djmil.cordacheckers.contracts.GameCommand.requireThat;
|
||||
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleCommand;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import djmil.cordacheckers.states.Piece;
|
||||
import djmil.cordacheckers.states.Piece.Color;
|
||||
import net.corda.v5.ledger.utxo.transaction.UtxoLedgerTransaction;
|
||||
|
||||
public class GameBoardContract implements net.corda.v5.ledger.utxo.Contract {
|
||||
|
||||
public static class MoveResult {
|
||||
final public Map<Integer, Piece> board;
|
||||
final public Piece.Color moveColor;
|
||||
|
||||
public MoveResult(Map<Integer, Piece> board, Color moveColor) {
|
||||
this.board = board;
|
||||
this.moveColor = moveColor;
|
||||
}
|
||||
|
||||
public static class Exception extends RuntimeException {
|
||||
public Exception(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final static Logger log = LoggerFactory.getLogger(GameBoardContract.class);
|
||||
|
||||
@ -19,13 +41,13 @@ public class GameBoardContract implements net.corda.v5.ledger.utxo.Contract {
|
||||
requireThat(trx.getCommands().size() == 1, GameCommand.REQUIRE_SINGLE_COMMAND);
|
||||
final GameCommand command = getSingleCommand(trx, GameCommand.class);
|
||||
|
||||
switch (command.action) {
|
||||
switch (command.getAction()) {
|
||||
case GAME_PROPOSAL_ACCEPT:
|
||||
command.validateGameProposalAccept(trx);
|
||||
break;
|
||||
|
||||
case GAME_BOARD_MOVE:
|
||||
command.validateGameBoardMove(trx);
|
||||
command.validateGameBoardMove(trx, command.getMove());
|
||||
break;
|
||||
|
||||
case GAME_BOARD_SURRENDER:
|
||||
@ -37,4 +59,60 @@ public class GameBoardContract implements net.corda.v5.ledger.utxo.Contract {
|
||||
}
|
||||
}
|
||||
|
||||
public static MoveResult applyMove(List<Integer> move, Map<Integer, Piece> board, Piece.Color moveColor) {
|
||||
final int mFrom = move.get(0);
|
||||
final int mTo = move.get(1);
|
||||
|
||||
final Piece piece = board.get(mFrom);
|
||||
if (piece == null)
|
||||
throw new MoveResult.Exception("An empty starting tile");
|
||||
|
||||
if (piece.getColor() != moveColor)
|
||||
throw new MoveResult.Exception("Can not move opponent's piece");
|
||||
|
||||
if (board.get(mTo) != null)
|
||||
throw new MoveResult.Exception("An occupied finishing tile");
|
||||
|
||||
final Map<Integer, Piece> newBoard = new LinkedHashMap<Integer, Piece>(board);
|
||||
newBoard.remove(mFrom);
|
||||
newBoard.put(mTo, piece);
|
||||
|
||||
return new GameBoardContract.MoveResult(newBoard, moveColor.opposite());
|
||||
}
|
||||
|
||||
final static Piece WHITE_MAN = new Piece(Piece.Color.WHITE, Piece.Type.MAN);
|
||||
final static Piece WHITE_KING = new Piece(Piece.Color.WHITE, Piece.Type.KING);
|
||||
final static Piece BLACK_MAN = new Piece(Piece.Color.BLACK, Piece.Type.MAN);
|
||||
final static Piece BLACK_KING = new Piece(Piece.Color.BLACK, Piece.Type.KING);
|
||||
|
||||
public final static Map<Integer, Piece> initialBoard = Map.ofEntries(
|
||||
// Inspired by Checkers notation rules: https://www.bobnewell.net/nucleus/checkers.php
|
||||
Map.entry( 1, BLACK_MAN),
|
||||
Map.entry( 2, BLACK_MAN),
|
||||
Map.entry( 3, BLACK_MAN),
|
||||
Map.entry( 4, BLACK_MAN),
|
||||
Map.entry( 5, BLACK_MAN),
|
||||
Map.entry( 6, BLACK_MAN),
|
||||
Map.entry( 7, BLACK_MAN),
|
||||
Map.entry( 8, BLACK_MAN),
|
||||
Map.entry( 9, BLACK_MAN),
|
||||
Map.entry(10, BLACK_MAN),
|
||||
Map.entry(11, BLACK_MAN),
|
||||
Map.entry(12, BLACK_MAN),
|
||||
|
||||
Map.entry(21, WHITE_MAN),
|
||||
Map.entry(22, WHITE_MAN),
|
||||
Map.entry(23, WHITE_MAN),
|
||||
Map.entry(24, WHITE_MAN),
|
||||
Map.entry(25, WHITE_MAN),
|
||||
Map.entry(26, WHITE_MAN),
|
||||
Map.entry(27, WHITE_MAN),
|
||||
Map.entry(28, WHITE_MAN),
|
||||
Map.entry(29, WHITE_MAN),
|
||||
Map.entry(30, WHITE_MAN),
|
||||
Map.entry(31, WHITE_MAN),
|
||||
Map.entry(32, WHITE_MAN)
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ public class GameCommand implements Command {
|
||||
GAME_RESULT_CREATE;
|
||||
}
|
||||
|
||||
public final Action action;
|
||||
public final List<Integer> move; // [0] from, [1] to
|
||||
private final Action action;
|
||||
private final List<Integer> move;
|
||||
|
||||
public static class ActionException extends RuntimeException {
|
||||
public ActionException() {
|
||||
@ -156,6 +156,7 @@ public class GameCommand implements Command {
|
||||
final GameBoardState outGameBoard = getSingleOutputState(trx, GameBoardState.class);
|
||||
|
||||
requireThat(inGameProposal.getParticipants().containsAll(outGameBoard.getParticipants()), IN_OUT_PARTICIPANTS);
|
||||
requireThat(outGameBoard.getBoard().equals(GameBoardContract.initialBoard), "Bad GameBoard initial state");
|
||||
}
|
||||
|
||||
public void validateGameProposalReject(UtxoLedgerTransaction trx) {
|
||||
@ -197,7 +198,7 @@ public class GameCommand implements Command {
|
||||
"Expected winner "+expectedWinnerName.getCommonName() +", proposed winner " +outGameResultState.getWinnerName().getCommonName());
|
||||
}
|
||||
|
||||
public void validateGameBoardMove(UtxoLedgerTransaction trx) {
|
||||
public void validateGameBoardMove(UtxoLedgerTransaction trx, List<Integer> move) {
|
||||
requireThat(trx.getInputContractStates().size() == 1, MOVE_INPUT_STATE);
|
||||
final var inGameBoardState = getSingleInputState(trx, GameBoardState.class);
|
||||
|
||||
@ -206,6 +207,9 @@ public class GameCommand implements Command {
|
||||
|
||||
requireThat(inGameBoardState.getWhitePlayer().compareTo(outGameBoardState.getWhitePlayer()) == 0, IN_OUT_PARTICIPANTS);
|
||||
requireThat(inGameBoardState.getBlackPlayer().compareTo(outGameBoardState.getBlackPlayer()) == 0, IN_OUT_PARTICIPANTS);
|
||||
|
||||
final var newGameBoard = new GameBoardState(inGameBoardState, move, outGameBoardState.getMessage());
|
||||
requireThat(outGameBoardState.equals(newGameBoard), "Unexpected output state");
|
||||
}
|
||||
|
||||
public void validateGameResultCreate(UtxoLedgerTransaction trx) {
|
||||
|
@ -19,7 +19,7 @@ public class GameProposalContract implements net.corda.v5.ledger.utxo.Contract {
|
||||
requireThat(trx.getCommands().size() == 1, GameCommand.REQUIRE_SINGLE_COMMAND);
|
||||
final GameCommand command = getSingleCommand(trx, GameCommand.class);
|
||||
|
||||
switch (command.action) {
|
||||
switch (command.getAction()) {
|
||||
case GAME_PROPOSAL_CREATE:
|
||||
command.validateGameProposalCreate(trx);
|
||||
break;
|
||||
|
@ -19,7 +19,7 @@ public class GameResultContract implements net.corda.v5.ledger.utxo.Contract {
|
||||
requireThat(trx.getCommands().size() == 1, GameCommand.REQUIRE_SINGLE_COMMAND);
|
||||
final GameCommand command = getSingleCommand(trx, GameCommand.class);
|
||||
|
||||
switch (command.action) {
|
||||
switch (command.getAction()) {
|
||||
case GAME_BOARD_SURRENDER:
|
||||
command.validateGameBoardSurrender(trx);
|
||||
break;
|
||||
|
@ -7,6 +7,7 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import djmil.cordacheckers.contracts.GameBoardContract;
|
||||
import djmil.cordacheckers.contracts.GameBoardContract.MoveResult;
|
||||
import djmil.cordacheckers.states.Piece.Color;
|
||||
import net.corda.v5.base.annotations.ConstructorForDeserialization;
|
||||
import net.corda.v5.base.types.MemberX500Name;
|
||||
@ -22,19 +23,22 @@ public class GameBoardState extends GameState {
|
||||
super(gameProposalState.whitePlayer, gameProposalState.blackPlayer,
|
||||
gameProposalState.gameUuid, gameProposalState.message, gameProposalState.participants);
|
||||
|
||||
// Initial GameBoard state
|
||||
this.board = new LinkedHashMap<Integer, Piece>(GameBoardContract.initialBoard);
|
||||
this.moveColor = Piece.Color.WHITE;
|
||||
this.moveNumber = 0;
|
||||
this.board = new LinkedHashMap<Integer, Piece>(initialBoard);
|
||||
}
|
||||
|
||||
public GameBoardState(GameBoardState oldGameBoardState, Map<Integer, Piece> newBoard, Piece.Color moveColor) {
|
||||
super(oldGameBoardState.whitePlayer, oldGameBoardState.blackPlayer,
|
||||
oldGameBoardState.gameUuid, oldGameBoardState.message, oldGameBoardState.participants);
|
||||
public GameBoardState(GameBoardState currentGameBoardState, List<Integer> move, String message) {
|
||||
super(currentGameBoardState.whitePlayer, currentGameBoardState.blackPlayer, currentGameBoardState.gameUuid,
|
||||
message, currentGameBoardState.participants);
|
||||
|
||||
this.moveColor = moveColor;
|
||||
this.moveNumber = oldGameBoardState.getMoveNumber() +1;
|
||||
this.board = newBoard;
|
||||
final MoveResult moveResult = GameBoardContract.applyMove(move, currentGameBoardState.getBoard(), currentGameBoardState.getMoveColor());
|
||||
this.moveColor = moveResult.moveColor;
|
||||
this.board = moveResult.board;
|
||||
|
||||
this.moveNumber = (currentGameBoardState.moveColor == this.moveColor)
|
||||
? currentGameBoardState.getMoveNumber() // current player has not finished his move jet
|
||||
: currentGameBoardState.getMoveNumber() +1;
|
||||
}
|
||||
|
||||
@ConstructorForDeserialization
|
||||
@ -64,33 +68,29 @@ public class GameBoardState extends GameState {
|
||||
return board;
|
||||
}
|
||||
|
||||
// TODO: move to contract
|
||||
public final static Map<Integer, Piece> initialBoard = Map.ofEntries(
|
||||
// Inspired by Checkers notation rules: https://www.bobnewell.net/nucleus/checkers.php
|
||||
Map.entry( 1, new Piece(Piece.Color.BLACK, Piece.Type.MAN)),
|
||||
Map.entry( 2, new Piece(Piece.Color.BLACK, Piece.Type.MAN)),
|
||||
Map.entry( 3, new Piece(Piece.Color.BLACK, Piece.Type.MAN)),
|
||||
Map.entry( 4, new Piece(Piece.Color.BLACK, Piece.Type.MAN)),
|
||||
Map.entry( 5, new Piece(Piece.Color.BLACK, Piece.Type.MAN)),
|
||||
Map.entry( 6, new Piece(Piece.Color.BLACK, Piece.Type.MAN)),
|
||||
Map.entry( 7, new Piece(Piece.Color.BLACK, Piece.Type.MAN)),
|
||||
Map.entry( 8, new Piece(Piece.Color.BLACK, Piece.Type.MAN)),
|
||||
Map.entry( 9, new Piece(Piece.Color.BLACK, Piece.Type.MAN)),
|
||||
Map.entry(10, new Piece(Piece.Color.BLACK, Piece.Type.MAN)),
|
||||
Map.entry(11, new Piece(Piece.Color.BLACK, Piece.Type.MAN)),
|
||||
Map.entry(12, new Piece(Piece.Color.BLACK, Piece.Type.MAN)),
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
GameBoardState other = (GameBoardState) obj;
|
||||
if (moveColor != other.moveColor)
|
||||
return false;
|
||||
if (moveNumber == null) {
|
||||
if (other.moveNumber != null)
|
||||
return false;
|
||||
} else if (!moveNumber.equals(other.moveNumber))
|
||||
return false;
|
||||
if (board == null) {
|
||||
if (other.board != null)
|
||||
return false;
|
||||
} else if (!board.equals(other.board))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Map.entry(21, new Piece(Piece.Color.WHITE, Piece.Type.MAN)),
|
||||
Map.entry(22, new Piece(Piece.Color.WHITE, Piece.Type.MAN)),
|
||||
Map.entry(23, new Piece(Piece.Color.WHITE, Piece.Type.MAN)),
|
||||
Map.entry(24, new Piece(Piece.Color.WHITE, Piece.Type.MAN)),
|
||||
Map.entry(25, new Piece(Piece.Color.WHITE, Piece.Type.MAN)),
|
||||
Map.entry(26, new Piece(Piece.Color.WHITE, Piece.Type.MAN)),
|
||||
Map.entry(27, new Piece(Piece.Color.WHITE, Piece.Type.MAN)),
|
||||
Map.entry(28, new Piece(Piece.Color.WHITE, Piece.Type.MAN)),
|
||||
Map.entry(29, new Piece(Piece.Color.WHITE, Piece.Type.MAN)),
|
||||
Map.entry(30, new Piece(Piece.Color.WHITE, Piece.Type.MAN)),
|
||||
Map.entry(31, new Piece(Piece.Color.WHITE, Piece.Type.MAN)),
|
||||
Map.entry(32, new Piece(Piece.Color.WHITE, Piece.Type.MAN))
|
||||
);
|
||||
|
||||
}
|
||||
|
@ -17,21 +17,14 @@ public class Piece {
|
||||
WHITE,
|
||||
BLACK;
|
||||
|
||||
public static Color oppositOf(Color color) {
|
||||
switch (color) {
|
||||
public Color opposite() {
|
||||
switch (this) {
|
||||
case WHITE:
|
||||
return BLACK;
|
||||
case BLACK:
|
||||
return WHITE;
|
||||
default:
|
||||
throw new UnknownException();
|
||||
}
|
||||
}
|
||||
|
||||
public static class UnknownException extends RuntimeException {
|
||||
public UnknownException() {
|
||||
super("Unknown Color value");
|
||||
}
|
||||
throw new RuntimeException("Unknown Color");
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,4 +45,20 @@ public class Piece {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Piece other = (Piece) obj;
|
||||
if (color != other.color)
|
||||
return false;
|
||||
if (type != other.type)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,85 @@
|
||||
package djmil.cordacheckers.gameboard;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import djmil.cordacheckers.contracts.GameCommand;
|
||||
import djmil.cordacheckers.gamestate.CommitSubFlow;
|
||||
import djmil.cordacheckers.gamestate.FlowResponce;
|
||||
import djmil.cordacheckers.gamestate.GetFlow;
|
||||
import djmil.cordacheckers.gamestate.View;
|
||||
import djmil.cordacheckers.gamestate.ViewBuilder;
|
||||
import djmil.cordacheckers.states.GameBoardState;
|
||||
import djmil.cordacheckers.states.GameState;
|
||||
import net.corda.v5.application.flows.ClientRequestBody;
|
||||
import net.corda.v5.application.flows.ClientStartableFlow;
|
||||
import net.corda.v5.application.flows.CordaInject;
|
||||
import net.corda.v5.application.flows.FlowEngine;
|
||||
import net.corda.v5.application.marshalling.JsonMarshallingService;
|
||||
import net.corda.v5.base.annotations.Suspendable;
|
||||
import net.corda.v5.crypto.SecureHash;
|
||||
import net.corda.v5.ledger.utxo.StateAndRef;
|
||||
import net.corda.v5.ledger.utxo.UtxoLedgerService;
|
||||
import net.corda.v5.ledger.utxo.transaction.UtxoSignedTransaction;
|
||||
|
||||
public class MoveFlow implements ClientStartableFlow{
|
||||
|
||||
private final static Logger log = LoggerFactory.getLogger(MoveFlow.class);
|
||||
|
||||
@CordaInject
|
||||
public JsonMarshallingService jsonMarshallingService;
|
||||
|
||||
@CordaInject
|
||||
public UtxoLedgerService utxoLedgerService;
|
||||
|
||||
@CordaInject
|
||||
public FlowEngine flowEngine;
|
||||
|
||||
@Suspendable
|
||||
@Override
|
||||
public String call(ClientRequestBody requestBody) {
|
||||
SecureHash utxoTrxId = null;
|
||||
|
||||
try {
|
||||
final MoveFlowArgs args = requestBody.getRequestBodyAs(jsonMarshallingService, MoveFlowArgs.class);
|
||||
|
||||
final GameCommand command = new GameCommand(args.move);
|
||||
|
||||
final StateAndRef<GameState> currntGameBoardSar = this.flowEngine
|
||||
.subFlow(new GetFlow(args.gameUuid));
|
||||
|
||||
final GameBoardState newGameBoard = new GameBoardState(
|
||||
(GameBoardState)currntGameBoardSar.getState().getContractState(),
|
||||
args.move,
|
||||
args.message);
|
||||
|
||||
final UtxoSignedTransaction gameBoardMoveTrx = utxoLedgerService.createTransactionBuilder()
|
||||
.addCommand(command)
|
||||
.addInputState(currntGameBoardSar.getRef())
|
||||
.addOutputState(newGameBoard)
|
||||
.addSignatories(newGameBoard.getParticipants())
|
||||
.setNotary(currntGameBoardSar.getState().getNotaryName())
|
||||
.setTimeWindowUntil(Instant.now().plusMillis(Duration.ofDays(1).toMillis()))
|
||||
.toSignedTransaction();
|
||||
|
||||
utxoTrxId = this.flowEngine
|
||||
.subFlow(new CommitSubFlow(gameBoardMoveTrx, command.getCounterparty(currntGameBoardSar)));
|
||||
|
||||
final View gameStateView = this.flowEngine
|
||||
.subFlow(new ViewBuilder(utxoTrxId));
|
||||
|
||||
return new FlowResponce(gameStateView, utxoTrxId)
|
||||
.toJsonEncodedString(jsonMarshallingService);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn(requestBody + " " +e.getClass() +": " +e.getMessage());
|
||||
e.printStackTrace(System.out);
|
||||
return new FlowResponce(e, utxoTrxId)
|
||||
.toJsonEncodedString(jsonMarshallingService);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package djmil.cordacheckers.gameboard;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class MoveFlowArgs {
|
||||
public final List<Integer> move;
|
||||
public final UUID gameUuid;
|
||||
public final String message;
|
||||
|
||||
// Serialisation service requires a default constructor
|
||||
public MoveFlowArgs() {
|
||||
this.move = null;
|
||||
this.gameUuid = null;
|
||||
this.message = null;
|
||||
}
|
||||
}
|
@ -21,10 +21,8 @@ import net.corda.v5.application.flows.ClientStartableFlow;
|
||||
import net.corda.v5.application.flows.CordaInject;
|
||||
import net.corda.v5.application.flows.FlowEngine;
|
||||
import net.corda.v5.application.marshalling.JsonMarshallingService;
|
||||
import net.corda.v5.application.membership.MemberLookup;
|
||||
import net.corda.v5.base.annotations.Suspendable;
|
||||
import net.corda.v5.crypto.SecureHash;
|
||||
import net.corda.v5.ledger.common.NotaryLookup;
|
||||
import net.corda.v5.ledger.utxo.StateAndRef;
|
||||
import net.corda.v5.ledger.utxo.UtxoLedgerService;
|
||||
import net.corda.v5.ledger.utxo.transaction.UtxoSignedTransaction;
|
||||
@ -36,12 +34,6 @@ public class SurrenderFlow implements ClientStartableFlow{
|
||||
@CordaInject
|
||||
public JsonMarshallingService jsonMarshallingService;
|
||||
|
||||
@CordaInject
|
||||
public MemberLookup memberLookup;
|
||||
|
||||
@CordaInject
|
||||
public NotaryLookup notaryLookup;
|
||||
|
||||
@CordaInject
|
||||
public UtxoLedgerService utxoLedgerService;
|
||||
|
||||
|
@ -76,7 +76,7 @@ public class CommitSubFlowResponder implements ResponderFlow {
|
||||
*/
|
||||
@Suspendable
|
||||
GameState getActualGameStateFromTransaction(UtxoLedgerTransaction gameStateTransaction, GameCommand command) {
|
||||
switch (command.action) {
|
||||
switch (command.getAction()) {
|
||||
case GAME_PROPOSAL_CREATE:
|
||||
return getSingleOutputState(gameStateTransaction, GameProposalState.class);
|
||||
|
||||
@ -89,7 +89,7 @@ public class CommitSubFlowResponder implements ResponderFlow {
|
||||
return getSingleInputState(gameStateTransaction, GameBoardState.class);
|
||||
|
||||
case GAME_BOARD_MOVE:
|
||||
return getSingleOutputState(gameStateTransaction, GameBoardState.class);
|
||||
return getSingleInputState(gameStateTransaction, GameBoardState.class);
|
||||
|
||||
case GAME_RESULT_CREATE:
|
||||
return getSingleOutputState(gameStateTransaction, GameResultState.class);
|
||||
|
@ -17,7 +17,7 @@ public class FlowResponce {
|
||||
public FlowResponce(Exception exception, SecureHash transactionId) {
|
||||
this.successStatus = null;
|
||||
this.transactionId = transactionId;
|
||||
this.failureStatus = exception.getMessage();
|
||||
this.failureStatus = exception.toString();
|
||||
}
|
||||
|
||||
public String toJsonEncodedString(JsonMarshallingService jsonMarshallingService) {
|
||||
|
@ -51,7 +51,7 @@ public class ViewBuilder implements SubFlow<View> {
|
||||
final GameState state = getLatestGameStateFromTransaction(gameStateUtxo, command);
|
||||
final View.Status viewStatus = action2status(command, state, myName);
|
||||
|
||||
switch (command.action) {
|
||||
switch (command.getAction()) {
|
||||
case GAME_PROPOSAL_CREATE:
|
||||
case GAME_PROPOSAL_CANCEL:
|
||||
case GAME_PROPOSAL_REJECT:
|
||||
@ -62,7 +62,7 @@ public class ViewBuilder implements SubFlow<View> {
|
||||
case GAME_PROPOSAL_ACCEPT:
|
||||
case GAME_BOARD_MOVE:
|
||||
if (state instanceof GameBoardState)
|
||||
return new View(viewStatus, (GameBoardState)state, command.move, myName);
|
||||
return new View(viewStatus, (GameBoardState)state, command.getMove(), myName);
|
||||
break;
|
||||
|
||||
case GAME_BOARD_SURRENDER:
|
||||
@ -85,7 +85,7 @@ public class ViewBuilder implements SubFlow<View> {
|
||||
*/
|
||||
@Suspendable
|
||||
GameState getLatestGameStateFromTransaction(UtxoLedgerTransaction gameStateTransaction, GameCommand command) {
|
||||
switch (command.action) {
|
||||
switch (command.getAction()) {
|
||||
case GAME_PROPOSAL_CREATE:
|
||||
return getSingleOutputState(gameStateTransaction, GameProposalState.class);
|
||||
|
||||
@ -109,7 +109,7 @@ public class ViewBuilder implements SubFlow<View> {
|
||||
View.Status action2status(GameCommand command, GameState state, MemberX500Name myName) {
|
||||
final boolean myAction = command.getInitiator(state).compareTo(myName) == 0;
|
||||
|
||||
switch (command.action) {
|
||||
switch (command.getAction()) {
|
||||
case GAME_PROPOSAL_CREATE:
|
||||
if (myAction)
|
||||
return View.Status.GAME_PROPOSAL_WAIT_FOR_OPPONENT;
|
||||
|
Loading…
Reference in New Issue
Block a user