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