Ranking: use Map instead of List

This commit is contained in:
djmil 2023-10-02 19:27:12 +02:00
parent f9f6920512
commit 7fe2898eef
9 changed files with 129 additions and 48 deletions

View File

@ -67,7 +67,7 @@ public class CordaClient {
}
// use custodian holding identity to get ranking table of all players
public List<Rank> fetchRanking(HoldingIdentity holdingIdentity) {
public Map<String, Rank> fetchRanking(HoldingIdentity holdingIdentity) {
final RequestBody requestBody = new RequestBody(
"ranking-" +UUID.randomUUID(),
"djmil.cordacheckers.gameresult.RankingFlow",

View File

@ -1,7 +1,6 @@
package djmil.cordacheckers.cordaclient.dao;
public record Rank(
String name,
Integer gamesPlayed,
Integer gamesWon
) {

View File

@ -1,11 +1,11 @@
package djmil.cordacheckers.cordaclient.dao.flow.arguments;
import java.util.List;
import java.util.Map;
import djmil.cordacheckers.cordaclient.dao.Rank;
public record RspRankList(
List<Rank> successStatus,
String failureStatus) implements Rsp<List<Rank>> {
Map<String, Rank> successStatus,
String failureStatus) implements Rsp<Map<String, Rank>> {
}

View File

@ -144,7 +144,7 @@ public class GameProposalTests {
assertThat(acceptedGameAcquierView.opponentName()).isEqualToIgnoringCase(issuer);
assertThat(acceptedGameAcquierView.opponentColor()).isEqualByComparingTo(acquierColor.opposite());
assertThat(acceptedGameAcquierView.board()).containsAllEntriesOf(GameState.defaultGameBoard);
assertThat(acceptedGameAcquierView.previousMove()).isEmpty();
assertThat(acceptedGameAcquierView.previousMove()).isNull();
assertThat(acceptedGameAcquierView.moveNumber() == 0);
assertThat(acceptedGameAcquierView.status()).isEqualByComparingTo(Status.GAME_BOARD_WAIT_FOR_YOU);
assertThat(acceptedGameAcquierView.uuid()).isEqualByComparingTo(game.uuid());
@ -160,7 +160,7 @@ public class GameProposalTests {
assertThat(acceptedGameIssuerView.opponentName()).isEqualToIgnoringCase(acquier);
assertThat(acceptedGameIssuerView.opponentColor()).isEqualByComparingTo(acquierColor);
assertThat(acceptedGameIssuerView.board()).containsAllEntriesOf(GameState.defaultGameBoard);
assertThat(acceptedGameIssuerView.previousMove()).isEmpty();
assertThat(acceptedGameIssuerView.previousMove()).isNull();
assertThat(acceptedGameIssuerView.moveNumber() == 0);
assertThat(acceptedGameIssuerView.status()).isEqualByComparingTo(Status.GAME_BOARD_WAIT_FOR_OPPONENT);
assertThat(acceptedGameIssuerView.uuid()).isEqualByComparingTo(game.uuid());

View File

@ -1,8 +1,12 @@
package djmil.cordacheckers.cordaclient;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatNoException;
import java.util.List;
import java.util.Arrays;
import java.util.Map;
import javax.naming.InvalidNameException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@ -24,33 +28,77 @@ public class RankingTests {
final String player1 = "kumar";
final String player2 = "bobik";
final static Stone WHITE_MAN = new Stone(Stone.Color.WHITE, Stone.Type.MAN);
final static Stone WHITE_KING = new Stone(Stone.Color.WHITE, Stone.Type.KING);
final static Stone BLACK_MAN = new Stone(Stone.Color.BLACK, Stone.Type.MAN);
final static Stone BLACK_KING = new Stone(Stone.Color.BLACK, Stone.Type.KING);
final static Map<Integer, Stone> board1 = Map.ofEntries(
Map.entry(10, BLACK_KING),
Map.entry(7, WHITE_KING)
);
@Test
void testGlobalRanking() {
void testSurrender() throws InvalidNameException {
final var hiCustodian = holdingIdentityResolver.getCustodian();
assertThat(hiCustodian).isNotNull();
final List<Rank> liderboard1 = cordaClient.fetchRanking(hiCustodian);
final Map<String, Rank> liderboard1 = cordaClient.fetchRanking(hiCustodian);
final var hiWinner = holdingIdentityResolver.getByUsername(player1);
final var hiLooser = holdingIdentityResolver.getByUsername(player2);
final var winnerName = hiWinner.getName();
final var losserName = hiLooser.getName();
final GameState game = cordaClient.gameProposalCreate(
hiWinner, hiLooser, Stone.Color.WHITE, "GameBoard GLOBAL_RANKING test");
final GameState game = cordaClient.gameProposalCreate(hiWinner, hiLooser, Stone.Color.WHITE,
"GameBoard GLOBAL_RANKING surrender test");
cordaClient.gameProposalAccept(hiLooser, game.uuid());
cordaClient.gameBoardSurrender(hiLooser, game.uuid());
final List<Rank> liderboard2 = cordaClient.fetchRanking(hiCustodian);
final Map<String, Rank> liderboard2 = cordaClient.fetchRanking(hiCustodian);
System.out.println(liderboard1);
System.out.println(liderboard2);
assertThat(liderboard1.get(winnerName).gamesWon() +1 == liderboard2.get(winnerName).gamesWon() );
assertThat(liderboard1.get(winnerName).gamesPlayed() +1 == liderboard2.get(winnerName).gamesPlayed());
assertThat(liderboard1.get(losserName).gamesWon() == liderboard2.get(losserName).gamesWon() );
assertThat(liderboard1.get(losserName).gamesPlayed() +1 == liderboard2.get(losserName).gamesPlayed());
}
@Test
void testVictory() throws InvalidNameException {
final var hiCustodian = holdingIdentityResolver.getCustodian();
assertThat(hiCustodian).isNotNull();
final Map<String, Rank> liderboard1 = cordaClient.fetchRanking(hiCustodian);
final var hiWinner = holdingIdentityResolver.getByUsername(player2);
final var hiLooser = holdingIdentityResolver.getByUsername(player1);
final var winnerName = hiWinner.getName();
final var losserName = hiLooser.getName();
final GameState game = cordaClient.gameProposalCreate(hiWinner, hiLooser, Stone.Color.BLACK,
board1, "GameBoard GLOBAL_RANKING victory test");
cordaClient.gameProposalAccept(hiLooser, game.uuid());
cordaClient.gameBoardMove(hiWinner, game.uuid(), Arrays.asList(7, 14), null);
final Map<String, Rank> liderboard2 = cordaClient.fetchRanking(hiCustodian);
assertThat(liderboard1.get(winnerName).gamesWon() +1 == liderboard2.get(winnerName).gamesWon() );
assertThat(liderboard1.get(winnerName).gamesPlayed() +1 == liderboard2.get(winnerName).gamesPlayed());
assertThat(liderboard1.get(losserName).gamesWon() == liderboard2.get(losserName).gamesWon() );
assertThat(liderboard1.get(losserName).gamesPlayed() +1 == liderboard2.get(losserName).gamesPlayed());
}
@Test
void testIndividualRanking() {
final var hiCustodian = holdingIdentityResolver.getByUsername(player2);
final List<Rank> liderboard = cordaClient.fetchRanking(hiCustodian);
System.out.println(liderboard);
assertThatNoException().isThrownBy( () ->
cordaClient.fetchRanking(hiCustodian)
);
}
}

View File

@ -8,20 +8,30 @@ import net.corda.v5.membership.NotaryInfo;
public class VNode {
static final String CHECKERS = "Checkers"; // O aka Organization
static final String PLAYER = "Player"; // OU aka OrganizationUnit
static final String CUSTODIAN = "Custodian"; // OU aka OrganizationUnit
static final String NOTARY = "Notary"; // OU aka OrganizationUnit
@CordaInject
MemberLookup memberLookup;
public static boolean isCordaCherckersPlayer(MemberInfo memberInfo) {
final MemberX500Name memberName = memberInfo.getName();
return memberName.getOrganization().equals(CHECKERS) &&
memberName.getOrganizationUnit().equals(PLAYER);
}
public static boolean isCordaCherckersCustodian(MemberInfo memberInfo) {
final MemberX500Name memberName = memberInfo.getName();
return memberName.getOrganization().equals(CHECKERS) &&
memberName.getOrganizationUnit().equals(CUSTODIAN);
}
public static boolean isCordaCherckersNotary(NotaryInfo notaryInfo) {
final MemberX500Name memberName = notaryInfo.getName();
return memberName.getOrganization().equals(CHECKERS) &&
memberName.getOrganizationUnit().equals(NOTARY);
}

View File

@ -1,20 +1,36 @@
package djmil.cordacheckers.gameresult;
public class Rank {
public final String name;
public final Integer gamesPlayed;
public final Integer gamesWon;
private Integer gamesPlayed;
private Integer gamesWon;
// Serialisation service requires a default constructor
Rank() {
name = null;
gamesPlayed = null;
gamesWon = null;
public Rank() {
gamesPlayed = 0;
gamesWon = 0;
}
public Rank(String name, Integer gamesPlayed, Integer gamesWon) {
this.name = name;
public Rank(Integer gamesPlayed, Integer gamesWon) {
this.gamesPlayed = gamesPlayed;
this.gamesWon = gamesWon;
}
Rank gamePlayed() {
gamesPlayed++;
return this;
}
Rank gameWon() {
gamesWon++;
return this;
}
public Integer getGamesPlayed() {
return gamesPlayed;
}
public Integer getGamesWon() {
return gamesWon;
}
}

View File

@ -1,7 +1,6 @@
package djmil.cordacheckers.gameresult;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@ -9,12 +8,13 @@ import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import djmil.cordacheckers.VNode;
import djmil.cordacheckers.states.GameResultState;
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.application.membership.MemberLookup;
import net.corda.v5.base.annotations.Suspendable;
import net.corda.v5.ledger.utxo.UtxoLedgerService;
@ -29,7 +29,7 @@ public class RankingFlow implements ClientStartableFlow {
public JsonMarshallingService jsonMarshallingService;
@CordaInject
public FlowEngine flowEngine;
public MemberLookup memberLookup;
@Suspendable
@Override
@ -37,27 +37,23 @@ public class RankingFlow implements ClientStartableFlow {
try {
final List<GameResultState> gameStateResutList = getGameResultsList();
Map<String, Integer> won = new HashMap<>();
Map<String, Rank> leaderboard = newLeaderboard();
for (GameResultState gs : gameStateResutList) {
final var winner = gs.getWinnerName().getCommonName();
won.put(winner, won.getOrDefault(winner, 0) +1);
}
if (winner != null)
leaderboard.put(winner, leaderboard.get(winner).gameWon() );
final var blackPlayer = gs.getBlackPlayer().getCommonName();
leaderboard.put(blackPlayer, leaderboard.get(blackPlayer).gamePlayed() );
Map<String, Integer> played = new HashMap<>(won);
for (GameResultState gs : gameStateResutList) {
final var looseer = gs.getLooserName().getCommonName();
played.put(looseer, played.getOrDefault(looseer, 0) +1);
}
List<Rank> board = new LinkedList<Rank>();
for (String name : played.keySet()) {
board.add(new Rank(name, played.getOrDefault(name, 0), won.getOrDefault(name, 0)));
final var whitePlayer = gs.getWhitePlayer().getCommonName();
leaderboard.put(whitePlayer, leaderboard.get(whitePlayer).gamePlayed() );
}
return new RankingFlowResponce(board)
return new RankingFlowResponce(leaderboard)
.toJsonEncodedString(jsonMarshallingService);
} catch (Exception e) {
log.warn("Exception during processing " + requestBody + " request: " + e.getMessage());
log.warn(requestBody + " [ERROR] " +e.toString());
return new RankingFlowResponce(e)
.toJsonEncodedString(jsonMarshallingService);
}
@ -72,4 +68,16 @@ public class RankingFlow implements ClientStartableFlow {
.collect(Collectors.toList());
}
@Suspendable
Map<String, Rank> newLeaderboard() {
Map<String, Rank> leaderboard = new HashMap<>();
memberLookup.lookup()
.stream()
.filter(member -> VNode.isCordaCherckersPlayer(member) )
.forEach(member -> leaderboard.put(member.getName().getCommonName(), new Rank()) );
return leaderboard;
}
}

View File

@ -1,14 +1,14 @@
package djmil.cordacheckers.gameresult;
import java.util.List;
import java.util.Map;
import net.corda.v5.application.marshalling.JsonMarshallingService;
public class RankingFlowResponce {
public final List<Rank> successStatus;
public final Map<String, Rank> successStatus;
public final String failureStatus;
public RankingFlowResponce(List<Rank> success) {
public RankingFlowResponce(Map<String, Rank> success) {
this.successStatus = success;
this.failureStatus = null;
}
@ -21,5 +21,5 @@ public class RankingFlowResponce {
public String toJsonEncodedString(JsonMarshallingService jsonMarshallingService) {
return jsonMarshallingService.format(this);
}
}
}