-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathOthello.php
97 lines (82 loc) · 2.45 KB
/
Othello.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<?php
namespace Packages\Models\Othello\Othello;
use Illuminate\Support\Str;
use Packages\Exceptions\DomainException;
use Packages\Models\Othello\Action\Action;
use Packages\Models\Othello\Action\ActionType;
class Othello
{
private function __construct(
public readonly string $id,
private Status $status,
private Turn $turn,
) {
if (!Str::isUuid($id)) throw new DomainException();
}
public static function init(): Othello
{
return new self(
id: Str::uuid(),
status: Status::PLAYING,
turn: Turn::init(),
);
}
public static function make(string $id, Status $status, Turn $turn): self
{
return new self(
id: $id,
status: $status,
turn: $turn,
);
}
/**
* ゲームの状態更新
*/
public function apply(Action $action): void
{
// プレー中ではない場合
if ($this->status !== Status::PLAYING) throw new DomainException();
$turnBefore = $this->turn;
// ターンを更新する
$this->turn = match ($action->actionType) {
ActionType::SET_STONE => $this->turn->advance($action->data),
ActionType::CONFIRM_SKIP => $this->turn->skip(),
};
$this->status = $this->nextStatus($turnBefore, $this->turn);
}
private function nextStatus(Turn $turnBefore, Turn $turnAfter): Status
{
if ($turnAfter->isLast()) return $this->status = Status::RESULTED;
if (self::mustInterrupt($turnBefore, $turnAfter)) return $this->status = Status::INTERRUPTED;
return Status::PLAYING;
}
private static function mustInterrupt(Turn $turnBefore, Turn $turnAfter)
{
return $turnBefore->mustSkip() && $turnAfter->mustSkip();
}
/**
* ゲームが終了しているか判定する
* 正常終了、スキップによる異常終了なのかは問わない
*
* @return bool
*/
public function isOver(): bool
{
// ターンが進行不可(正常系)、もしくはスキップが連続してどちらも置く場所がなくなった(異常系)場合、終了
return !$this->turn->isLast();
}
/**
* @return Status
*/
public function getStatus(): Status
{
return $this->status;
}
/**
* @return Turn
*/
public function getTurn(): Turn
{
return $this->turn;
}
}