@startuml skinparam linetype ortho package viewer { class Viewer { final Game Viewer(List) void eventLoop(ApplicationContext) } class Main { static void main(String[]) } class StopWatich { Duration peek() } } package context { interface Updateable { Stream update(Context) } class Updateables { static Stream updateAll(Context, List) static Stream updateAll(Context, Updateable...) } class Context { Context(Game, List, GraphicsContext) Game getGame() List getEvents() GraphicsContext getGraphicsContext() Duration getTimeDelta() } class GraphicsContext { Graphics2D, ScreenInfo paintCircle(Color, Vec2, float) paintSquare(Color, Vec2, float, float) paintString(Color, Vec2,String) } class Game implements Updateable { Stage final List int indexBoard final List bool over Game(List) Stage getStage() bool isOver() Stream update(Context) } class Stage implements Updateable { Stage(Board) Board getBoard() List getBlocks() Stream update(Context) bool isCleared() } } package event { class Events { static Stream filter(List, Class) static Optional findFirst(List, Class) } interface Event interface GameEvent implements Event interface InputEvent implements Event class ConfirmOrder implements InputEvent class BombSetupOrder implements InputEvent class MoveRobotOrder implements InputEvent { MoveRobotEvent(TileVec2) TileVec2 getTarget() } class BombSetupEvent implements GameEvent { BombSetupEvent(TileVec2) TileVec2 getSource() } class BombExplosionEvent implements GameEvent { BombExplosionEvent(TileVec2) TileVec2 getSource() } class GameOverEvent implements GameEvent class BlockCreateEvent implements GameEvent class BlockDestroyEvent implements GameEvent } package board { class Board { Board(width, height) BlockType getBlockTypeAt(TileVec2) BlockType setBlockTypeAt(TileVec2, BlockType) Stream> stream() } class BoardParser { static Board parse(File) } class BoardValidator { static class Constraint BoardValidator(Board) BoardValidator validate(Predicate, String error) Board get() } class BoardConverter { static Board worldToBoard(List) static List boardToWorld(Board) } class TileVec2 { static final int TILE_DIM static TileVec2 fromVec2(Vec2) TileVec2(col, row) Vec2 toPixelPos() List neighbors() } class Matrix { static int getWidth(...) static int getHeight(...) static boolean isShapeValid(...) } class PathFinder { PathFinder(Board) List findPath(TileVec2 origin, TileVec2 target) } } package block { enum BlockType { FREE, WALL, TRASH, GARBAGE, ROBOT, BOMB boolean isBounding() boolean mustBeReachable() boolean isTraversable() boolean isMovableByExplosion() } class BlockFactory { Block build(BlockType, TileVec2) } abstract class Block implements Updateable { Block(BlockType) BlockType getType() TileVec2 getTile() abstract Vec2 getPos() abstract void link(World) } abstract class JBoxBlock extends Block { JBoxBlock(BlockType, BodyType, Shape, Vec2) Vec2 getPos() void link(World) void unlink(World) Stream streamContactEdges() } class RobotBlock extends Block { Vec2 getPos() void link(World world) Stream update(Context) } class WallBlock extends JBoxBlock { Stream update(Context) } class TrashBlock extends JBoxBlock { Stream update(Context) } class BombBlock extends JBoxBlock { Stream update(Context) } class GarbageBlock extends JBoxBlock { Stream update(Context) } } @enduml