---
# System prepended metadata

title: Saboteur Functional Domain Modeling
tags: [saboteur]

---

# 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
```
