DDDでポケモンバトルを実装する(Step3：ポケモンのバトルを実装する)

## はじめに
前回までの記事の続きとなります。今回はポケモンバトルを実装していきます。
Enitityを横断したドメインサービスの実装に入っていきます！！

https://qiita.com/koji0705/items/7029aa443a8966c9224e

:::note info
今回はポケモンバトルを実装しています。ポケモンや技等の横断したドメインサービス「バトル」を実装しています。
実装していく上で機能間の連動が複雑になり、開発生産性が低下します。機能間の連動をうまく解決できるようにするのがドメインサービスです。
:::


## 成果物

https://github.com/kouji0705/pokemon_ddd/pull/3

```shell:ディレクトリ構成
~/develop/pokemon_ddd (feat/step_pokemon_battle)$ tree src 
src
├── entities
│   ├── Move.ts
│   ├── Pokemon.test.ts
│   ├── Pokemon.ts
│   └── Stats.ts
├── enums
│   └── PokemonType.ts
├── index.ts
└── services
    └── Battle.ts　←今回はここを実装していきます。

4 directories, 7 files
```


```ts:src/services/Battle.ts
import { Pokemon } from "@entities/Pokemon";
import { Move } from "@entities/Move";

export class Battle {
	constructor(
		private pokemon1: Pokemon,
		private pokemon2: Pokemon,
	) {}

	// ダメージを計算するメソッド
	private calculateDamage(attacker: Pokemon, move: Move): number {
		return move.power;
	}

	// 攻撃を実行するメソッド
	private performMove(attacker: Pokemon, defender: Pokemon, move: Move): void {
		const damage = this.calculateDamage(attacker, move);
		defender.receiveDamage(damage);
		console.log(
			`${attacker.name} used ${move.name}. It dealt ${damage} damage.`,
		);
	}

	public battleTurn(): void {
		// ポケモン1の攻撃
		const move1 = this.pokemon1.getMoves()[0];
		console.log("=======HIT8 move1: ", move1);
		this.performMove(this.pokemon1, this.pokemon2, move1);

		// 勝敗のチェック
		if (this.pokemon2.getStats().hp <= 0) {
			console.log(`${this.pokemon1.name} wins!`);
			return;
		}
		console.log(
			"=======HIT8 this.pokemon2.getStats().hp: ",
			this.pokemon2.getStats().hp,
		);

		// ポケモン2の攻撃
		const move2 = this.pokemon2.getMoves()[0];
		console.log("=======HIT8 move2: ", move2);
		this.performMove(this.pokemon2, this.pokemon1, move2);

		// 勝敗のチェック
		if (this.pokemon1.getStats().hp <= 0) {
			console.log(`${this.pokemon2.name} wins!`);
			return;
		}
		console.log(
			"=======HIT8 this.pokemon1.getStats().hp: ",
			this.pokemon1.getStats().hp,
		);
	}
}
```

:::note info
ドメインサービスは、複数のエンティティや値オブジェクトにまたがるビジネスロジックを実装します。
:::


```ts:index.ts
import { Pokemon } from "@entities/Pokemon";
import { PokemonType } from "@enums/PokemonType";
import { Stats } from "@entities/Stats";
import { Move } from "@entities/Move";
import { Battle } from "@services/Battle"; // サービスのインポートパスを修正

const pikachuStats: Stats = { hp: 100, attack: 55, defense: 40, speed: 90 };
const bulbasaurStats: Stats = { hp: 100, attack: 49, defense: 49, speed: 45 };

const thunderbolt: Move = {
	name: "Thunderbolt",
	type: PokemonType.Electric,
	power: 90,
};
const tackle: Move = { name: "Tackle", type: PokemonType.Normal, power: 40 };

const pikachu = new Pokemon(
	25,
	"Pikachu",
	[PokemonType.Electric],
	pikachuStats,
	[thunderbolt],
);
const bulbasaur = new Pokemon(
	1,
	"Bulbasaur",
	[PokemonType.Grass, PokemonType.Poison],
	bulbasaurStats,
	[tackle],
);

const battle = new Battle(pikachu, bulbasaur);

// バトルを実行
battle.battleTurn();
battle.battleTurn();
```

## 実行結果

```shell:実行結果
~/develop/pokemon_ddd (feat/step_pokemon_battle)$ yarn run exec
yarn run v1.22.19
$ ts-node -r tsconfig-paths/register src/index.ts
=======HIT8 move1:  { name: 'Thunderbolt', type: 'Electric', power: 90 }
Pikachu used Thunderbolt. It dealt 90 damage.
=======HIT8 this.pokemon2.getStats().hp:  10
=======HIT8 move2:  { name: 'Tackle', type: 'Normal', power: 40 }
Bulbasaur used Tackle. It dealt 40 damage.
=======HIT8 this.pokemon1.getStats().hp:  60
=======HIT8 move1:  { name: 'Thunderbolt', type: 'Electric', power: 90 }
Pikachu used Thunderbolt. It dealt 90 damage.
Pikachu wins!
✨  Done in 1.21s.
```