Commit 7306f26f authored by Colin DAMON's avatar Colin DAMON
Browse files

Merge branch '24-ugly-trivia' into 'master'

Resolve "Ugly trivia"

Closes #24

See merge request !21
parents 35acb32e 1c54461c
...@@ -7,3 +7,4 @@ include: ...@@ -7,3 +7,4 @@ include:
- local: "/roman-numerals/.gitlab-ci.yml" - local: "/roman-numerals/.gitlab-ci.yml"
- local: "/string-calculator/.gitlab-ci.yml" - local: "/string-calculator/.gitlab-ci.yml"
- local: "/gilded-rose/.gitlab-ci.yml" - local: "/gilded-rose/.gitlab-ci.yml"
- local: "/ugly-trivia/.gitlab-ci.yml"
...@@ -22,3 +22,4 @@ Ce dépôt Git a pour but de partager les différents ateliers pouvant être ré ...@@ -22,3 +22,4 @@ Ce dépôt Git a pour but de partager les différents ateliers pouvant être ré
4. [C'est une bonne situation ça techlead ? (débat)](https://www.youtube.com/watch?v=9tOoXfOE12o) 4. [C'est une bonne situation ça techlead ? (débat)](https://www.youtube.com/watch?v=9tOoXfOE12o)
5. [Pagination Seven](/pagination-seven) 5. [Pagination Seven](/pagination-seven)
6. [GildedRose](/gilded-rose) 6. [GildedRose](/gilded-rose)
7. [UglyTrivia](/ugly-trivia)
package-ugly-trivia:
variables:
PROJECT_FOLDER: "ugly-trivia"
extends: .java
only:
refs:
- master
- merge_requests
changes:
- ".gitlab-common-ci.yml"
- "ugly-trivia/**/*"
# String calculator
Revue d'[UglyTrivia](/uglyTrivia).
Dans le cadre d'un programme de mentoring interne (BlackBelt) Julie a fait une résolution du kata ugly trivia. Pendant ce live, Julie et Colin (son mentor) vont faire une revue de cette résolution.
- **Auteurs** : Colin DAMON et Julie CONTE
- **Date** : 19/09/2020
- **Langage** : Java
- **Niveau** : Moyen
- **Replay** : [REVUE KATA : Ugly Trivia avec Julie, Emmanuelle, Alexis & Colin](https://www.youtube.com/watch?v=IeAa8chmngI)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<version>1.0.0</version>
<groupId>fr.ippon.kata</groupId>
<artifactId>java-parent</artifactId>
<relativePath>../java-parent</relativePath>
</parent>
<version>1.0.0-SNAPSHOT</version>
<artifactId>ugly-trivia</artifactId>
<name>UglyTrivia</name>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-booter</artifactId>
<version>3.0.0-M3</version>
</dependency>
</dependencies>
<developers>
<developer>
<email>jconte@ippon.fr</email>
<name>Julie CONTE</name>
</developer>
<developer>
<email>cdamon@ippon.fr</email>
<name>Colin DAMON</name>
</developer>
</developers>
</project>
package com.adaptionsoft.games.uglytrivia;
public class Answer {
private final Notifications notifications;
private final AnswerRandomSimulator answerRandom;
public Answer(Notifications notifications, AnswerRandomSimulator answerRandom) {
this.notifications = notifications;
this.answerRandom = answerRandom;
}
public Player answer(Player player) {
if (!answerRandom.isRight()) {
return wrongAnswer(player);
}
return goodAnswer(player);
}
private Player goodAnswer(Player player) {
if (!player.isInPenaltyBox()) {
notifications.correctAnswer();
player = player.addCoin();
notifications.actualGoldCoins(player.getName(), player.getPurse());
}
return player;
}
private Player wrongAnswer(Player player) {
notifications.incorrectlyAnswered();
notifications.sendInPenaltyBox(player.getName());
return player.inPenaltyBox();
}
}
package com.adaptionsoft.games.uglytrivia;
import java.util.Random;
class AnswerRandomSimulator {
private final Random rand;
AnswerRandomSimulator(Random rand) {
this.rand = rand;
}
boolean isRight() {
return !(rand.nextInt(9) == 7);
}
}
package com.adaptionsoft.games.uglytrivia;
class Board {
private final int limitBoardSize;
Board(int limitBoardSize) {
this.limitBoardSize = limitBoardSize;
}
boolean isBeyondLimitBoard(int position) {
return position >= limitBoardSize;
}
int getLimit() {
return limitBoardSize;
}
}
package com.adaptionsoft.games.uglytrivia;
import java.util.Arrays;
import java.util.List;
enum Category {
POP("Pop", List.of(0,4,8)),
SCIENCE("Science", List.of(1,5,9)),
SPORTS("Sports", List.of(2,6,10)),
ROCK("Rock", List.of());
private final String category;
private final List<Integer> positions;
Category(String category, List<Integer> positions) {
this.category = category;
this.positions = positions;
}
static Category fromPosition(int position) {
return Arrays.stream(Category.values()).filter(category -> category.positions.contains(position)).findFirst().orElse(Category.ROCK);
}
String getCategory() {
return category;
}
}
package com.adaptionsoft.games.uglytrivia;
import java.io.PrintStream;
class ConsolePrinter {
private final PrintStream print;
public ConsolePrinter(PrintStream print) {
this.print = print;
}
void sendMessage(String message) {
print.println(message);
}
}
package com.adaptionsoft.games.uglytrivia;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
class Deck {
Map<Category, LinkedList<Question>> deck;
Deck(int limitDeckSize) {
deck = new HashMap<>();
deck.put(Category.POP, new LinkedList<>());
deck.put(Category.SCIENCE, new LinkedList<>());
deck.put(Category.SPORTS, new LinkedList<>());
deck.put(Category.ROCK, new LinkedList<>());
for (int i = 0; i < limitDeckSize; i++) {
deck.get(Category.POP).addLast(new Question(Category.POP, i));
deck.get(Category.SCIENCE).addLast(new Question(Category.SCIENCE, i));
deck.get(Category.SPORTS).addLast(new Question(Category.SPORTS, i));
deck.get(Category.ROCK).addLast(new Question(Category.ROCK, i));
}
}
String removeFirstQuestion(Category category) {
return deck.get(category).removeFirst().getMessage();
}
}
package com.adaptionsoft.games.uglytrivia;
import java.util.Random;
class Dice {
private final Random rand;
public Dice(Random rand) {
this.rand = rand;
}
public int roll() {
return rand.nextInt(5) + 1;
}
}
package com.adaptionsoft.games.uglytrivia;
class Game {
static final int MAX_PLAYER_PLAYABLE = 6;
static final int MAX_GOLD_COINS = 6;
static final int MIN_PLAYER_PLAYABLE = 2;
static final int LIMIT_DECK_SIZE = 50;
private final Turn turn;
private final Answer answer;
private final Notifications notifications;
private final Deck deck;
private Players players;
Game(Turn turn, Answer answer, Notifications notifications) {
this.notifications = notifications;
this.turn = turn;
this.answer = answer;
players = new Players();
deck = new Deck(LIMIT_DECK_SIZE);
}
boolean isPlayable() {
return minimumPlayer() && limitPlayersNotExceeded();
}
private boolean minimumPlayer() {
return howManyPlayers() >= MIN_PLAYER_PLAYABLE;
}
private boolean limitPlayersNotExceeded() {
return howManyPlayers() < MAX_PLAYER_PLAYABLE;
}
boolean add(String playerName) {
players = players.add(playerName);
notifications.addPlayer(playerName);
notifications.playerPlace(howManyPlayers());
return true;
}
private int howManyPlayers() {
return players.howManyPlayers();
}
boolean playTurn() {
updateCurrentPlayer(turn.tryToPlay(currentPlayer()));
askQuestion();
updateCurrentPlayer(answer.answer(currentPlayer()));
if (didPlayerWin()) {
return true;
}
players = players.nextPlayer();
return false;
}
private boolean didPlayerWin() {
return currentPlayer().getPurse() == MAX_GOLD_COINS;
}
private void updateCurrentPlayer(Player currentPlayer) {
players = players.updateCurrentPlayer(currentPlayer);
}
private void askQuestion() {
notifications.askQuestion(deck.removeFirstQuestion(currentCategory()));
}
private Category currentCategory() {
return Category.fromPosition(currentPlayer().getPosition());
}
private Player currentPlayer() {
return players.getCurrentPlayer();
}
}
package com.adaptionsoft.games.uglytrivia;
class Notifications {
private final ConsolePrinter printer;
public Notifications(ConsolePrinter printer) {
this.printer = printer;
}
void addPlayer(String player) {
printer.sendMessage(player + " was added");
}
void playerPlace(int place) {
printer.sendMessage("They are player number " + place);
}
void currentPlayer(String player) {
printer.sendMessage(player + " is the current player");
}
void roll(int roll) {
printer.sendMessage("They have rolled a " + roll);
}
void notGettingOutOfPenaltyBox(String player) {
printer.sendMessage(player + " is not getting out of the penalty box");
}
void newLocation(String player, int location) {
printer.sendMessage(player + "'s new location is " + location);
}
void currentCategory(String category) {
printer.sendMessage("The category is " + category);
}
void gettingOutOfPenaltyBox(String player) {
printer.sendMessage(player + " is getting out of the penalty box");
}
void correctAnswer() {
printer.sendMessage("Answer was correct!!!!");
}
void actualGoldCoins(String player, int goldCoins) {
printer.sendMessage(player + " now has " + goldCoins + " Gold Coins.");
}
void incorrectlyAnswered() {
printer.sendMessage("Question was incorrectly answered");
}
void sendInPenaltyBox(String player) {
printer.sendMessage(player + " was sent to the penalty box");
}
void askQuestion(String question) {
printer.sendMessage(question);
}
}
package com.adaptionsoft.games.uglytrivia;
import org.apache.maven.surefire.shade.booter.org.apache.commons.lang3.builder.HashCodeBuilder;
import java.util.Optional;
class Player {
private final String name;
private final int position;
private final int purse;
private final boolean inPenaltyBox;
private final int order;
Player(String name, int order) {
this.name = name;
this.position = 0;
this.purse = 0;
this.inPenaltyBox = false;
this.order = order;
}
private Player(PlayerBuilder builder) {
name = builder.name;
position = builder.position;
purse = builder.purse;
inPenaltyBox = builder.isInPenaltyBox;
order = builder.order;
}
String getName() {
return name;
}
int getPosition() {
return position;
}
Player position(int position) {
int newPosition = this.position + position;
return buildNewPlayer(Optional.of(newPosition), Optional.empty(), Optional.empty());
}
Player reset(int borderBoard) {
Integer newPosition = position - borderBoard;
return buildNewPlayer(Optional.of(newPosition), Optional.empty(), Optional.empty());
}
int getPurse() {
return purse;
}
Player addCoin() {
return buildNewPlayer(Optional.empty(), Optional.of(this.purse + 1), Optional.empty());
}
boolean isInPenaltyBox() {
return inPenaltyBox;
}
Player inPenaltyBox() {
return buildNewPlayer(Optional.empty(), Optional.empty(), Optional.of(true));
}
Player outPenaltyBox() {
return buildNewPlayer(Optional.empty(), Optional.empty(), Optional.of(false));
}
public int getOrder() {
return order;
}
private Player buildNewPlayer(Optional<Integer> position, Optional<Integer> purse, Optional<Boolean> inPenaltyBox) {
return new PlayerBuilder()
.name(name)
.position(position.orElse(this.position))
.purse(purse.orElse(this.purse))
.isInPenaltyBox(inPenaltyBox.orElse(this.inPenaltyBox))
.order(order)
.build();
}
private static class PlayerBuilder {
private String name;
private int position;
private int purse;
private boolean isInPenaltyBox;
private int order;
PlayerBuilder name(String name) {
this.name = name;
return this;
}
PlayerBuilder position(int position) {
this.position = position;
return this;
}
PlayerBuilder purse(int purse) {
this.purse = purse;
return this;
}
PlayerBuilder isInPenaltyBox(boolean isInPenaltyBox) {
this.isInPenaltyBox = isInPenaltyBox;
return this;
}
PlayerBuilder order(int order) {
this.order = order;
return this;
}
Player build() {
return new Player(this);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Player player = (Player) o;
return name.equals(player.name) && order == player.getOrder();
}
@Override
public int hashCode() {
return new HashCodeBuilder().append(name).append(order).build();
}
}
package com.adaptionsoft.games.uglytrivia;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
class Players {
private final List<Player> players;
private int currentPlayer;
Players() {
this.players = new ArrayList<>();
}
Players(List<Player> players, int currentPlayer) {
this.players = players.stream().sorted(Comparator.comparing(Player::getOrder)).collect(Collectors.toUnmodifiableList());
this.currentPlayer = currentPlayer;
}
Players add(String playerName) {
List<Player> newPlayers = new ArrayList<>(players);
newPlayers.add(new Player(playerName, players.size()));
return new Players(newPlayers, currentPlayer);
}
Player get(int index) {
return players.get(index);
}
int howManyPlayers() {
return players.size();
}
Player getCurrentPlayer() {
return players.get(currentPlayer);
}
Players nextPlayer() {
currentPlayer++;
if (isExceededLimitPlayers(currentPlayer)) {
currentPlayer = 0;
}
return new Players(players, currentPlayer);
}
private boolean isExceededLimitPlayers(int index) {
return index >= players.size();
}
Players updateCurrentPlayer(Player player) {
List<Player> newPlayers = new ArrayList<>(players);
newPlayers.remove(currentPlayer);
newPlayers.add(player);
return new Players(newPlayers, currentPlayer);
}
}
package com.adaptionsoft.games.uglytrivia;
class Question {
private final String message;
Question(Category category, int index) {