diff --git a/doc/prices.png b/doc/prices.png new file mode 100644 index 0000000..0b82c0f Binary files /dev/null and b/doc/prices.png differ diff --git a/phpunit.xml b/phpunit.xml index 01e21e2..1ea1df0 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -8,6 +8,7 @@ beStrictAboutOutputDuringTests="true" beStrictAboutTodoAnnotatedTests="true" verbose="true" + testdox="true" colors="true"> diff --git a/src/Game.php b/src/Game.php new file mode 100644 index 0000000..d57e55b --- /dev/null +++ b/src/Game.php @@ -0,0 +1,49 @@ +withPriceList(Milk::name(), $priceBuilder->milkPrices()) + ->withPriceList(Wool::name(), $priceBuilder->woolPrices()) + ->withPriceList(Grain::name(), $priceBuilder->grainPrices()); + + $player = new Player($money, $market); + while (true) { + echo sprintf('You have %i pounds', $player->money()); + $goodName = readline(sprintf('What do you want to buy now? (%s)', implode(',', self::GOODS))); + $amount = (int)readline('How many pounds?'); + $player->buy(new Unit($amount), Good::byName($goodName)); + static::printMarket($market); + sleep(1); + } + } + + private static function printMarket(Market $market) + { + foreach($market->allPriceList() as $goodName => $priceList){ + echo $goodName.PHP_EOL; + foreach($priceList as $price) { + // display the table + } + echo PHP_EOL; + } + } +} diff --git a/src/Good.php b/src/Good.php index 2e540c6..431d96b 100644 --- a/src/Good.php +++ b/src/Good.php @@ -1,11 +1,45 @@ */ + private $prices; + + public function __construct() { - return new Pound(5); + $this->prices = []; + } + + public function withPriceList(string $goodName, PriceList $priceList): self + { + $this->prices[$goodName] = $priceList; + + return $this; + } + + public function priceFor(Good $good): Pound + { + return $this->prices[$good->name()]->current(); } public function sellTo(Offer $offer): Pound { - return new Pound( - $offer->amount()->amount() * - $this->priceFor($offer->good())->amount() - ); + $good = $offer->good(); + $unit = $offer->amount(); + $payment = $this->priceFor($good)->multiply($unit->amount()); + $this->adjustPrice($good, $unit); + + return $payment; + } + + private function adjustPrice(Good $good, Unit $unit) + { + /** @var PriceList $priceList */ + $priceList = $this->prices[$good->name()]; + $priceList->moveTo($unit); } } diff --git a/src/Milk.php b/src/Milk.php deleted file mode 100644 index 8689abe..0000000 --- a/src/Milk.php +++ /dev/null @@ -1,10 +0,0 @@ -money = $money; + $this->market = $market; + } + + public function buy(Unit $unit, Good $good): void + { + $payment = $this->market->sellTo(new Offer($unit, $good)); + $this->money = $this->money->minus($payment->amount()); + } + + public function money(): Pound + { + return $this->money; + } +} diff --git a/src/Pound.php b/src/Pound.php index 1be124e..069a23a 100644 --- a/src/Pound.php +++ b/src/Pound.php @@ -1,4 +1,5 @@ amount; } + + public function multiply(int $factor): Pound + { + return new Pound($this->amount * $factor); + } + + public function minus(int $number): Pound + { + return new Pound($this->amount - $number); + } } diff --git a/src/PriceList.php b/src/PriceList.php index 8a6a231..2368de0 100644 --- a/src/PriceList.php +++ b/src/PriceList.php @@ -1,4 +1,5 @@ position = $initPosition; $this->prices = $prices; } @@ -30,4 +33,9 @@ public function current(): Pound { return $this->prices[$this->position]; } + + public function moveTo(Unit $unit): void + { + $this->position += $unit->amount(); + } } diff --git a/src/PriceListBuilder.php b/src/PriceListBuilder.php index bc0da06..8c5995b 100644 --- a/src/PriceListBuilder.php +++ b/src/PriceListBuilder.php @@ -1,4 +1,5 @@ '/Exception.php', 'clansofcaledonia\\good' => '/Good.php', + 'clansofcaledonia\\good\\grain' => '/Good/Grain.php', + 'clansofcaledonia\\good\\milk' => '/Good/Milk.php', + 'clansofcaledonia\\good\\wool' => '/Good/Wool.php', 'clansofcaledonia\\market' => '/Market.php', - 'clansofcaledonia\\milk' => '/Milk.php', 'clansofcaledonia\\offer' => '/Offer.php', 'clansofcaledonia\\outofrangeexception' => '/OutOfRangeException.php', + 'clansofcaledonia\\player' => '/Player.php', 'clansofcaledonia\\pound' => '/Pound.php', 'clansofcaledonia\\pricelist' => '/PriceList.php', 'clansofcaledonia\\pricelistbuilder' => '/PriceListBuilder.php', diff --git a/tests/GoodTest.php b/tests/Good/GoodTest.php similarity index 61% rename from tests/GoodTest.php rename to tests/Good/GoodTest.php index f44ff47..cd19b21 100644 --- a/tests/GoodTest.php +++ b/tests/Good/GoodTest.php @@ -1,6 +1,8 @@ assertTrue($milk->isMilk()); } + + public function testCanNotBeMilk(): void + { + $grain = Good::grain(); + + $this->assertFalse($grain->isMilk()); + } } diff --git a/tests/MarketTest.php b/tests/MarketTest.php index d01128e..83be875 100644 --- a/tests/MarketTest.php +++ b/tests/MarketTest.php @@ -1,39 +1,56 @@ market = (new Market) + ->withPriceList( + Milk::name(), + PriceList::fromList( + $initPosition = 0, + new Pound(10), + new Pound(20), + new Pound(30), + new Pound(40), + new Pound(50) + ) + ); + } - $this->assertEquals(new Pound(5), $market->priceFor(Good::milk())); + public function testInitialPoundsFromInitPosition(): void + { + $this->assertEquals(new Pound(10), $this->market->priceFor(Good::milk())); } public function testMilkCanBeSoldToTheMarket(): Market { - $market = new Market; - - $payment = $market->sellTo( + $payment = $this->market->sellTo( new Offer( - new Unit(2), + new Unit(3), Good::milk() ) ); - $this->assertEquals(new Pound(10), $payment); + $this->assertEquals(new Pound(30), $payment); - return $market; + return $this->market; } /** @@ -41,6 +58,6 @@ public function testMilkCanBeSoldToTheMarket(): Market */ public function testSellingMilkToTheMarketReducesMilkPrice(Market $market): void { - $this->assertEquals(new Pound(4), $market->priceFor(Good::milk())); + $this->assertEquals(new Pound(40), $market->priceFor(Good::milk())); } } diff --git a/tests/PlayerTest.php b/tests/PlayerTest.php new file mode 100644 index 0000000..8e02e91 --- /dev/null +++ b/tests/PlayerTest.php @@ -0,0 +1,38 @@ +withPriceList( + $good::name(), + PriceList::fromList( + $initPosition = 0, + new Pound(10), + new Pound(20), + new Pound(30), + new Pound(40), + new Pound(50) + )); + + $initPounds = new Pound(100); + $player = new Player($initPounds, $market); + $player->buy(new Unit(2), Good::milk()); + + $this->assertEquals(new Pound(80), $player->money()); + $this->assertEquals(new Pound(30), $market->priceFor($good)); + } + +} diff --git a/tests/PoundTest.php b/tests/PoundTest.php index 3d3ec6d..0b593a4 100644 --- a/tests/PoundTest.php +++ b/tests/PoundTest.php @@ -1,4 +1,5 @@ assertSame($amount, $p->amount()); } + + /** + * @dataProvider multiplyFactors + */ + public function testCanBeMultiplyByAFactor(int $init, int $factor, int $result): void + { + $this->assertEquals(new Pound($result), (new Pound($init))->multiply($factor)); + } + + public function multiplyFactors(): array + { + return [ + [2, 2, 4], + [2, 5, 10], + [3, 2, 6], + ]; + } + /** + * @dataProvider minusNumbers + */ + public function testCanBeMinusByANumber(int $init, int $factor, int $result): void + { + $this->assertEquals(new Pound($result), (new Pound($init))->minus($factor)); + } + + public function minusNumbers(): array + { + return [ + [2, 2, 0], + [2, 5, -3], + [3, 2, 1], + ]; + } } diff --git a/tests/PriceListBuilderTest.php b/tests/PriceListBuilderTest.php index 5df7e04..27fdfd5 100644 --- a/tests/PriceListBuilderTest.php +++ b/tests/PriceListBuilderTest.php @@ -1,4 +1,5 @@ assertEquals(new Pound(5), $milkPrices->current()); } + + public function testCanBuildWoolPriceList(): void + { + $builder = new PriceListBuilder; + + $milkPrices = $builder->woolPrices(); + + $this->assertEquals(new Pound(4), $milkPrices->current()); + } + + public function testCanBuildGrainPriceList(): void + { + $builder = new PriceListBuilder; + + $milkPrices = $builder->grainPrices(); + + $this->assertEquals(new Pound(5), $milkPrices->current()); + } } diff --git a/tests/PriceListTest.php b/tests/PriceListTest.php index aba7abb..ab9278f 100644 --- a/tests/PriceListTest.php +++ b/tests/PriceListTest.php @@ -1,4 +1,5 @@ assertEquals(new Pound(4), $prices->current()); + $this->assertEquals(new Pound(2), $prices->current()); } }