Commit 69f15321 authored by Colin DAMON's avatar Colin DAMON

Kata implementation

parent 963409d6
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