Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extending the code examples and providing a new Bot #2

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apply plugin: 'java'
apply plugin: 'application'

mainClassName = "com.zuehlke.jasschallenge.Application"
mainClassName = "com.zuehlke.jasschallenge.RandomBot"

compileJava {
sourceCompatibility = '1.8'
Expand Down
Binary file removed doc/images/chooseUsername.PNG
Binary file not shown.
Binary file removed doc/images/createTournament.PNG
Binary file not shown.
Binary file added doc/images/result.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/tournament.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed doc/images/tournamentPage.PNG
Binary file not shown.
Binary file added doc/images/tournamentReady.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/tournament_page.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/username.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
124 changes: 53 additions & 71 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,81 +1,63 @@
# jass-challenge-client-java ![Build Status](https://travis-ci.org/webplatformz/challenge-client-java.svg?branch=master)
# Jass Challenge 2020

This is a Java client (bot) for the [Jass challenge server](https://github.com/webplatformz/challenge).
This is a Java client (bot) for the [Jass challenge server](https://github.com/RFS-0/challenge).
This client allows you to easily develop a bot for the Jass challenge.

### Wiki (Server):
https://github.com/webplatformz/challenge/wiki

### JassChallenge2017
If you are an enrolled student in switzerland, you are welcome to participate the **JassChallenge2017** competition in April '17

https://jass-challenge.zuehlke.io/

Note: This readme refers to the forked versions of the jass challenge server and the java client.
The original server and client can be found here:
* [original jass challenge server](https://github.com/webplatformz/challenge)
* [original java client](https://github.com/webplatformz/challenge-client-java)

The forked version of the server offers a description how to deploy it as a kubernetes deployment (on GCP).
The forked version of the client offers some utility classes that should help you speed up the development of a bot.

## Getting started

Clone this repository and start (`gradlew run`) the [Application](src/main/java/com/zuehlke/jasschallenge/Application.java) class:

``` java
public class Application {
//CHALLENGE2017: Set your bot name
private static final String BOT_NAME = "awesomeJavaBot";
//CHALLENGE2017: Set your own strategy
private static final RandomJassStrategy STRATEGY = new RandomJassStrategy();

private static final String LOCAL_URL = "ws://localhost:3000";

public static void main(String[] args) throws Exception {
String websocketUrl = parseWebsocketUrlOrDefault(args);

Player myLocalPlayer = new Player(BOT_NAME, STRATEGY);
startGame(websocketUrl, myLocalPlayer, SessionType.TOURNAMENT);
}
}
```

The client needs the challenge server to connect to. Clone the challenge server and run npm start. For more information
go to [Jass challenge server](https://github.com/webplatformz/challenge) repository.

## Implement your own bot

To implement your own bot you need to provide an implementation of the
[JassStrategy](src/main/java/com/zuehlke/jasschallenge/client/game/strategy/JassStrategy.java) interface:

``` java
public interface JassStrategy {
Mode chooseTrumpf(Set<Card> availableCards, GameSession session);
Card chooseCard(Set<Card> availableCards, GameSession session);

default void onSessionStarted(GameSession session) {}
default void onGameStarted(GameSession session) {}
default void onMoveMade(Move move, GameSession session) {}
default void onGameFinished() {}
default void onSessionFinished() {}
}
```

## Start your own tournament
To test your bot against other bots, such das the random bot, you need to start your own tournament.

1. start the challenge server:
`npm start`
2. Browse to http://localhosthost:3000
3. Enter some user name:

![Alt text](doc/images/chooseUsername.PNG?raw=true "Choose a user name")
4. Enter some tournament name and press **Enter**

![Alt text](doc/images/createTournament.PNG?raw=true "Choose a user name")

5. Join your bots, they should appear on the next page

![Alt text](doc/images/tournamentPage.PNG?raw=true "Choose a user name")

6. Join random strategy bots for testing. In your challenge server directory enter the command:
`npm run bot:start`
This will add 4 random bot teams to your tournament.
1. Clone the forked server: `git clone https://github.com/RFS-0/challenge.git`
2. Clone this repository (i.e. the java client): `https://github.com/RFS-0/challenge-client-java.git`

## Running the server

To run the server execute the following commands:
1. `npm run clean`
2. `npm run build`
3. `npm run start:tournament`

This will start the jass challenge server on `localhost:3000`.

## How to create a new jass bot

1. Create an implementation of the [JassStrategy](src/main/java/com/zuehlke/jasschallenge/client/game/strategy/JassStrategy.java) interface. This implementation will be your bot. See [RandomJassStrategy](src/main/java/com/zuehlke/jasschallenge/client/game/strategy/RandomJassStrategy.java) or [StrongestOrWeakestStrategy](src/main/java/com/zuehlke/jasschallenge/client/game/strategy/StrongestOrWeakestStrategy.java) for reference.
* You might want to check out the [utils](src/main/java/com/zuehlke/jasschallenge/client/game/strategy/utils) package, it provides some helpful classes to implement a new bot.
2. Create a new application to run your bot. See [RandomBot](src/main/java/com/zuehlke/jasschallenge/RandomBot.java) or [StrongestOrWeakestBot](src/main/java/com/zuehlke/jasschallenge/StrongestOrWeakestBot.java) for reference. Just replace the values of the following attributes with your own values:
* `BOT_NAME` -> define the name of your bot; must be unique among all bots
* `STRATEGY` -> instantiate your implementation of the [JassStrategy](src/main/java/com/zuehlke/jasschallenge/client/game/strategy/JassStrategy.java) interface
* `SERVER_URL` -> once the tournament begins this has to be updated with the ip address and port of the remote jass challenge server. Set it to `ws://127.0.0.1:3000` during development.

## How to run the client

1. Run `./gradlew clean`
2. Run `./gradlew build`
3. Execute the `main` method of your bot. Or if you want to run the application with the `./gradlew run` command be sure to update the `mainClassName` in [build.gradle](build.gradle).
4. Execute step 3 again. Because to form a team, two instances of your bot must be connected to the jass challenge server. Teams are formed via the bot name. This is why each team should use a unique name for their bot and you have to run your client twice to form a team.

### Example development scenario

1. You implemented a first version of your bot and now you would like to test it. For this you first start the [jass challenge server](https://github.com/RFS-0/challenge).
2. Switch to your clone of the server repository and execute `npm run start:tournament`
3. Go to `localhost:3000` and enter some user name, e.g. `user`:
![Alt text](doc/images/username.PNG?raw=true "Choose a user name")
4. Enter some tournament name, e.g. `tournament` and click enter:
![Alt text](doc/images/tournament.PNG?raw=true "Choose a user name")
5. You should now see this screen:
![Alt text](doc/images/tournament_page.PNG?raw=true "Tournament page")
6. To test against bots that use the random strategy you have two options. Either run the main method of the [RandomBot](src/main/java/com/zuehlke/jasschallenge/RandomBot.java) twice or run `npm run bot:start` in the server repo to start 4 teams of random bots. The [StrongestOrWeakestBot](src/main/java/com/zuehlke/jasschallenge/StrongestOrWeakestBot.java) is only available in this version of the java client, so to evaluate your bot against it you have to run is main method twice.
7. Do not forget to execute the main method of your bot twice as well!
8. Once all the clients have connected to the server the tournament page it should look like this:
![Alt text](doc/images/tournamentReady.PNG?raw=true "Tournament ready")
9. Click start to run the tournament.
10. Click show rankings to see how well your bot performed:
![Alt text](doc/images/result.PNG?raw=true "Tournament result")

## Contributors ##
Thanks to [fluescher](https://github.com/fluescher) for creating this skeleton.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.zuehlke.jasschallenge.client.game.Player;
import com.zuehlke.jasschallenge.client.game.strategy.RandomJassStrategy;
import com.zuehlke.jasschallenge.messages.type.SessionType;

import java.util.Arrays;

/**
Expand All @@ -14,21 +15,18 @@
* gradlew run [websocketUrl]
* </pre>
*/
public class Application {
//CHALLENGE2017: Set your bot name
private static final String BOT_NAME = "awesomeJavaBot";
//CHALLENGE2017: Set your own strategy
public class RandomBot {
private static final String BOT_NAME = "random_bot";
private static final RandomJassStrategy STRATEGY = new RandomJassStrategy();

private static final String LOCAL_URL = "ws://127.0.0.1:3000";
private static final String SERVER_URL = "ws://127.0.0.1:3000";

public static void main(String[] args) throws Exception {
String websocketUrl = parseWebsocketUrlOrDefault(args);

Player myLocalPlayer = new Player(BOT_NAME, STRATEGY);
Player randomPlayer = new Player(BOT_NAME, STRATEGY);

System.out.println("Connecting... Server socket URL: " + websocketUrl);
startGame(websocketUrl, myLocalPlayer, SessionType.TOURNAMENT);
startGame(websocketUrl, randomPlayer, SessionType.SINGLE_GAME);
}


Expand All @@ -37,11 +35,11 @@ private static String parseWebsocketUrlOrDefault(String[] args) {
System.out.println("Arguments: " + Arrays.toString(args));
return args[0];
}
return LOCAL_URL;
return SERVER_URL;
}

private static void startGame(String targetUrl, Player myLocalPlayer, SessionType sessionType) throws Exception {
RemoteGame remoteGame = new RemoteGame(targetUrl, myLocalPlayer, sessionType);
RemoteGame remoteGame = new RemoteGame(targetUrl, myLocalPlayer, sessionType, "tournament");
remoteGame.start();
}
}
45 changes: 45 additions & 0 deletions src/main/java/com/zuehlke/jasschallenge/StrongestOrWeakestBot.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.zuehlke.jasschallenge;

import com.zuehlke.jasschallenge.client.RemoteGame;
import com.zuehlke.jasschallenge.client.game.Player;
import com.zuehlke.jasschallenge.client.game.strategy.StrongestOrWeakestStrategy;
import com.zuehlke.jasschallenge.messages.type.SessionType;

import java.util.Arrays;

/**
* Starts one bot in tournament mode. Add your own strategy to compete in the Jass Challenge Tournament 2017!
* <br><br>
* To start from CLI use
* <pre>
* gradlew run [websocketUrl]
* </pre>
*/
public class StrongestOrWeakestBot {
private static final String BOT_NAME = "strongest_or_weakest_bot";
private static final StrongestOrWeakestStrategy STRATEGY = new StrongestOrWeakestStrategy();
private static final String SERVER_URL = "ws://127.0.0.1:3000";

public static void main(String[] args) throws Exception {
String websocketUrl = parseWebsocketUrlOrDefault(args);

Player strongestOrWeakestPlayer = new Player(BOT_NAME, STRATEGY);

System.out.println("Connecting... Server socket URL: " + websocketUrl);
startGame(websocketUrl, strongestOrWeakestPlayer, SessionType.TOURNAMENT);
}


private static String parseWebsocketUrlOrDefault(String[] args) {
if (args.length > 0) {
System.out.println("Arguments: " + Arrays.toString(args));
return args[0];
}
return SERVER_URL;
}

private static void startGame(String targetUrl, Player myLocalPlayer, SessionType sessionType) throws Exception {
RemoteGame remoteGame = new RemoteGame(targetUrl, myLocalPlayer, sessionType, "tournament");
remoteGame.start();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,20 @@ public class RemoteGame implements Game {
private final Player player;
private final String targetUrl;
private final SessionType sessionType;
private final String sessionName;

public RemoteGame(String targetUrl, Player player, SessionType sessionType) {
public RemoteGame(String targetUrl, Player player, SessionType sessionType, String sessionName) {
this.targetUrl = targetUrl;
this.player = player;
this.sessionType = sessionType;
this.sessionName = sessionName;
}

@Override
public void start() throws Exception {
final WebSocketClient client = new WebSocketClient();
try {
RemoteGameSocket socket = new RemoteGameSocket(new GameHandler(player, sessionType));
RemoteGameSocket socket = new RemoteGameSocket(new GameHandler(player, sessionType, sessionName));
client.start();

URI uri = new URI(targetUrl);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.zuehlke.jasschallenge.client.game;

import com.zuehlke.jasschallenge.game.cards.Card;

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

public final class GameSessions {

public static List<Card> getCardsPlayedInCurrentRound(GameSession session) {
return session.getCurrentRound().getMoves().stream()
.map(Move::getPlayedCard)
.collect(Collectors.toList());
}
}
21 changes: 21 additions & 0 deletions src/main/java/com/zuehlke/jasschallenge/client/game/Rounds.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.zuehlke.jasschallenge.client.game;

import com.zuehlke.jasschallenge.game.cards.Card;
import com.zuehlke.jasschallenge.game.cards.Color;

import java.util.List;

public final class Rounds {
public static boolean isFirstCardOfRound(List<Card> playedCards) {
return playedCards.size() < 1;
}

public static Color getColorOfRound(List<Card> playedCards) {
Card firstCardOfRound = playedCards.get(0);
return firstCardOfRound.getColor();
}

public static boolean isNewRound(GameSession session, int currentRoundNumber) {
return session.getCurrentRound().getRoundNumber() != currentRoundNumber;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.zuehlke.jasschallenge.client.game.strategy;

import com.zuehlke.jasschallenge.client.game.GameSession;
import com.zuehlke.jasschallenge.client.game.Move;
import com.zuehlke.jasschallenge.client.game.strategy.utils.Strategy;
import com.zuehlke.jasschallenge.client.game.strategy.utils.StrategyBuilder;
import com.zuehlke.jasschallenge.game.cards.Card;
import com.zuehlke.jasschallenge.game.mode.Mode;

import java.util.*;

import static com.zuehlke.jasschallenge.client.game.strategy.utils.rules.ChooseCardRules.*;
import static com.zuehlke.jasschallenge.client.game.strategy.utils.rules.ChooseTrumpfRules.CHOOSE_TRUMPF_WITH_HIGHEST_TOTAL_RANK;

public class StrongestOrWeakestStrategy implements JassStrategy {

private Strategy strategy;
private List<Move> allMoves = new ArrayList<>();

public StrongestOrWeakestStrategy() {
strategy = new StrategyBuilder()
.chooseTrumpfRules()
.addRule(CHOOSE_TRUMPF_WITH_HIGHEST_TOTAL_RANK)
.chooseCardRules()
.addRule(CHOOSE_STRONGEST_CARD_IF_ROUND_CAN_BE_WON)
.addRule(CHOOSE_WEAKEST_CARD_THAT_CAN_BE_APPLIED_TO_ROUND)
.addRule(CHOOSE_WEAKEST_CARD)
.build();
}

@Override
public Mode chooseTrumpf(Set<Card> availableCards, GameSession session, boolean isGschobe) {
return strategy.applyChooseTrumpfRules(availableCards, session, isGschobe);
}

@Override
public Card chooseCard(Set<Card> availableCards, GameSession session) {
return strategy.applyChooseCardRules(availableCards, session, allMoves);
}

@Override
public void onGameStarted(GameSession session) {
allMoves.clear();
}

@Override
public void onMoveMade(Move move, GameSession session) {
allMoves.add(move);
}
}
Loading