Commit fa6ae32c authored by Colin DAMON's avatar Colin DAMON
Browse files

Merge branch '53-h2g2-kata-java' into 'master'

Resolve "H2G2 kata java"

Closes #53

See merge request !38
parents 734bd362 69f15321
...@@ -15,3 +15,4 @@ include: ...@@ -15,3 +15,4 @@ include:
- local: "/string-calculator-2/.gitlab-ci.yml" - local: "/string-calculator-2/.gitlab-ci.yml"
- local: "/trip-service-kata/.gitlab-ci.yml" - local: "/trip-service-kata/.gitlab-ci.yml"
- local: "/tcr-roman-numerals/.gitlab-ci.yml" - local: "/tcr-roman-numerals/.gitlab-ci.yml"
- local: "/java-h2g2/.gitlab-ci.yml"
...@@ -37,3 +37,4 @@ Ce dépôt Git a pour but de partager les différents ateliers pouvant être ré ...@@ -37,3 +37,4 @@ Ce dépôt Git a pour but de partager les différents ateliers pouvant être ré
| [Proxifier son localhost avec un nginx dockerisé avec Edouard CATTEZ](https://www.youtube.com/watch?v=qWMfRb3zK7k) | Talk | Facile | | [Proxifier son localhost avec un nginx dockerisé avec Edouard CATTEZ](https://www.youtube.com/watch?v=qWMfRb3zK7k) | Talk | Facile |
| [Dev pour des data scientists, un sale boulot](https://www.youtube.com/watch?v=QK3OJGAresE) | Discussion | | | [Dev pour des data scientists, un sale boulot](https://www.youtube.com/watch?v=QK3OJGAresE) | Discussion | |
| [TCR - Roman Numerals](/tcr-roman-numerals) | Kata | Moyenne | | [TCR - Roman Numerals](/tcr-roman-numerals) | Kata | Moyenne |
| [H2G2 en Java](/java-h2g2) | Kata | Moyenne |
package-java-h2g2:
variables:
PROJECT_FOLDER: "java-h2g2"
extends: .java
only:
refs:
- master
- merge_requests
changes:
- ".gitlab-common-ci.yml"
- "java-h2g2/**/*"
# Java h2g2
Résolution en TDD et en Java du kata [Potter](https://codingdojo.org/kata/Potter/) renommé h2g2 pour l'occasion.
- **Auteurs** : Anthony REY et Colin DAMON
- **Date** : 27/11/2020
- **Langage** : Java
- **Niveau** : Moyen
- **Replay** : TODO
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.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>java-h2g2</artifactId>
<name>JavaH2G2</name>
<developers>
<developer>
<email>arey@ippon.fr</email>
<name>Anthony REY</name>
</developer>
<developer>
<email>cdamon@ippon.fr</email>
<name>Colin DAMON</name>
</developer>
</developers>
</project>
package fr.ippon.kata.h2g2;
public enum Book {
FIRST,
SECOND,
THIRD,
FORTH,
FIFTH
}
package fr.ippon.kata.h2g2;
import static java.util.stream.Collectors.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Shop {
private static final Map<Integer, Float> FACTORS = buildFactors();
private static final int BOOK_PRICE = 8;
private static Map<Integer, Float> buildFactors() {
Map<Integer, Float> factors = new HashMap<>();
factors.put(5, 0.75f);
factors.put(4, 0.80f);
factors.put(3, 0.90f);
factors.put(2, 0.95f);
factors.put(1, 1f);
factors.put(0, 1f);
return factors;
}
public static float buy(Book... books) {
Basket basket = new Basket(books);
return (float) basket.getPacks().stream().map(packPrice()).reduce(BigDecimal.ZERO, BigDecimal::add).floatValue();
}
private static Function<Integer, BigDecimal> packPrice() {
return count -> BigDecimal.valueOf(BOOK_PRICE * count * FACTORS.get(count));
}
private static final class Basket {
private final Collection<Integer> packs;
public Basket(Book... books) {
packs = buildPacks(books);
}
private Collection<Integer> buildPacks(Book[] books) {
Map<Book, Integer> groupedBooks = groupBooks(books);
List<Integer> packs = firstPackLevel(groupedBooks);
return optimizePacks(packs);
}
private Collection<Integer> optimizePacks(List<Integer> packs) {
int threePack = countPackBySize(packs, 3);
int fivePack = countPackBySize(packs, 5);
int commonPacks = Math.min(fivePack, threePack);
List<Integer> result = new ArrayList<>();
result.addAll(repeatPack(1, countPackBySize(packs, 1)));
result.addAll(repeatPack(2, countPackBySize(packs, 2)));
result.addAll(repeatPack(3, threePack - commonPacks));
result.addAll(repeatPack(4, countPackBySize(packs, 4) + commonPacks * 2));
result.addAll(repeatPack(5, fivePack - commonPacks));
return result;
}
private List<Integer> repeatPack(int packSize, int packCount) {
return IntStream.range(0, packCount).mapToObj(key -> Integer.valueOf(packSize)).collect(Collectors.toList());
}
private int countPackBySize(List<Integer> packs, int size) {
return (int) packs.stream().filter(value -> value == size).count();
}
private List<Integer> firstPackLevel(Map<Book, Integer> groupedBooks) {
List<Integer> packs = new ArrayList<>();
while (remainingBooks(groupedBooks)) {
packs.add(groupedBooks.size());
groupedBooks =
groupedBooks.entrySet().stream().filter(booksRemaining()).collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue() - 1));
}
return packs;
}
private boolean remainingBooks(Map<Book, Integer> groupedBooks) {
return !groupedBooks.isEmpty();
}
private Predicate<Entry<Book, Integer>> booksRemaining() {
return entry -> entry.getValue() > 1;
}
private static Map<Book, Integer> groupBooks(Book... books) {
return Arrays
.stream(books)
.collect(groupingBy(Function.identity()))
.entrySet()
.stream()
.collect(toMap(Entry::getKey, entry -> entry.getValue().size()));
}
private Collection<Integer> getPacks() {
return packs;
}
}
}
package fr.ippon.kata.h2g2;
import static fr.ippon.kata.h2g2.Book.*;
import static org.assertj.core.api.Assertions.*;
import org.junit.jupiter.api.Test;
class H2G2Test {
@Test
void shouldBeFreeWithoutBooks() {
assertThat(Shop.buy()).isEqualTo(0);
}
@Test
void shouldPayFullPriceForOneBook() {
assertThat(Shop.buy(FIRST)).isEqualTo(8);
}
@Test
void shouldPayFullPriceForTwoFirstBooks() {
assertThat(Shop.buy(FIRST, FIRST)).isEqualTo(8 * 2);
}
@Test
void shouldGetFivePercentOffWithTwoBooksFromSeries() {
assertThat(Shop.buy(FIRST, SECOND)).isEqualTo(8 * 2 * 0.95f);
}
@Test
void shouldGetTenPercentOffWithThreeBooksFromSeries() {
assertThat(Shop.buy(THIRD, FORTH, FIFTH)).isEqualTo(8 * 3 * 0.90f);
}
@Test
void shouldGetTwentyPercentOffWithFourBooksFromSeries() {
assertThat(Shop.buy(SECOND, THIRD, FORTH, FIFTH)).isEqualTo(8 * 4 * 0.80f);
}
@Test
void shouldGetTwentyFivePercentOffWithFiveBooksFromSeries() {
assertThat(Shop.buy(FIRST, SECOND, THIRD, FORTH, FIFTH)).isEqualTo(8 * 5 * 0.75f);
}
@Test
void shouldGetBestPossibleReductionForFirstFirstSecond() {
assertThat(Shop.buy(FIRST, FIRST, SECOND)).isEqualTo(8 + (8 * 2 * 0.95f));
}
@Test
void shouldGetBestPossibleReductionForBasketOfHell() {
assertThat(Shop.buy(FIRST, FIRST, SECOND, SECOND, THIRD, THIRD, FORTH, FIFTH)).isEqualTo(2 * 8 * 4 * 0.8f);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment