@startuml skinparam linetype ortho package utils { class Matrix { static int getWidth(...) static int getHeight(...) static boolean isShapeValid(...) } } package viewer { class Viewer { final Game Viewer(List) void main(String[]) void eventLoop(ApplicationContext) void renderFrame(Graphics2D,ApplicationContext,List) } } package context { class Context { Context(Game,List,GraphicsContext) final Game final List final GraphicsContext Game getGame() List getEvents() GraphicsContext getGraphicsContext() } class GraphicsContext { final Graphics2D final ScreenInfo paintCircle(Color, Vec2, float) paintSquare(Color, Vec2, float, float) } class InputHandler { private final ApplicationContext InputHandler(ApplicationContext) List getEvents() } class ScreenManager { private final ApplicationContext private final Graphics2D ScreenManager(ApplicationContext,Graphics2D) GraphicsContext clearScreen() } class Game { Stage final List int indexBoard final List bool over Game(List) Stage getStage() bool isOver() void setOver() void nextStage() void retryStage() List update(Context context) } } package event { interface Event interface InputEvent implements Event interface GameEvent implements Event class DropBombEvent implements InputEvent class AddBombEvent implements InputEvent { final TileVec2 AddBombEvent(TileVec2) TileVec2 getTile() } class MoveRobotEvent implements InputEvent { final TileVec2 MoveRobotEvent(TileVec2) TileVec2 getTile() } class ConfirmEvent implements InputEvent class GameOverEvent implements Event class ExplosionEvent implements GameEvent { Block source Body source } } 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 Board 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) Vec2 TileVec2(col, row) Vec2 toPixelPos() List neighbors() } class PathFinder { Graph 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 { BlockType List Vec2 Block(BlockType, List, Vec2) void setPos(Vec2) BlockType getBlockType() Vec2 getPos() TileVec2 getTile() List update(Context) } class WallBlock extends Block class TrashBlock extends Block class BombBlock extends Block class GarbageBlock extends Block class RobotBlock extends Block class Stage { List Board Stage(Board) List getBlocks() List update(Context) bool isCleared() } } package controller { interface Controller { List update(Context) } abstract class BlockController implements Controller { Block Controller(Block) } class BlockControllerFactory { BlockController build(Block) } class GameController implements Controller abstract class PhysicsController extends BlockController abstract class DisplayController extends BlockController class WallPhysicsController extends PhysicsController class WallDisplayController extends DisplayController class TrashPhysicsController extends PhysicsController class TrashDisplayController extends DisplayController class GarbagePhysicsController extends PhysicsController class GarbageDisplayController extends DisplayController class RobotPhysicsController extends PhysicsController { List path } class RobotDisplayController extends DisplayController class BombPhysicsController extends PhysicsController class BombDisplayController extends DisplayController } RobotPhysicsController --> PathFinder RobotPhysicsController --> BoardConverter Stage --> BoardConverter PhysicsController --() JBox2D Zen5 ()-- Viewer viewer --> context viewer --> model context --> event model --> controller board --> model @enduml