@startuml !include style.ipuml ' !include hide-groups.ipuml ' !include hide-details.ipuml class main as "main()" hide main circle hide main members exception Exception { + Exception(const char* fmt, ...) + what() : const char* -- # error : char* # va_format(va_list args, const char* fmt) } rectangle Group_FileReading as "File reading" <> { class FileReaderFactory <> { + create(url : const string &) : uniq } interface FileReader { # FileReader(url : const string &) + ~FileReader() -- # open() + read() : const string + close() -- # url : const string } class LocalFileReader { + ~LocalFileReader() } class HTTPFileReader { } package CPR { } FileReader <|.d. LocalFileReader FileReader <|.d. HTTPFileReader FileReaderFactory -u-> LocalFileReader FileReaderFactory -u-> HTTPFileReader HTTPFileReader -l> CPR ' LAYOUT HTTPFileReader -r[hidden] LocalFileReader } rectangle Group_ParsingDeserialization as "Parsing & deserialization" <> { class ParserFactory <> { + ParserFactory() + get_parser(FileReader &) : Parser & -- - parsers : vec> } interface Parser { + parse(FileReader &, MuseumDeserializer &) + heuristic(FileReader &) : unsigned int -- # set_file(FileReader &) # get_file() : FileReader & -- file : FileReader * } class XMLParser class TXTParser class CSVParser package pugixml { } Parser <|.d. XMLParser Parser <|.d. TXTParser Parser <|.d. CSVParser ParserFactory -u-> XMLParser ParserFactory -u-> TXTParser ParserFactory -u-> CSVParser XMLParser -r> pugixml class MuseumDeserializer { + MuseumDeserializer(Museum &) -- + set_canvas(CanvasData) + set_tile(TileData) + add_artist(ArtistData) + add_type(type : string, Color, weight : unsigned int) } Parser .> MuseumDeserializer ' LAYOUT CSVParser -r[hidden] TXTParser TXTParser -r[hidden] XMLParser } rectangle Group_Collisions as "Collisions" <> { class CollisionContext { + CollisionContext(Museum &) + update() -- + get_checker() : shared + cycle_method() - checker : shared - create_checker() : shared - checker_index : size_t -- - museum : Museum & } abstract class CollisionChecker { + CollisionChecker(Museum &) + check() <> -- + compare(Artist & a, Artist & b) -- # museum : Museum & } class QuadTreeCollisionChecker { + constructor(Museum &) - constructor(parent : this, boundary : const Rectangle &) -- + get_boundary() : const Rectangle & + subtree : uniq[4] + check() -- - capacity : const int - artists : forward_list - artists_size : size_t - boundary : Rectangle <<+get>> -- - subdivide() - cull() } class NaiveCollisionChecker { + check() } class NullCollisionChecker { + check() } CollisionChecker <|-- QuadTreeCollisionChecker CollisionChecker <|-- NaiveCollisionChecker CollisionChecker <|-- NullCollisionChecker CollisionContext -> CollisionChecker } rectangle Group_Pathfinding as "Pathfinding" <> { class PathfindingContext { + PathfindingContext(Museum &) + update() -- - start_point : XY <<+get>> <<+set>> - end_point : XY <<+get>> <<+set>> + empty_point(const XY &) : bool -- + register_weight(type : const string &, weight : unsigned int) + get_weight(type : const string &) : unsigned int - weight_map : map -- + get_solver() : Pathfinder & + cycle_solver() - solvers : vec> - solver_index : size_t -- + has_collision : bool -- - museum : Museum & } abstract class Pathfinder { + Pathfinder(Museum &) + find_between(const XY &, const XY &) < -- + is_visited(const XY &) : bool + is_solution(const XY &) : bool + is_solved() : bool + get_solution() : const forward_list & -- # clear() # set_visited(const XY &) # set_solved(const forward_list &) -- - visited : vec - solution : vec - path : forward_list - solved : bool -- # museum : Museum & } class BreadthFirstPathfinder { + find_between(const XY &, const XY &) -- - find_step(const vec> &) : vec> - end : XY } class DijkstraPathfinder { + find_between(const XY &, const XY &) -- # clear() - end : XY - map_get(const XY &) : Node & - map : unordered_map - dijkstra(const XY &) } Pathfinder <|-- BreadthFirstPathfinder Pathfinder <|-- DijkstraPathfinder PathfindingContext -> Pathfinder } rectangle Group_Model as "Model" <> { class Museum { + people : People + canvas : Canvas + collision : CollisionContext + pathfinding : PathfindingContext -- + paused : bool + update() + skip_forward() + skip_backward() -- - jump : unsigned long -- - working : bool - worker : thread * - work() } together { class Canvas { + Canvas(Museum &) -- + get_tile(XY) : Tile & + set_tile(TileData) -- + update() + data : CanvasData + set_data(CanvasData) -- + tile_color : TileColorFactory + tile_behavior : TileBehaviorFactory -- - tiles : vector - museum : Museum & } struct CanvasData { + rows : unsigned int + columns : unsigned int } class People { + People(Museum &) + update(tick : bool) -- + add_artist(ArtistData) + remove_artist(Artist &) + get_artists() : forward_list -- - artists : forward_list - artist_count : size_t - museum : Museum & } interface Memento { } People -r[hidden] Canvas } together { class Tile { + data : TileData + color : Color + behavior : uniq + set_data(TileData &) + set_type(type : const string &) + update() + get_neighbor(XY) : Tile * -- - museum : Museum & } struct TileData { + x : unsigned int + y : unsigned int + type : string } class Artist { + update(tick : bool) + step : bool + color : Color + data : ArtistData -- - data : ArtistData - museum : Museum & } struct ArtistData { + x : float + y : float + vx : float + vy : float } class TileColorFactory <> { + get_color(string) : Color <> + register_color(string, Color) <> } class TileBehaviorFactory <> { + TileBehaviorFactory(Museum &) + create(string) : uniq -- - museum : Museum & } } struct Color { red : unsigned int green : unsigned int blue : unsigned int } together { interface TileBehavior { + step(Artist *) + update(Tile &) -- # TileBehavior(Museum &) -- # interactions : unsigned int # museum : Museum & } class NullTileBehavior { - type = "" <> } class StepTileBehavior { - type = "G" : <> } class DeleteArtistTileBehavior { - type = "R" : <> } class SetNeighborTileBehavior { - type = "B" : <> -- - dx : int - dy : int } class CreateArtistTileBehavior { - type = "Y" : <> -- - last_interactions : unsigned int } NullTileBehavior -d[hidden]- StepTileBehavior StepTileBehavior -d[hidden]- DeleteArtistTileBehavior DeleteArtistTileBehavior -d[hidden]- SetNeighborTileBehavior SetNeighborTileBehavior -d[hidden]- CreateArtistTileBehavior } Canvas -l[hidden] People Museum --> People Museum --> Canvas Canvas --> Tile Canvas --> TileColorFactory Canvas --> TileBehaviorFactory People --> Artist Tile -> TileData Artist -l> ArtistData Canvas -> CanvasData Tile --> "state" Color Tile .> TileColorFactory TileColorFactory -> Color TileBehavior <|.. NullTileBehavior TileBehavior <|.. StepTileBehavior TileBehavior <|.. DeleteArtistTileBehavior TileBehavior <|.. SetNeighborTileBehavior TileBehavior <|.. CreateArtistTileBehavior TileBehaviorFactory --> NullTileBehavior TileBehaviorFactory --> StepTileBehavior TileBehaviorFactory --> DeleteArtistTileBehavior TileBehaviorFactory --> SetNeighborTileBehavior TileBehaviorFactory --> CreateArtistTileBehavior Tile --> "state" TileBehavior Tile .[norank].> TileBehaviorFactory Memento <|.[norank]. TileData Memento <|.[norank]. ArtistData Memento <|.[norank]. CanvasData ' LAYOUT Artist -r[hidden] Tile } together { /' LAYOUT '/ rectangle Group_Visualization as "Visualization" <> { struct Rectangle { x : unsigned int y : unsigned int width : unsigned int height : unsigned int } enum MouseCode { } enum KeyboardCode { } package SDL3 { } class View { + window_size(width, height) + dialog_file(callback : fn(files : vec, data), data) + draw_rect(Rectangle, Color) -- - window : SDL_Window * - renderer : SDL_Renderer * -- + open : bool - worker : thread * - work() } class ViewController { + update() + ev_keydown(KeyboardCode) + ev_mousedown(MouseCode) + ev_mousemove(x, y) -- - draw_artists : bool <<+get>> <<+set>> } ViewController ..> View ViewController <-- View View --> SDL3 View .l> Rectangle ViewController .l> KeyboardCode ViewController .l> MouseCode } rectangle Group_Commands as "Commands" <> { interface Command { + execute() } class ToggleMuseumPauseCommand { + constructor(Museum &) + constructor(Museum &, set : bool) } class OpenFileGUICommand { + constructor(Museum &, View &) -- - museum : Museum & - view : View & } class LoadFilesCommand { + constructor(Museum &, files : vec) + constructor(Museum &, argc, argv) -- - load_files() - museum : Museum & - files : vec } class StepTileCommand { + constructor(Canvas &, const XY &) -- - canvas : Canvas & - tile_pos : XY } class TimeTravelCommand { + constructor(Museum &, forwards : bool) -- - museum : Museum & - forwards : bool } class ControlBooleanCommand { + constructor(target : bool &) + constructor(target : bool &, set : bool) -- - toggle : bool - value : bool - target : bool & } class CycleCollisionMethodCommand { + constructor(Museum &) } class ToggleArtistPathCollisionCommand { + constructor(Museum &) } class SetPathfindingStartPointCommand { + constructor(Museum &) - museum : Museum & - point : XY } class SetPathfindingEndPointCommand { + constructor(Museum &) - museum : Museum & - point : XY } Command <|-d- StepTileCommand Command <|-d- LoadFilesCommand Command <|-d- TimeTravelCommand Command <|-d- CycleCollisionMethodCommand Command <|-u- OpenFileGUICommand Command <|-u- ControlBooleanCommand Command <|-u- SetPathfindingStartPointCommand Command <|-u- SetPathfindingEndPointCommand ControlBooleanCommand <|-u- ToggleMuseumPauseCommand ControlBooleanCommand <|-u- ToggleArtistPathCollisionCommand } } /' LAYOUT '/ Parser .l> FileReader ' Parser -l> FileReaderFactory MuseumDeserializer .l> Museum Museum --> PathfindingContext Museum --> CollisionContext ViewController -[norank]> Command main -d-> Museum main -u-> LoadFilesCommand ' main -[norank]> MuseumDeserializer main -[norank]> View main .r> Exception @enduml