Skip to content

Commit 11c37b8

Browse files
committed
extract rules to the warrior builder
1 parent 36029dd commit 11c37b8

File tree

5 files changed

+86
-39
lines changed

5 files changed

+86
-39
lines changed

src/Realms/RolePlaying/Character.php

-23
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,14 @@
55
namespace App\Realms\RolePlaying;
66

77
use App\Realms\RolePlaying\Inventory\Item;
8-
use App\Realms\RolePlaying\Inventory\ItemType;
9-
use App\Realms\RolePlaying\Inventory\Problems\CannotWearMultipleArmors;
10-
use App\Realms\RolePlaying\Inventory\Problems\CannotWearTooManyRings;
11-
use App\Realms\RolePlaying\Inventory\Problems\InventoryProblem;
12-
use App\Realms\RolePlaying\Inventory\Problems\NoDualWielding;
13-
use App\Realms\RolePlaying\Inventory\Problems\WeaponNotEquipped;
148
use loophp\collection\Collection;
159
use Stringable;
1610

1711
final class Character implements Stringable
1812
{
19-
/**
20-
* @throws InventoryProblem
21-
* @throws CannotWearTooManyRings
22-
* @throws WeaponNotEquipped
23-
* @throws CannotWearMultipleArmors
24-
* @throws NoDualWielding
25-
*/
2613
public static function of(string $name, int $hitPoints, Item ...$items): self
2714
{
2815
$items = Collection::fromIterable($items);
29-
30-
$countByType = static fn (ItemType $type) => $items
31-
->filter(static fn (Item $item) => $item->type->is($type))
32-
->count();
33-
34-
WeaponNotEquipped::whenNoWeapon($countByType(ItemType::Weapon));
35-
NoDualWielding::whenMoreThanOneWeapon($countByType(ItemType::Weapon));
36-
CannotWearMultipleArmors::whenMoreThanOneArmor($countByType(ItemType::Armor));
37-
CannotWearTooManyRings::whenMoreThanTwoRings($countByType(ItemType::Ring));
38-
3916
$armor = $items->reduce(static fn (int $sum, Item $item) => $sum + $item->armor, 0);
4017
$attack = $items->reduce(static fn (int $sum, Item $item) => $sum + $item->damage, 0);
4118

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Realms\RolePlaying;
6+
7+
use App\Realms\RolePlaying\Inventory\Item;
8+
use App\Realms\RolePlaying\Inventory\ItemType;
9+
use App\Realms\RolePlaying\Inventory\Problems\CannotWearMultipleArmors;
10+
use App\Realms\RolePlaying\Inventory\Problems\CannotWearTooManyRings;
11+
use App\Realms\RolePlaying\Inventory\Problems\NoDualWielding;
12+
use App\Realms\RolePlaying\Inventory\Problems\WeaponNotEquipped;
13+
use loophp\collection\Collection;
14+
15+
final class WarriorBuilder
16+
{
17+
private string $name = "player";
18+
private int $hitPoints = 100;
19+
private array $items = [];
20+
21+
public static function start(): self
22+
{
23+
return new self();
24+
}
25+
26+
public function withHitPoints(int $hitPoints): self
27+
{
28+
$this->hitPoints = $hitPoints;
29+
return $this;
30+
}
31+
32+
public function withName(string $name): self
33+
{
34+
$this->name = $name;
35+
return $this;
36+
}
37+
38+
public function withItems(Item ...$items): self
39+
{
40+
$this->items = array_merge($this->items, $items);
41+
return $this;
42+
}
43+
44+
/**
45+
* @throws WeaponNotEquipped
46+
* @throws NoDualWielding
47+
* @throws CannotWearMultipleArmors
48+
* @throws CannotWearTooManyRings
49+
*/
50+
public function build(): Character
51+
{
52+
$items = Collection::fromIterable($this->items);
53+
54+
$countByType = static fn (ItemType $type) => $items
55+
->filter(static fn (Item $item) => $item->type->is($type))
56+
->count();
57+
58+
WeaponNotEquipped::whenNoWeapon($countByType(ItemType::Weapon));
59+
NoDualWielding::whenMoreThanOneWeapon($countByType(ItemType::Weapon));
60+
CannotWearMultipleArmors::whenMoreThanOneArmor($countByType(ItemType::Armor));
61+
CannotWearTooManyRings::whenMoreThanTwoRings($countByType(ItemType::Ring));
62+
63+
return Character::of($this->name, $this->hitPoints, ...$this->items);
64+
}
65+
}

src/Solutions/Y2015/D21/RolePlayingGameSimulator.php

+8-7
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
use App\Aoc\Progress\Progress;
99
use App\Aoc\Runner\RunMode;
1010
use App\Aoc\Solution;
11-
use App\Realms\RolePlaying\Character;
1211
use App\Realms\RolePlaying\Inventory\Item;
1312
use App\Realms\RolePlaying\Inventory\ItemType;
13+
use App\Realms\RolePlaying\WarriorBuilder;
1414
use App\Solutions\Y2015\D21\Strategy\InventoriesSatisfyingRequirements;
1515
use App\Solutions\Y2015\D21\Strategy\ShoppingCart;
1616
use loophp\collection\Collection;
@@ -25,12 +25,13 @@ public function challenges(): iterable
2525

2626
public function solve(Challenge $challenge, mixed $input, RunMode $runMode): mixed
2727
{
28-
$boss = Character::of(
29-
'boss',
30-
$input->hitPoints,
31-
Item::of('boss weapon', damage: $input->damage, armor: 0, type: ItemType::Weapon),
32-
Item::of('boss armor', damage: 0, armor: $input->armor, type: ItemType::Armor),
33-
);
28+
$boss = WarriorBuilder::start()
29+
->withName('boss')
30+
->withHitPoints($input->hitPoints)
31+
->withItems(
32+
Item::of('boss item', $input->damage, $input->armor, ItemType::Weapon),
33+
)
34+
->build();
3435

3536
$positivePointsRequired = $boss->attack + $boss->armor;
3637

src/Solutions/Y2015/D22/Readme.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Oh boy!
2+
3+
https://ericlippert.com/2015/05/11/wizards-and-warriors-part-five/

tests/Realms/RolePlaying/CharacterMother.php

+10-9
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,19 @@ final class CharacterMother
1313
{
1414
public static function withItems(string $name, int $hitPoints, string ...$names): Character
1515
{
16-
$items = Collection::fromIterable(ItemsFactory::all())
16+
$stock = Collection::fromIterable(ItemsFactory::all())
1717
->map(static fn (ItemPrice $itemPrice) => [$itemPrice->item->name, $itemPrice->item])
1818
->unpack()
1919
->all(false);
2020

21-
return Character::of(
22-
$name,
23-
$hitPoints,
24-
...
25-
Collection::fromIterable($names)
26-
->map(static fn (string $name) => $items[$name] ?? NoItemByThatName::ofName($name))
27-
->all(),
28-
);
21+
$items = Collection::fromIterable($names)
22+
->map(static fn (string $name) => $stock[$name] ?? NoItemByThatName::ofName($name))
23+
->all();
24+
25+
return WarriorBuilder::start()
26+
->withName($name)
27+
->withHitPoints($hitPoints)
28+
->withItems(...$items)
29+
->build();
2930
}
3031
}

0 commit comments

Comments
 (0)