Skip to content

Commit

Permalink
Merge pull request #20 from Mw3y/step-11
Browse files Browse the repository at this point in the history
Step 11
  • Loading branch information
Mw3y authored May 24, 2024
2 parents f654e25 + e307444 commit 1e21714
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 121 deletions.
19 changes: 2 additions & 17 deletions src/ch/epfl/chacun/ActionEncoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ private static List<Pos> sortFringe(GameState gameState) {
*/
private static List<Occupant> sortOccupants(GameState gameState) {
return gameState.board().occupants().stream()
.sorted(Comparator.comparing(Occupant::zoneId)).toList();
.sorted(Comparator.comparing(Occupant::zoneId))
.toList();
}

/**
Expand Down Expand Up @@ -248,22 +249,6 @@ public record StateAction(GameState gameState, String action) {
* @author Balthazar Baillat (sciper: 373420)
*/
public static class IllegalActionException extends Exception {

/**
* Constructs an illegal action exception.
*/
public IllegalActionException() {
super();
}

/**
* Constructs an illegal action exception with a message.
*
* @param message the message
*/
public IllegalActionException(String message) {
super(message);
}
}


Expand Down
13 changes: 11 additions & 2 deletions src/ch/epfl/chacun/Base32.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,17 @@ public class Base32 {
* @return true if and only if the string is valid and false otherwise
*/
public static boolean isValid(String string) {
return string.chars().allMatch(c -> ALPHABET.indexOf(c) != -1);
return string.chars().allMatch(c -> isValid((char) c));
}

/**
* Checks if the given character is valid in base 32.
*
* @param character the character to be checked
* @return true if and only if the character is valid and false otherwise
*/
public static boolean isValid(char character) {
return ALPHABET.indexOf(character) != -1;
}

/**
Expand Down Expand Up @@ -60,7 +70,6 @@ public static String encodeBits10(int value) {
* @return the integer corresponding to the decoded value
*/
public static int decode(String value) {
Preconditions.checkArgument(value.length() == 1 || value.length() == 2);
Preconditions.checkArgument(isValid(value));
int decodedValue = 0;
// For each value, add its index in the base 32 alphabet times
Expand Down
52 changes: 21 additions & 31 deletions src/ch/epfl/chacun/MessageBoard.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,7 @@ public MessageBoard withScoredForest(Area<Zone.Forest> forest) {
int points = Points.forClosedForest(tileCount, mushroomGroupCount);
String messageContent = textMaker
.playersScoredForest(forest.majorityOccupants(), points, mushroomGroupCount, tileCount);
// Add a new message
List<Message> messages = newMessages(messageContent, points, forest.majorityOccupants(), forest.tileIds());
return new MessageBoard(textMaker, messages);
return addMessage(messageContent, points, forest.majorityOccupants(), forest.tileIds());
}
return this;
}
Expand All @@ -83,9 +81,7 @@ public MessageBoard withScoredForest(Area<Zone.Forest> forest) {
*/
public MessageBoard withClosedForestWithMenhir(PlayerColor player, Area<Zone.Forest> forest) {
String messageContent = textMaker.playerClosedForestWithMenhir(player);
// Create the message
List<Message> messages = newMessages(messageContent, 0, Set.of(), forest.tileIds());
return new MessageBoard(textMaker, messages);
return addMessage(messageContent, 0, Set.of(), forest.tileIds());
}

/**
Expand All @@ -105,9 +101,7 @@ public MessageBoard withScoredRiver(Area<Zone.River> river) {
Set<PlayerColor> scorers = river.majorityOccupants();
String messageContent = textMaker
.playersScoredRiver(scorers, points, fishCount, tileIds.size());
// Add a new message
List<Message> messages = newMessages(messageContent, points, scorers, tileIds);
return new MessageBoard(textMaker, messages);
return addMessage(messageContent, points, scorers, tileIds);
}
return this;
}
Expand All @@ -133,8 +127,7 @@ public MessageBoard withScoredHuntingTrap(PlayerColor scorer, Area<Zone.Meadow>
if (points > 0) {
// Add a new message
String messageContent = textMaker.playerScoredHuntingTrap(scorer, points, animalCount);
List<Message> messages = newMessages(messageContent, points, Set.of(scorer), adjacentMeadow.tileIds());
return new MessageBoard(textMaker, messages);
return addMessage(messageContent, points, Set.of(scorer), adjacentMeadow.tileIds());
}
return this;
}
Expand All @@ -152,9 +145,7 @@ public MessageBoard withScoredLogboat(PlayerColor scorer, Area<Zone.Water> river
int lakeCount = Area.lakeCount(riverSystem);
int points = Points.forLogboat(lakeCount);
String messageContent = textMaker.playerScoredLogboat(scorer, points, lakeCount);
// Add a new message
List<Message> messages = newMessages(messageContent, points, Set.of(scorer), riverSystem.tileIds());
return new MessageBoard(textMaker, messages);
return addMessage(messageContent, points, Set.of(scorer), riverSystem.tileIds());
}

/**
Expand All @@ -174,11 +165,8 @@ public MessageBoard withScoredRiverSystem(Area<Zone.Water> riverSystem) {
Set<PlayerColor> scorers = riverSystem.majorityOccupants();
// Don't create a message if no points are scored
if (points > 0) {
String messageContent = textMaker.playersScoredRiverSystem(scorers,
points, fishCount);
// Add a new message
List<Message> messages = newMessages(messageContent, points, scorers, riverSystem.tileIds());
return new MessageBoard(textMaker, messages);
String messageContent = textMaker.playersScoredRiverSystem(scorers, points, fishCount);
return addMessage(messageContent, points, scorers, riverSystem.tileIds());
}
}
return this;
Expand Down Expand Up @@ -206,9 +194,7 @@ public MessageBoard withScoredMeadow(Area<Zone.Meadow> meadow, Set<Animal> cance
// Don't create a message if no points are scored
if (points > 0) {
String messageContent = textMaker.playersScoredMeadow(scorers, points, animalCount);
// Add a new message
List<Message> messages = newMessages(messageContent, points, scorers, meadow.tileIds());
return new MessageBoard(textMaker, messages);
return addMessage(messageContent, points, scorers, meadow.tileIds());
}
}
return this;
Expand Down Expand Up @@ -242,8 +228,7 @@ public MessageBoard withScoredPitTrap(Area<Zone.Meadow> adjacentMeadow, Set<Anim
// Don't create a message if no points are scored
if (points > 0) {
String messageContent = textMaker.playersScoredPitTrap(scorers, points, animalCount);
List<Message> messages = newMessages(messageContent, points, scorers, adjacentMeadow.tileIds());
return new MessageBoard(textMaker, messages);
return addMessage(messageContent, points, scorers, adjacentMeadow.tileIds());
}
}
return this;
Expand All @@ -264,9 +249,7 @@ public MessageBoard withScoredRaft(Area<Zone.Water> riverSystem) {
int lakeCount = Area.lakeCount(riverSystem);
int points = Points.forRaft(lakeCount);
String messageContent = textMaker.playersScoredRaft(scorers, lakeCount, points);
// Add a new message
List<Message> messages = newMessages(messageContent, points, scorers, riverSystem.tileIds());
return new MessageBoard(textMaker, messages);
return addMessage(messageContent, points, scorers, riverSystem.tileIds());
}
return this;
}
Expand All @@ -280,8 +263,7 @@ public MessageBoard withScoredRaft(Area<Zone.Water> riverSystem) {
*/
public MessageBoard withWinners(Set<PlayerColor> winners, int points) {
String messageContent = textMaker.playersWon(winners, points);
List<Message> messages = newMessages(messageContent, 0, Set.of(), Set.of());
return new MessageBoard(textMaker, messages);
return addMessage(messageContent, 0, Set.of(), Set.of());
}

/**
Expand All @@ -297,10 +279,18 @@ private int pointsForMeadow(Map<Animal.Kind, Integer> animalCount) {
animalCount.getOrDefault(Animal.Kind.DEER, 0));
}

private List<Message> newMessages(String text, int points, Set<PlayerColor> scorers, Set<Integer> tileIds) {
/**
* Adds a new message to the message board.
* @param text the text of the message
* @param points the points associated with the message
* @param scorers the players who have scored the points
* @param tileIds the ids of the tiles involved in the message
* @return the list of messages with the new message added
*/
private MessageBoard addMessage(String text, int points, Set<PlayerColor> scorers, Set<Integer> tileIds) {
List<Message> newMessages = new ArrayList<>(messages);
newMessages.add(new Message(text, points, scorers, tileIds));
return newMessages;
return new MessageBoard(textMaker, newMessages);
}

/**
Expand Down
36 changes: 28 additions & 8 deletions src/ch/epfl/chacun/TextMakerFr.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,26 @@ private String joinAnimalsWithQuantities(Map<Animal.Kind, Integer> animals) {
.toList());
}

/**
* Returns a string with the name of the player and the points he's earned.
* @param player the player
* @param points the points
* @return the string with the name of the player and the points he's earned
*/
private String hasEarned(PlayerColor player, int points) {
return STR."\{playerName(player)} a remporté \{points(points)}";
}

/**
* Returns a string with the names of the players and the points they've earned.
* @param players the players
* @param points the points
* @return the string with the names of the players and the points they've earned
*/
private String hasEarnedPlural(Set<PlayerColor> players, int points) {
return STR."\{joinPlayerNames(players)} \{conjugateEarn(players)} \{points(points)}";
}

@Override
public String playerName(PlayerColor playerColor) {
return players.get(playerColor);
Expand All @@ -142,15 +162,15 @@ public String playerClosedForestWithMenhir(PlayerColor player) {
public String playersScoredForest(Set<PlayerColor> scorers, int points, int mushroomGroupCount, int tileCount) {
String mushrooms = mushroomGroupCount > 0 ?
STR." et de \{accord("groupe", mushroomGroupCount)} de champignons" : "";
return STR."\{joinPlayerNames(scorers)} \{conjugateEarn(scorers)} \{points(points)} en tant " +
return STR."\{hasEarnedPlural(scorers, points)} en tant " +
STR."qu'\{pluralize("occupant·e", scorers)} " +
STR."\{pluralize("majoritaire", scorers)} d'une forêt " +
STR."composée de \{accord("tuile", tileCount)}\{mushroomGroupCount > 0 ? mushrooms : ""}.";
}

@Override
public String playersScoredRiver(Set<PlayerColor> scorers, int points, int fishCount, int tileCount) {
return STR."\{joinPlayerNames(scorers)} \{conjugateEarn(scorers)} \{points(points)} en tant qu'" +
return STR."\{hasEarnedPlural(scorers, points)} en tant qu'" +
STR."\{pluralize("occupant·e", scorers)} " +
STR."\{pluralize("majoritaire", scorers)} d'une rivière " +
STR."composée de \{accord("tuile", tileCount)}" +
Expand All @@ -159,43 +179,43 @@ public String playersScoredRiver(Set<PlayerColor> scorers, int points, int fishC

@Override
public String playerScoredHuntingTrap(PlayerColor scorer, int points, Map<Animal.Kind, Integer> animals) {
return STR."\{playerName(scorer)} a remporté \{points(points)} en plaçant la fosse à pieux dans un pré " +
return STR."\{hasEarned(scorer, points)} en plaçant la fosse à pieux dans un pré " +
STR."dans lequel elle est entourée de \{joinAnimalsWithQuantities(animals)}.";
}

@Override
public String playerScoredLogboat(PlayerColor scorer, int points, int lakeCount) {
return STR."\{playerName(scorer)} a remporté \{points(points)} en plaçant la pirogue dans un réseau " +
return STR."\{hasEarned(scorer, points)} en plaçant la pirogue dans un réseau " +
STR."hydrographique contenant \{accord("lac", lakeCount)}.";
}

@Override
public String playersScoredMeadow(Set<PlayerColor> scorers, int points, Map<Animal.Kind, Integer> animals) {
return STR."\{joinPlayerNames(scorers)} \{conjugateEarn(scorers)} \{points(points)} en tant qu'" +
return STR."\{hasEarnedPlural(scorers, points)} en tant qu'" +
STR."\{pluralize("occupant·e", scorers)} " +
STR."\{pluralize("majoritaire", scorers)} d'un pré contenant " +
STR."\{joinAnimalsWithQuantities(animals)}.";
}

@Override
public String playersScoredRiverSystem(Set<PlayerColor> scorers, int points, int fishCount) {
return STR."\{joinPlayerNames(scorers)} \{conjugateEarn(scorers)} \{points(points)} en tant qu'" +
return STR."\{hasEarnedPlural(scorers, points)} en tant qu'" +
STR."\{pluralize("occupant·e", scorers)} " +
STR."\{pluralize("majoritaire", scorers)} d'un réseau " +
STR."hydrographique contenant \{accord("poisson", fishCount)}.";
}

@Override
public String playersScoredPitTrap(Set<PlayerColor> scorers, int points, Map<Animal.Kind, Integer> animals) {
return STR."\{joinPlayerNames(scorers)} \{conjugateEarn(scorers)} \{points(points)} " +
return STR."\{hasEarnedPlural(scorers,points)} " +
STR."en tant qu'\{pluralize("occupant·e", scorers)} " +
STR."\{pluralize("majoritaire", scorers)} d'un pré contenant " +
STR."la grande fosse à pieux entourée de \{joinAnimalsWithQuantities(animals)}.";
}

@Override
public String playersScoredRaft(Set<PlayerColor> scorers, int points, int lakeCount) {
return STR."\{joinPlayerNames(scorers)} \{conjugateEarn(scorers)} \{points(points)} en tant " +
return STR."\{hasEarnedPlural(scorers, points)} en tant " +
STR."qu'\{pluralize("occupant·e", scorers)} " +
STR."\{pluralize("majoritaire", scorers)} " +
STR."d'un réseau hydrographique contenant le radeau et \{accord("lac", lakeCount)}.";
Expand Down
51 changes: 31 additions & 20 deletions src/ch/epfl/chacun/gui/ActionUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
* Helper class to display the actions interface.
Expand All @@ -19,6 +21,11 @@
*/
public final class ActionUI {

/**
* The maximum number of actions to display at a time.
*/
private static final int NUMBER_OF_ACTIONS_TO_DISPLAY = 4;

/**
* Non-instantiable class constructor.
*/
Expand All @@ -38,30 +45,21 @@ public static Node create(ObservableValue<List<String>> actionsO, Consumer<Strin
container.setId("actions");

Text fourPreviousActionsText = new Text();
// Only display the last NUMBER_OF_ACTIONS_TO_DISPLAY actions
fourPreviousActionsText.textProperty().bind(actionsO.map(actions -> {
StringBuilder s = new StringBuilder();
List<String> fourPreviousActions = actions.size() < 4 ? actions
: actions.subList(actions.size() - 4, actions.size());

int index = actions.size() / 4;
for (int i = 0; i < fourPreviousActions.size(); ++i) {
s.append(STR."\{index + i + 1}:\{fourPreviousActions.get(i)} ");
}
return s.toString();
int numberOfAppliedActions = actions.size();
int firstIndex = Math.max(0, numberOfAppliedActions - NUMBER_OF_ACTIONS_TO_DISPLAY);
return IntStream.range(firstIndex, numberOfAppliedActions)
.mapToObj(i -> STR."\{i + 1}:\{actions.get(i)}")
.collect(Collectors.joining(", "));
}));

TextField actionField = new TextField();
actionField.setId("action-field");

// Sanitize the user input
actionField.setTextFormatter(new TextFormatter<>(change -> {
// TODO: Use streams
change.setText(change.getText().toUpperCase());
change.getText().chars().forEach(i -> {
String c = String.valueOf((char) i);
// TODO: Optimize
if (!Base32.isValid(c) || actionField.getText().length() >= 2)
change.setText(change.getText().replace(c, ""));
});
String sanitizedInput = sanitizeInput(change.getText());
change.setText(sanitizedInput);
return change;
}));

Expand All @@ -71,8 +69,21 @@ public static Node create(ObservableValue<List<String>> actionsO, Consumer<Strin
actionField.clear();
});

container.getChildren().add(fourPreviousActionsText);
container.getChildren().add(actionField);
container.getChildren().addAll(fourPreviousActionsText, actionField);
return container;
}

/**
* Sanitizes the input by uppercasing it and only keeping the characters that are in the base 32 alphabet.
* @param input the input to sanitize
* @return the sanitized input
*/
private static String sanitizeInput(String input) {
StringBuilder sanitizedInput = new StringBuilder();
for (char character : input.toUpperCase().toCharArray()) {
if (Base32.isValid(character))
sanitizedInput.append(character);
}
return sanitizedInput.toString();
}
}
Loading

0 comments on commit 1e21714

Please sign in to comment.