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

Step 11 - fixes #19

Merged
merged 13 commits into from
May 24, 2024
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
15 changes: 12 additions & 3 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 All @@ -48,7 +58,7 @@ public static String encodeBits5(int value) {
*/
public static String encodeBits10(int value) {
// Encoded independently two 5-bit parts and merge them
return encodeBits5(value >> BASE_32_SYMBOL_BITS) + encodeBits5(value);
return encodeBits5(value >> BASE_32_SYMBOL_BITS) + encodeBits5(value);
}

/**
Expand All @@ -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
50 changes: 31 additions & 19 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,29 +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);
if (!Base32.isValid(c))
change.setText(change.getText().replace(c, ""));
});
String sanitizedInput = sanitizeInput(change.getText());
change.setText(sanitizedInput);
return change;
}));

Expand All @@ -70,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
Loading