# Saboteur Functional Domain Modeling
###### tags: `saboteur`
## Reference
[figjam](https://www.figma.com/file/tENh3ZEizbshNvR0KrGtzf/Saboteur-Domain-Modeling?type=whiteboard&node-id=0%3A1&t=5Ta3mFrl7NHxpvuN-1)
[type](https://hackmd.io/@YM0fzpcaQUe5gSGCway3_Q/HJyRNiuUn)
## Context: place path card
### Workflow: place path card
```
workflow: place path card
input:
event source
place path card command
output:
async result of
ok -> path card has been placed event
err -> place path card error
step:
get current placements
check if position has been placed
check if position is connected
append event to event source
return path card has been placed event
```
#### Substep: aggregate all events to get current placements
```
substep: aggregate all events to get current placements
input:
list of events
output:
current placements
step:
aggregate current placement by
match event:
is placement has been placed event ->
concate event data to current placements
return current placements
```
### Workflow: check position has been placed
```
workflow: check position has been placed
input:
current placements
place path card command
output:
result of
ok -> place path card command
err -> position has been placed error
step:
if current placements includes placement in command then:
return position has been placed error
return place path card command
```
### Workflow: check position is connected
```
workflow: check position is connected
input:
current placements
place path card command
output:
result of
ok -> place path card command
err -> placement can not connected error
step:
check if card not need to check then:
return place path card command
check if placement can not connect from start then:
return placement can not connect from start error
check if placement can not fit neighbors then:
return placement can not fit neighbors error
return place path card command
```
## Context: update board
### Workflow: get current placements
```
workflow: get current placements
input:
event source
output:
async result of
ok -> current placements
err -> get current placements error
step:
read all events from event source,
if any error occured then:
return event source read error
aggregate all events to get current placements
return current placements
```
## Context: action card
### Workflow: place broken tool
```
workflow: place broken tool
input:
event source
broken tool command
output:
async result of
ok -> broken tool has been placed event
err -> place broken tool error
step:
get tools has been broken on player
check if tool has been broken on player then:
return tool has broken error
append event to event source
return broken tool has been placed event
```
### Workflow: get tools has broken on player
```
workflow: get tools has been broken on player
input:
event source
player id
output:
async result of
ok -> tools
err -> event source read error
step:
read all events from event source,
if error occured then:
return event source read error
aggregate all events to get tools has been broken on player
return tools has broken
```
### Workflow: check tools has broken
```
workflow: check tools has broken
input:
tools has broken
broken tool command
output:
result of
ok -> broken tool command
err -> tool has been broken error
step:
if tools has broken includes tool in command then:
return tool has been broken error
return broken tool command
```
### Workflow: remove broken tool
```
workflow: remove broken tool
input:
event source
fix tool command
output:
async result of
ok -> broken tool has been removed event
err -> remove broken tool error
step:
get tools has been broken on player
check if tool has not been broken on player then:
append event to event source
return broken tool has been removed event
return remove broken tool error
```
### Workflow: reveal goal
```
workflow: reveal goal
input:
event source
map command
output:
async result of
ok -> goal card has been reveal event
err -> goal card not found error
step:
if position not match goal positions:
return goal card not found error
read all event from event source,
if error occured then:
return event source read error
append event to event source
return goal card has been reveal event
```
### Workflow: remove path card
```
workflow: remove path card
input:
event source
rockfall command
output:
async result of
ok -> path card has been removed event
err -> remove path card error
step:
get current placements
if position has not been placed then:
return target can not be removed error
append event to event source
return path card has been removed event
```
### Workflow: pass
```
workflow: pass
input:
event source
output:
async result of
ok -> turn has been passed event
err -> pass error
step:
append event to event source
return turn has been passed event
```
### Workflow: draw
```ts
type DrawCommand = {
playerId: string
}
```
```ts
type DrawEvent = {
playerId: string;
card: HandCard;
}
```
```ts
type DrawCardError = Error & {
name: 'DrawCardError'
message: 'The deck is empty and there are no more cards to draw'
}
type DrawError =
| DrawCardError
| EventSourceReadError
| EventSourceWriteError
```
```ts
type Draw = (eventsource: EventSource, command: DrawCommand) => ResultAsync<DrawEvent, DrawError>
```
```yaml
workflow: draw
input:
event source
draw command
output:
async result of
ok -> player has draw event
err -> draw error
step:
read all events from event source
if error occured:
return event source read error
aggregate all events to get deck
if deck is empty:
return draw card error
draw a card randomly from the deck
append event to event source
if error occured:
return event source write error
otherwise:
return player has draw event
```
### Workflow: flip goal
```yaml
workflow: flip goal
input:
output:
step:
```
### Worlflow: claim victory
```yaml
workflow: claim victory
input:
output:
step:
```
### Workflow: settlement
```yaml
workflow: settlement
input:
output:
step:
```
### Workflow: game over
```yaml
workflow: game over
input:
event source
game over command
output:
async result of
ok -> game over
err -> game over error
step:
- Check if the game has reached the end condition
- If the game reaches the end condition:
if Dig to Treasure Card : return good guy wins
if Successfully stopped by saboteurs : return saboteurs wins
if All players cannot act : return Declare the game a draw
- otherwise:
- Return to game to continue
```
### Workflow: create room
```ts
type CreateRoomCommand = {
playerId: string;
}
```
```ts
type CreateRoomEvent = {
playerId: string;
roomId: string;
}
```
```ts
type CreateRoomError = EventSourceWriteError
```
```ts
type CreateRoom = (eventsource: EventSource, command: CreateRoomCommand) => ResultAsync<CreateRoomEvent, CreateRoomError>
```
```yaml
workflow: create room
input:
event source
create room command
output:
async result of
ok -> create room event
err -> create room error
step:
append event to event source
if error occured:
return event source write error
otherwise:
return create room event
```
### Workflow: join room
```ts
type JoinRoomCommand = {
playerId: string;
roomId: string;
}
```
```ts
type JoinRoomEvent = {
playerId: string;
roomId: string;
}
```
```ts
type PlayerCountError = Error & {
name: 'PlayerCountError'
message: "Not meeting the game's player count requirement"
}
type JoinRoomError =
| PlayerCountError
| EventSourceReadError
| EventSourceWriteError
```
```ts
type GameRoom = {
playerIds: string[];
roomId: string;
status: 'wait for join' | 'game started';
};
```
```ts
type JoinRoom = (eventsource: EventSource, command: JoinRoomCommand) => ResultAsync<JoinRoomEvent, JoinRoomError>
```
```yaml
workflow: join room
input:
event source
join room command
output:
async result of
ok -> game room
err -> join room error
step:
read all events from event source
if error occured:
return event source read error
check player count meets game requirement
if player count exceeds or falls below the game:
return player count error
append event to event source
if error occured:
return event source write error
otherwise:
return game room
```
### Workflow: game start
```yaml
workflow: game start
input:
output:
step:
```
### Workflow: assign role
```ts
type AssignRoleCommand = {
playerId: string;
role: RoleCard;
}
```
```ts
type AssignRoleEvent = {
playerId: string;
role: RoleCard;
}
```
```ts
type AssignRoleError = EventSourceWriteError
```
```ts
type AssignRole = (eventsource: EventSource, command: AssignRoleCommand) => ResultAsync<AssignRoleEvent, AssignRoleError>
```
```yaml
workflow: assign role
input:
event source
assign role command
output:
async result of
ok -> player assign role event
err -> assign role error
step:
append event to event source
if error occured:
return event source write error
otherwise:
return assign role event
```
### Workflow: game prepare
```yaml
workflow: game prepare
input:
output:
step:
```
### Workflow: turn start
```ts
type TurnStartCommand = {
playerId: string;
}
```
```ts
type TurnStartEvent = {
playerId: string;
}
```
```ts
type TurnStartError = EventSourceWriteError
```
```ts
type TurnStart = (eventsource: EventSource, command: TurnStartCommand) => ResultAsync<TurnStartEvent, TurnStartError>
```
```yaml
workflow: turn start
input:
event source
turn start command
output:
async result of
ok -> turn start event
err -> turn start error
step:
append event to event source
if error occured:
return event source write error
otherwise:
return turn start event
```