a simple source of truth about UtxoGameState transaction for
- ViewBuilder
- CommitSubFlowResponder
This commit is contained in:
djmil 2023-09-30 20:09:25 +02:00
parent 729384fb62
commit eb1e7fd93c
10 changed files with 152 additions and 194 deletions

View File

@ -9,7 +9,7 @@ public interface Rsp <T> {
public default T getResponce(RequestBody requestBody) { public default T getResponce(RequestBody requestBody) {
if (failureStatus() != null) { if (failureStatus() != null) {
final String msg = requestBody.flowClassName() +" requestId " +requestBody.clientRequestId() +" has failed: " +failureStatus(); final String msg = requestBody.flowClassName() +" requestId " +requestBody.clientRequestId() +" has failed: " +failureStatus();
System.err.println(msg +". Reson " +failureStatus()); System.err.println(msg);
throw new RuntimeException(msg); throw new RuntimeException(msg);
} }

View File

@ -48,23 +48,24 @@ public class GameBoardTests {
assertThat(acceptedGameBlackView.opponentColor()).isEqualByComparingTo(Stone.Color.WHITE); assertThat(acceptedGameBlackView.opponentColor()).isEqualByComparingTo(Stone.Color.WHITE);
assertThat(acceptedGameBlackView.status()).isEqualByComparingTo(Status.GAME_BOARD_WAIT_FOR_OPPONENT); assertThat(acceptedGameBlackView.status()).isEqualByComparingTo(Status.GAME_BOARD_WAIT_FOR_OPPONENT);
assertThatThrownBy(() -> { // Black can not surrender, since it is opponent's turn // Black shall be able to surrender, even if it is not his turn
cordaClient.gameBoardSurrender(
hiBlack, game.uuid());
});
final GameState surrendererGameView = cordaClient.gameBoardSurrender( final GameState surrendererGameView = cordaClient.gameBoardSurrender(
hiWhite, game.uuid());
assertThat(surrendererGameView.opponentName()).isEqualToIgnoringCase(blackPlayerName);
assertThat(surrendererGameView.opponentColor()).isEqualByComparingTo(Stone.Color.BLACK);
assertThat(surrendererGameView.status()).isEqualByComparingTo(Status.GAME_RESULT_YOU_LOOSE);
final GameState winnerGameView = cordaClient.gameStateGet(
hiBlack, game.uuid()); hiBlack, game.uuid());
assertThat(winnerGameView.opponentName()).isEqualToIgnoringCase(whitePlayerName); assertThat(surrendererGameView.opponentName()).isEqualToIgnoringCase(whitePlayerName);
assertThat(winnerGameView.opponentColor()).isEqualByComparingTo(Stone.Color.WHITE); assertThat(surrendererGameView.opponentColor()).isEqualByComparingTo(Stone.Color.WHITE);
assertThat(surrendererGameView.status()).isEqualByComparingTo(Status.GAME_RESULT_YOU_LOOSE);
assertThatThrownBy(() -> { // White can not surrender, since Black already did
cordaClient.gameBoardSurrender(
hiWhite, game.uuid());
});
final GameState winnerGameView = cordaClient.gameStateGet(
hiWhite, game.uuid());
assertThat(winnerGameView.opponentName()).isEqualToIgnoringCase(blackPlayerName);
assertThat(winnerGameView.opponentColor()).isEqualByComparingTo(Stone.Color.BLACK);
assertThat(winnerGameView.status()).isEqualByComparingTo(Status.GAME_RESULT_YOU_WON); assertThat(winnerGameView.status()).isEqualByComparingTo(Status.GAME_RESULT_YOU_WON);
} }

View File

@ -27,8 +27,7 @@ public class GameCommand implements Command {
GAME_BOARD_MOVE, GAME_BOARD_MOVE,
GAME_BOARD_SURRENDER, GAME_BOARD_SURRENDER,
GAME_BOARD_VICTORY;
GAME_RESULT_CREATE;
} }
private final Action action; private final Action action;
@ -72,61 +71,42 @@ public class GameCommand implements Command {
public List<Integer> getMove() { public List<Integer> getMove() {
return move; return move;
} }
/*
* Session initiator/respondent
*/
public MemberX500Name getCounterparty(StateAndRef<GameState> gameStateSar) { public MemberX500Name getCounterparty(StateAndRef<GameState> gameStateSar) {
final GameState gameState = gameStateSar.getState().getContractState(); return getCounterparty(gameStateSar.getState().getContractState());
return gameState.getOpponentName(getInitiator(gameState));
} }
public MemberX500Name getCounterparty(GameState gameState) { public MemberX500Name getCounterparty(GameState gameState) {
return gameState.getOpponentName(getInitiator(gameState)); switch (this.action) {
}
public MemberX500Name getInitiator(StateAndRef<GameState> gameStateSar) {
return getInitiator(gameStateSar.getState().getContractState());
}
public MemberX500Name getInitiator(GameState gameState) {
switch (action) {
case GAME_PROPOSAL_CREATE: case GAME_PROPOSAL_CREATE:
case GAME_PROPOSAL_CANCEL: case GAME_PROPOSAL_CANCEL:
if (gameState instanceof GameProposalState)
return ((GameProposalState)gameState).getIssuerName();
break;
case GAME_PROPOSAL_REJECT:
if (gameState instanceof GameProposalState) if (gameState instanceof GameProposalState)
return ((GameProposalState)gameState).getAcquierName(); return ((GameProposalState)gameState).getAcquierName();
break; break;
case GAME_PROPOSAL_ACCEPT:
if (gameState instanceof GameProposalState) // <<-- Session validation perspective
return ((GameProposalState)gameState).getAcquierName();
if (gameState instanceof GameBoardState) // <<-- GameViewBuilder perspective
return ((GameBoardState)gameState).getActivePlayerName();
break;
case GAME_BOARD_SURRENDER: case GAME_PROPOSAL_ACCEPT:
if (gameState instanceof GameBoardState) // <<-- Session validation perspective case GAME_PROPOSAL_REJECT:
return ((GameBoardState)gameState).getActivePlayerName(); if (gameState instanceof GameProposalState)
if (gameState instanceof GameResultState) // <<-- GameViewBuilder perspective return ((GameProposalState)gameState).getIssuerName();
return ((GameResultState)gameState).getLooserName();
break; break;
case GAME_BOARD_MOVE: case GAME_BOARD_MOVE:
if (gameState instanceof GameBoardState) if (gameState instanceof GameBoardState) {
return ((GameBoardState)gameState).getActivePlayerName(); final var activePlayer = ((GameBoardState)gameState).getActivePlayerName();
return gameState.getOpponentName(activePlayer);
}
break; break;
case GAME_RESULT_CREATE: case GAME_BOARD_SURRENDER:
if (gameState instanceof GameResultState) if (gameState instanceof GameResultState)
return ((GameResultState)gameState).getWinnerName(); return ((GameResultState)gameState).getWinnerName();
break; break;
case GAME_BOARD_VICTORY:
if (gameState instanceof GameResultState)
return ((GameResultState)gameState).getLooserName();
break;
default: default:
throw new ActionException(); throw new ActionException();
} }
@ -192,10 +172,10 @@ public class GameCommand implements Command {
requireThat(inActors.containsAll(outActors) && outActors.containsAll(inActors), IN_OUT_PARTICIPANTS); requireThat(inActors.containsAll(outActors) && outActors.containsAll(inActors), IN_OUT_PARTICIPANTS);
final var activePlayerName = getInitiator(inGameBoardState); final GameInfo gameInfo = new GameInfo(trx);
final var expectedWinnerName = inGameBoardState.getOpponentName(activePlayerName); final var winnerName = inGameBoardState.getOpponentName(gameInfo.issuer);
requireThat(outGameResultState.getWinnerName().compareTo(expectedWinnerName) == 0, requireThat(outGameResultState.getWinnerName().compareTo(winnerName) == 0,
"Expected winner "+expectedWinnerName.getCommonName() +", proposed winner " +outGameResultState.getWinnerName().getCommonName()); "Expected winner "+winnerName.getCommonName() +", proposed winner " +outGameResultState.getWinnerName().getCommonName());
} }
public void validateGameBoardMove(UtxoLedgerTransaction trx, List<Integer> move) { public void validateGameBoardMove(UtxoLedgerTransaction trx, List<Integer> move) {

View File

@ -0,0 +1,79 @@
package djmil.cordacheckers.contracts;
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleCommand;
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleInputState;
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleOutputState;
import djmil.cordacheckers.contracts.GameCommand.ActionException;
import djmil.cordacheckers.states.GameBoardState;
import djmil.cordacheckers.states.GameProposalState;
import djmil.cordacheckers.states.GameResultState;
import djmil.cordacheckers.states.GameState;
import net.corda.v5.base.types.MemberX500Name;
import net.corda.v5.ledger.utxo.transaction.UtxoLedgerTransaction;
public class GameInfo {
public final GameCommand command;
public final MemberX500Name issuer; // a person who has created/updated state (important for CommitSubFlowResponder)
public final MemberX500Name actor; // a person who is expected to act on a state (inmportnat for ViewBuilder)
public final GameState state; // lates, most actual state
public GameInfo(UtxoLedgerTransaction utxoTrx) {
this.command = getSingleCommand(utxoTrx, GameCommand.class);
switch (this.command.getAction()) {
case GAME_PROPOSAL_CREATE:
this.state = getSingleOutputState(utxoTrx, GameProposalState.class);
this.issuer = ((GameProposalState)this.state).getIssuerName();
this.actor = ((GameProposalState)this.state).getAcquierName();
return;
case GAME_PROPOSAL_CANCEL:
this.state = getSingleInputState(utxoTrx, GameProposalState.class);
this.issuer = ((GameProposalState)this.state).getIssuerName();
this.actor = null;
return;
case GAME_PROPOSAL_REJECT:
this.state = getSingleInputState(utxoTrx, GameProposalState.class);
this.issuer = ((GameProposalState)this.state).getAcquierName();
this.actor = null;
return;
case GAME_PROPOSAL_ACCEPT:
this.state = getSingleOutputState(utxoTrx, GameBoardState.class);
this.issuer = getSingleInputState(utxoTrx, GameProposalState.class).getAcquierName();
this.actor = ((GameBoardState)this.state).getActivePlayerName();
return;
case GAME_BOARD_MOVE:
this.state = getSingleOutputState(utxoTrx, GameBoardState.class);
this.issuer = getSingleInputState(utxoTrx, GameBoardState.class).getActivePlayerName();
this.actor = ((GameBoardState)this.state).getActivePlayerName();
return;
case GAME_BOARD_VICTORY:
this.state = getSingleOutputState(utxoTrx, GameResultState.class);
this.issuer = ((GameResultState)this.state).getWinnerName();
this.actor = null;
return;
case GAME_BOARD_SURRENDER:
this.state = getSingleOutputState(utxoTrx, GameResultState.class);
this.issuer = ((GameResultState)this.state).getLooserName();
this.actor = null;
return;
}
throw new ActionException();
}
public boolean isMyAction(MemberX500Name myName) {
if (this.actor == null)
return false;
return this.actor.compareTo(myName) == 0;
}
}

View File

@ -24,7 +24,7 @@ public class GameResultContract implements net.corda.v5.ledger.utxo.Contract {
command.validateGameBoardSurrender(trx); command.validateGameBoardSurrender(trx);
break; break;
case GAME_RESULT_CREATE: case GAME_BOARD_VICTORY:
command.validateGameResultCreate(trx); command.validateGameResultCreate(trx);
break; break;

View File

@ -91,5 +91,4 @@ public class GameBoardState extends GameState {
return true; return true;
} }
} }

View File

@ -67,7 +67,7 @@ public class SurrenderFlow implements ClientStartableFlow{
utxoTrxId = this.flowEngine utxoTrxId = this.flowEngine
.subFlow(new CommitSubFlow(gameBoardSurrenderTrx, .subFlow(new CommitSubFlow(gameBoardSurrenderTrx,
command.getCounterparty(gameBoardSar), command.getCounterparty(out.gameResult),
out.custodyName)); out.custodyName));
final View gameStateView = this.flowEngine final View gameStateView = this.flowEngine

View File

@ -1,17 +1,9 @@
package djmil.cordacheckers.gamestate; package djmil.cordacheckers.gamestate;
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleCommand;
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleOutputState;
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleInputState;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import djmil.cordacheckers.contracts.GameCommand; import djmil.cordacheckers.contracts.GameInfo;
import djmil.cordacheckers.states.GameBoardState;
import djmil.cordacheckers.states.GameProposalState;
import djmil.cordacheckers.states.GameResultState;
import djmil.cordacheckers.states.GameState;
import net.corda.v5.application.flows.CordaInject; import net.corda.v5.application.flows.CordaInject;
import net.corda.v5.application.flows.InitiatedBy; import net.corda.v5.application.flows.InitiatedBy;
import net.corda.v5.application.flows.ResponderFlow; import net.corda.v5.application.flows.ResponderFlow;
@ -40,10 +32,7 @@ public class CommitSubFlowResponder implements ResponderFlow {
public void call(FlowSession session) { public void call(FlowSession session) {
UtxoTransactionValidator txValidator = trxToValidate -> { UtxoTransactionValidator txValidator = trxToValidate -> {
try { try {
final GameCommand gameCommand = getSingleCommand(trxToValidate, GameCommand.class); checkParticipants(session, trxToValidate);
final GameState gameState = getActualGameStateFromTransaction(trxToValidate, gameCommand);
checkParticipants(session, gameCommand, gameState);
/* /*
* Other checks / actions ? * Other checks / actions ?
@ -66,52 +55,20 @@ public class CommitSubFlowResponder implements ResponderFlow {
} }
} }
/**
*
* @param gameStateTransaction an utxo ledger transaction, that involves GameState
* @param command
* @return the most recent (from perspective of session participants validation) GameState for a given transaction
*
* @see djmil.cordacheckers.gamestate.ViewBuilder#getLatestGameStateFromTransaction(UtxoLedgerTransaction, GameCommand)
*/
@Suspendable @Suspendable
GameState getActualGameStateFromTransaction(UtxoLedgerTransaction gameStateTransaction, GameCommand command) { void checkParticipants(FlowSession session, UtxoLedgerTransaction gameStateUtxo) throws ParticipantException {
switch (command.getAction()) { final GameInfo info = new GameInfo(gameStateUtxo);
case GAME_PROPOSAL_CREATE:
return getSingleOutputState(gameStateTransaction, GameProposalState.class);
case GAME_PROPOSAL_ACCEPT:
case GAME_PROPOSAL_REJECT:
case GAME_PROPOSAL_CANCEL:
return getSingleInputState(gameStateTransaction, GameProposalState.class);
case GAME_BOARD_SURRENDER:
return getSingleInputState(gameStateTransaction, GameBoardState.class);
case GAME_BOARD_MOVE:
return getSingleInputState(gameStateTransaction, GameBoardState.class);
case GAME_RESULT_CREATE:
return getSingleOutputState(gameStateTransaction, GameResultState.class);
}
throw new GameCommand.ActionException();
}
@Suspendable
void checkParticipants(FlowSession session, GameCommand gameCommand, GameState gameState) throws ParticipantException {
final var conterpartyName = session.getCounterparty(); final var conterpartyName = session.getCounterparty();
final var actorName = gameCommand.getInitiator(gameState); if (info.issuer.compareTo(conterpartyName) != 0)
if (actorName.compareTo(conterpartyName) != 0) throw new ParticipantException("Issuer", conterpartyName, info.issuer);
throw new ParticipantException("Actor", conterpartyName, actorName);
final var myName = memberLookup.myInfo().getName(); final var myName = memberLookup.myInfo().getName();
if (myName.getOrganizationUnit().equals("Custodian")) if (myName.getOrganizationUnit().equals("Custodian"))
return; // Custodian shall not validate state's counterparty return; // Custodian shall not validate state's counterparty
final var opponentName = gameState.getOpponentName(myName); // throws NotInvolved final var opponentName = info.state.getOpponentName(myName); // throws NotInvolved
if (conterpartyName.compareTo(opponentName) != 0) if (conterpartyName.compareTo(opponentName) != 0)
throw new ParticipantException("Counterparty", conterpartyName, opponentName); throw new ParticipantException("Opponent", conterpartyName, opponentName);
} }
public static class ParticipantException extends Exception { public static class ParticipantException extends Exception {

View File

@ -48,7 +48,7 @@ public class View {
this.uuid = null; this.uuid = null;
} }
public View(View.Status status, GameProposalState gameProposal, MemberX500Name myName) { public View(View.Status status, MemberX500Name myName, GameProposalState gameProposal) {
this.status = status; this.status = status;
this.opponentName = gameProposal.getOpponentName(myName).getCommonName(); this.opponentName = gameProposal.getOpponentName(myName).getCommonName();
this.opponentColor = gameProposal.getOpponentColor(myName); this.opponentColor = gameProposal.getOpponentColor(myName);
@ -59,18 +59,7 @@ public class View {
this.uuid = gameProposal.getGameUuid(); this.uuid = gameProposal.getGameUuid();
} }
public View(View.Status status, GameBoardState gameBoard, MemberX500Name myName) { public View(View.Status status, MemberX500Name myName, GameBoardState gameBoard, List<Integer> previousMove) {
this.status = status;
this.opponentName = gameBoard.getOpponentName(myName).getCommonName();
this.opponentColor = gameBoard.getOpponentColor(myName);
this.board = gameBoard.getBoard();
this.moveNumber = gameBoard.getMoveNumber();
this.previousMove = null;
this.message = gameBoard.getMessage();
this.uuid = gameBoard.getGameUuid();
}
public View(View.Status status, GameBoardState gameBoard, List<Integer> previousMove, MemberX500Name myName) {
this.status = status; this.status = status;
this.opponentName = gameBoard.getOpponentName(myName).getCommonName(); this.opponentName = gameBoard.getOpponentName(myName).getCommonName();
this.opponentColor = gameBoard.getOpponentColor(myName); this.opponentColor = gameBoard.getOpponentColor(myName);
@ -81,7 +70,7 @@ public class View {
this.uuid = gameBoard.getGameUuid(); this.uuid = gameBoard.getGameUuid();
} }
public View(View.Status status, GameResultState gameResult, MemberX500Name myName) { public View(View.Status status, MemberX500Name myName, GameResultState gameResult) {
this.status = status; this.status = status;
this.opponentName = gameResult.getOpponentName(myName).getCommonName(); this.opponentName = gameResult.getOpponentName(myName).getCommonName();
this.opponentColor = gameResult.getOpponentColor(myName); this.opponentColor = gameResult.getOpponentColor(myName);

View File

@ -1,14 +1,11 @@
package djmil.cordacheckers.gamestate; package djmil.cordacheckers.gamestate;
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleCommand;
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleOutputState;
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleInputState;
import djmil.cordacheckers.contracts.GameCommand; import djmil.cordacheckers.contracts.GameCommand;
import djmil.cordacheckers.contracts.GameInfo;
import djmil.cordacheckers.states.GameBoardState; import djmil.cordacheckers.states.GameBoardState;
import djmil.cordacheckers.states.GameProposalState; import djmil.cordacheckers.states.GameProposalState;
import djmil.cordacheckers.states.GameResultState; import djmil.cordacheckers.states.GameResultState;
import djmil.cordacheckers.states.GameState;
import net.corda.v5.application.flows.CordaInject; import net.corda.v5.application.flows.CordaInject;
import net.corda.v5.application.flows.SubFlow; import net.corda.v5.application.flows.SubFlow;
import net.corda.v5.application.membership.MemberLookup; import net.corda.v5.application.membership.MemberLookup;
@ -45,76 +42,32 @@ public class ViewBuilder implements SubFlow<View> {
@Suspendable @Suspendable
View buildGameStateView(UtxoLedgerTransaction gameStateUtxo) { View buildGameStateView(UtxoLedgerTransaction gameStateUtxo) {
MemberX500Name myName = memberLookup.myInfo().getName(); final GameInfo game = new GameInfo(gameStateUtxo);
final MemberX500Name myName = memberLookup.myInfo().getName();
final View.Status viewStatus = action2status(game, myName);
final GameCommand command = getSingleCommand(gameStateUtxo, GameCommand.class); if (game.state instanceof GameProposalState)
final GameState state = getLatestGameStateFromTransaction(gameStateUtxo, command); return new View(viewStatus, myName, (GameProposalState) game.state);
final View.Status viewStatus = action2status(command, state, myName);
switch (command.getAction()) { if (game.state instanceof GameBoardState)
case GAME_PROPOSAL_CREATE: return new View(viewStatus, myName, (GameBoardState) game.state, game.command.getMove());
case GAME_PROPOSAL_CANCEL:
case GAME_PROPOSAL_REJECT:
if (state instanceof GameProposalState)
return new View(viewStatus, (GameProposalState)state, myName);
break;
case GAME_PROPOSAL_ACCEPT: if (game.state instanceof GameResultState)
case GAME_BOARD_MOVE: return new View(viewStatus, myName, (GameResultState) game.state);
if (state instanceof GameBoardState)
return new View(viewStatus, (GameBoardState)state, command.getMove(), myName);
break;
case GAME_BOARD_SURRENDER:
case GAME_RESULT_CREATE:
if (state instanceof GameResultState)
return new View(viewStatus, (GameResultState)state, myName);
break;
}
throw new GameCommand.ActionException(); throw new RuntimeException("Unexpected GameState");
}
/**
*
* @param gameStateTransaction an utxo ledger transaction, that involves GameState
* @param command
* @return the most recent (from perspective of building a GameView) GameState for a given transaction
*
* @see djmil.cordacheckers.gamestate.CommitSubFlowResponder#getActualGameStateFromTransaction(UtxoLedgerTransaction, GameCommand)
*/
@Suspendable
GameState getLatestGameStateFromTransaction(UtxoLedgerTransaction gameStateTransaction, GameCommand command) {
switch (command.getAction()) {
case GAME_PROPOSAL_CREATE:
return getSingleOutputState(gameStateTransaction, GameProposalState.class);
case GAME_PROPOSAL_REJECT:
case GAME_PROPOSAL_CANCEL:
return getSingleInputState(gameStateTransaction, GameProposalState.class);
case GAME_PROPOSAL_ACCEPT:
case GAME_BOARD_MOVE:
return getSingleOutputState(gameStateTransaction, GameBoardState.class);
case GAME_BOARD_SURRENDER:
case GAME_RESULT_CREATE:
return getSingleOutputState(gameStateTransaction, GameResultState.class);
}
throw new GameCommand.ActionException();
} }
@Suspendable @Suspendable
View.Status action2status(GameCommand command, GameState state, MemberX500Name myName) { View.Status action2status(GameInfo game, MemberX500Name myName) {
final boolean myAction = command.getInitiator(state).compareTo(myName) == 0;
switch (command.getAction()) { switch (game.command.getAction()) {
case GAME_PROPOSAL_CREATE: case GAME_PROPOSAL_CREATE:
if (myAction) if (game.isMyAction(myName))
return View.Status.GAME_PROPOSAL_WAIT_FOR_OPPONENT;
else
return View.Status.GAME_PROPOSAL_WAIT_FOR_YOU; return View.Status.GAME_PROPOSAL_WAIT_FOR_YOU;
else
return View.Status.GAME_PROPOSAL_WAIT_FOR_OPPONENT;
case GAME_PROPOSAL_REJECT: case GAME_PROPOSAL_REJECT:
return View.Status.GAME_PROPOSAL_REJECTED; return View.Status.GAME_PROPOSAL_REJECTED;
@ -124,19 +77,19 @@ public class ViewBuilder implements SubFlow<View> {
case GAME_PROPOSAL_ACCEPT: case GAME_PROPOSAL_ACCEPT:
case GAME_BOARD_MOVE: case GAME_BOARD_MOVE:
if (myAction) if (game.isMyAction(myName))
return View.Status.GAME_BOARD_WAIT_FOR_YOU; return View.Status.GAME_BOARD_WAIT_FOR_YOU;
else else
return View.Status.GAME_BOARD_WAIT_FOR_OPPONENT; return View.Status.GAME_BOARD_WAIT_FOR_OPPONENT;
case GAME_BOARD_SURRENDER: case GAME_BOARD_SURRENDER:
if (myAction) if (game.issuer.compareTo(myName) == 0)
return View.Status.GAME_RESULT_YOU_LOOSE; return View.Status.GAME_RESULT_YOU_LOOSE;
else else
return View.Status.GAME_RESULT_YOU_WON; return View.Status.GAME_RESULT_YOU_WON;
case GAME_RESULT_CREATE: case GAME_BOARD_VICTORY:
if (myAction) if (game.issuer.compareTo(myName) == 0)
return View.Status.GAME_RESULT_YOU_WON; return View.Status.GAME_RESULT_YOU_WON;
else else
return View.Status.GAME_RESULT_YOU_LOOSE; return View.Status.GAME_RESULT_YOU_LOOSE;