From a8b2598b57ef8ce735c36e2d4da1752ba631a528 Mon Sep 17 00:00:00 2001 From: vdrnvdrn Date: Wed, 25 Oct 2023 17:34:42 +0500 Subject: [PATCH 1/5] done --- robots/src/gui/GameVisualizer.java | 210 ---------------- robots/src/gui/GameWindow.java | 20 -- robots/src/gui/MainApplicationFrame.java | 156 ------------ robots/src/gui/RobotsProgram.java | 25 -- robots/src/log/LogChangeListener.java | 6 - robots/src/log/LogWindowSource.java | 89 ------- robots/src/main/java/gui/GameVisualizer.java | 87 +++++++ robots/src/main/java/gui/GameWindow.java | 23 ++ robots/src/{ => main/java}/gui/LogWindow.java | 33 +-- .../main/java/gui/MainApplicationFrame.java | 100 ++++++++ robots/src/main/java/gui/PositionWindow.java | 45 ++++ robots/src/main/java/gui/RobotsProgram.java | 40 +++ robots/src/main/java/gui/Translatable.java | 7 + .../src/main/java/log/LogChangeListener.java | 6 + robots/src/{ => main/java}/log/LogEntry.java | 11 +- robots/src/{ => main/java}/log/LogLevel.java | 8 +- robots/src/main/java/log/LogWindowSource.java | 65 +++++ robots/src/{ => main/java}/log/Logger.java | 6 +- robots/src/main/java/model/Entity.java | 12 + robots/src/main/java/model/Model.java | 66 +++++ robots/src/main/java/model/Robot.java | 234 ++++++++++++++++++ robots/src/main/java/model/RobotModel.java | 64 +++++ robots/src/main/java/model/Target.java | 46 ++++ robots/src/main/java/model/TargetModel.java | 21 ++ robots/src/main/java/model/TypeRobot.java | 27 ++ robots/src/main/java/tools/DrawTools.java | 13 + robots/src/main/java/tools/MathTools.java | 36 +++ robots/src/main/java/view/GameDrawer.java | 20 ++ robots/src/main/java/view/GameView.java | 47 ++++ robots/src/main/java/view/RobotDrawer.java | 55 ++++ robots/src/main/java/view/TargetDrawer.java | 22 ++ robots/src/main/java/view/ViewModel.java | 76 ++++++ 32 files changed, 1141 insertions(+), 535 deletions(-) delete mode 100644 robots/src/gui/GameVisualizer.java delete mode 100644 robots/src/gui/GameWindow.java delete mode 100644 robots/src/gui/MainApplicationFrame.java delete mode 100644 robots/src/gui/RobotsProgram.java delete mode 100644 robots/src/log/LogChangeListener.java delete mode 100644 robots/src/log/LogWindowSource.java create mode 100644 robots/src/main/java/gui/GameVisualizer.java create mode 100644 robots/src/main/java/gui/GameWindow.java rename robots/src/{ => main/java}/gui/LogWindow.java (67%) create mode 100644 robots/src/main/java/gui/MainApplicationFrame.java create mode 100644 robots/src/main/java/gui/PositionWindow.java create mode 100644 robots/src/main/java/gui/RobotsProgram.java create mode 100644 robots/src/main/java/gui/Translatable.java create mode 100644 robots/src/main/java/log/LogChangeListener.java rename robots/src/{ => main/java}/log/LogEntry.java (92%) rename robots/src/{ => main/java}/log/LogLevel.java (90%) create mode 100644 robots/src/main/java/log/LogWindowSource.java rename robots/src/{ => main/java}/log/Logger.java (95%) create mode 100644 robots/src/main/java/model/Entity.java create mode 100644 robots/src/main/java/model/Model.java create mode 100644 robots/src/main/java/model/Robot.java create mode 100644 robots/src/main/java/model/RobotModel.java create mode 100644 robots/src/main/java/model/Target.java create mode 100644 robots/src/main/java/model/TargetModel.java create mode 100644 robots/src/main/java/model/TypeRobot.java create mode 100644 robots/src/main/java/tools/DrawTools.java create mode 100644 robots/src/main/java/tools/MathTools.java create mode 100644 robots/src/main/java/view/GameDrawer.java create mode 100644 robots/src/main/java/view/GameView.java create mode 100644 robots/src/main/java/view/RobotDrawer.java create mode 100644 robots/src/main/java/view/TargetDrawer.java create mode 100644 robots/src/main/java/view/ViewModel.java diff --git a/robots/src/gui/GameVisualizer.java b/robots/src/gui/GameVisualizer.java deleted file mode 100644 index f82cfd8f8..000000000 --- a/robots/src/gui/GameVisualizer.java +++ /dev/null @@ -1,210 +0,0 @@ -package gui; - -import java.awt.Color; -import java.awt.EventQueue; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.util.Timer; -import java.util.TimerTask; - -import javax.swing.JPanel; - -public class GameVisualizer extends JPanel -{ - private final Timer m_timer = initTimer(); - - private static Timer initTimer() - { - Timer timer = new Timer("events generator", true); - return timer; - } - - private volatile double m_robotPositionX = 100; - private volatile double m_robotPositionY = 100; - private volatile double m_robotDirection = 0; - - private volatile int m_targetPositionX = 150; - private volatile int m_targetPositionY = 100; - - private static final double maxVelocity = 0.1; - private static final double maxAngularVelocity = 0.001; - - public GameVisualizer() - { - m_timer.schedule(new TimerTask() - { - @Override - public void run() - { - onRedrawEvent(); - } - }, 0, 50); - m_timer.schedule(new TimerTask() - { - @Override - public void run() - { - onModelUpdateEvent(); - } - }, 0, 10); - addMouseListener(new MouseAdapter() - { - @Override - public void mouseClicked(MouseEvent e) - { - setTargetPosition(e.getPoint()); - repaint(); - } - }); - setDoubleBuffered(true); - } - - protected void setTargetPosition(Point p) - { - m_targetPositionX = p.x; - m_targetPositionY = p.y; - } - - protected void onRedrawEvent() - { - EventQueue.invokeLater(this::repaint); - } - - private static double distance(double x1, double y1, double x2, double y2) - { - double diffX = x1 - x2; - double diffY = y1 - y2; - return Math.sqrt(diffX * diffX + diffY * diffY); - } - - private static double angleTo(double fromX, double fromY, double toX, double toY) - { - double diffX = toX - fromX; - double diffY = toY - fromY; - - return asNormalizedRadians(Math.atan2(diffY, diffX)); - } - - protected void onModelUpdateEvent() - { - double distance = distance(m_targetPositionX, m_targetPositionY, - m_robotPositionX, m_robotPositionY); - if (distance < 0.5) - { - return; - } - double velocity = maxVelocity; - double angleToTarget = angleTo(m_robotPositionX, m_robotPositionY, m_targetPositionX, m_targetPositionY); - double angularVelocity = 0; - if (angleToTarget > m_robotDirection) - { - angularVelocity = maxAngularVelocity; - } - if (angleToTarget < m_robotDirection) - { - angularVelocity = -maxAngularVelocity; - } - - moveRobot(velocity, angularVelocity, 10); - } - - private static double applyLimits(double value, double min, double max) - { - if (value < min) - return min; - if (value > max) - return max; - return value; - } - - private void moveRobot(double velocity, double angularVelocity, double duration) - { - velocity = applyLimits(velocity, 0, maxVelocity); - angularVelocity = applyLimits(angularVelocity, -maxAngularVelocity, maxAngularVelocity); - double newX = m_robotPositionX + velocity / angularVelocity * - (Math.sin(m_robotDirection + angularVelocity * duration) - - Math.sin(m_robotDirection)); - if (!Double.isFinite(newX)) - { - newX = m_robotPositionX + velocity * duration * Math.cos(m_robotDirection); - } - double newY = m_robotPositionY - velocity / angularVelocity * - (Math.cos(m_robotDirection + angularVelocity * duration) - - Math.cos(m_robotDirection)); - if (!Double.isFinite(newY)) - { - newY = m_robotPositionY + velocity * duration * Math.sin(m_robotDirection); - } - m_robotPositionX = newX; - m_robotPositionY = newY; - double newDirection = asNormalizedRadians(m_robotDirection + angularVelocity * duration); - m_robotDirection = newDirection; - } - - private static double asNormalizedRadians(double angle) - { - while (angle < 0) - { - angle += 2*Math.PI; - } - while (angle >= 2*Math.PI) - { - angle -= 2*Math.PI; - } - return angle; - } - - private static int round(double value) - { - return (int)(value + 0.5); - } - - @Override - public void paint(Graphics g) - { - super.paint(g); - Graphics2D g2d = (Graphics2D)g; - drawRobot(g2d, round(m_robotPositionX), round(m_robotPositionY), m_robotDirection); - drawTarget(g2d, m_targetPositionX, m_targetPositionY); - } - - private static void fillOval(Graphics g, int centerX, int centerY, int diam1, int diam2) - { - g.fillOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, diam2); - } - - private static void drawOval(Graphics g, int centerX, int centerY, int diam1, int diam2) - { - g.drawOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, diam2); - } - - private void drawRobot(Graphics2D g, int x, int y, double direction) - { - int robotCenterX = round(m_robotPositionX); - int robotCenterY = round(m_robotPositionY); - AffineTransform t = AffineTransform.getRotateInstance(direction, robotCenterX, robotCenterY); - g.setTransform(t); - g.setColor(Color.MAGENTA); - fillOval(g, robotCenterX, robotCenterY, 30, 10); - g.setColor(Color.BLACK); - drawOval(g, robotCenterX, robotCenterY, 30, 10); - g.setColor(Color.WHITE); - fillOval(g, robotCenterX + 10, robotCenterY, 5, 5); - g.setColor(Color.BLACK); - drawOval(g, robotCenterX + 10, robotCenterY, 5, 5); - } - - private void drawTarget(Graphics2D g, int x, int y) - { - AffineTransform t = AffineTransform.getRotateInstance(0, 0, 0); - g.setTransform(t); - g.setColor(Color.GREEN); - fillOval(g, x, y, 5, 5); - g.setColor(Color.BLACK); - drawOval(g, x, y, 5, 5); - } -} diff --git a/robots/src/gui/GameWindow.java b/robots/src/gui/GameWindow.java deleted file mode 100644 index ecb63c00f..000000000 --- a/robots/src/gui/GameWindow.java +++ /dev/null @@ -1,20 +0,0 @@ -package gui; - -import java.awt.BorderLayout; - -import javax.swing.JInternalFrame; -import javax.swing.JPanel; - -public class GameWindow extends JInternalFrame -{ - private final GameVisualizer m_visualizer; - public GameWindow() - { - super("Игровое поле", true, true, true, true); - m_visualizer = new GameVisualizer(); - JPanel panel = new JPanel(new BorderLayout()); - panel.add(m_visualizer, BorderLayout.CENTER); - getContentPane().add(panel); - pack(); - } -} diff --git a/robots/src/gui/MainApplicationFrame.java b/robots/src/gui/MainApplicationFrame.java deleted file mode 100644 index 62e943ee1..000000000 --- a/robots/src/gui/MainApplicationFrame.java +++ /dev/null @@ -1,156 +0,0 @@ -package gui; - -import java.awt.Dimension; -import java.awt.Toolkit; -import java.awt.event.KeyEvent; - -import javax.swing.JDesktopPane; -import javax.swing.JFrame; -import javax.swing.JInternalFrame; -import javax.swing.JMenu; -import javax.swing.JMenuBar; -import javax.swing.JMenuItem; -import javax.swing.SwingUtilities; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; - -import log.Logger; - -/** - * Что требуется сделать: - * 1. Метод создания меню перегружен функционалом и трудно читается. - * Следует разделить его на серию более простых методов (или вообще выделить отдельный класс). - * - */ -public class MainApplicationFrame extends JFrame -{ - private final JDesktopPane desktopPane = new JDesktopPane(); - - public MainApplicationFrame() { - //Make the big window be indented 50 pixels from each edge - //of the screen. - int inset = 50; - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - setBounds(inset, inset, - screenSize.width - inset*2, - screenSize.height - inset*2); - - setContentPane(desktopPane); - - - LogWindow logWindow = createLogWindow(); - addWindow(logWindow); - - GameWindow gameWindow = new GameWindow(); - gameWindow.setSize(400, 400); - addWindow(gameWindow); - - setJMenuBar(generateMenuBar()); - setDefaultCloseOperation(EXIT_ON_CLOSE); - } - - protected LogWindow createLogWindow() - { - LogWindow logWindow = new LogWindow(Logger.getDefaultLogSource()); - logWindow.setLocation(10,10); - logWindow.setSize(300, 800); - setMinimumSize(logWindow.getSize()); - logWindow.pack(); - Logger.debug("Протокол работает"); - return logWindow; - } - - protected void addWindow(JInternalFrame frame) - { - desktopPane.add(frame); - frame.setVisible(true); - } - -// protected JMenuBar createMenuBar() { -// JMenuBar menuBar = new JMenuBar(); -// -// //Set up the lone menu. -// JMenu menu = new JMenu("Document"); -// menu.setMnemonic(KeyEvent.VK_D); -// menuBar.add(menu); -// -// //Set up the first menu item. -// JMenuItem menuItem = new JMenuItem("New"); -// menuItem.setMnemonic(KeyEvent.VK_N); -// menuItem.setAccelerator(KeyStroke.getKeyStroke( -// KeyEvent.VK_N, ActionEvent.ALT_MASK)); -// menuItem.setActionCommand("new"); -//// menuItem.addActionListener(this); -// menu.add(menuItem); -// -// //Set up the second menu item. -// menuItem = new JMenuItem("Quit"); -// menuItem.setMnemonic(KeyEvent.VK_Q); -// menuItem.setAccelerator(KeyStroke.getKeyStroke( -// KeyEvent.VK_Q, ActionEvent.ALT_MASK)); -// menuItem.setActionCommand("quit"); -//// menuItem.addActionListener(this); -// menu.add(menuItem); -// -// return menuBar; -// } - - private JMenuBar generateMenuBar() - { - JMenuBar menuBar = new JMenuBar(); - - JMenu lookAndFeelMenu = new JMenu("Режим отображения"); - lookAndFeelMenu.setMnemonic(KeyEvent.VK_V); - lookAndFeelMenu.getAccessibleContext().setAccessibleDescription( - "Управление режимом отображения приложения"); - - { - JMenuItem systemLookAndFeel = new JMenuItem("Системная схема", KeyEvent.VK_S); - systemLookAndFeel.addActionListener((event) -> { - setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - this.invalidate(); - }); - lookAndFeelMenu.add(systemLookAndFeel); - } - - { - JMenuItem crossplatformLookAndFeel = new JMenuItem("Универсальная схема", KeyEvent.VK_S); - crossplatformLookAndFeel.addActionListener((event) -> { - setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); - this.invalidate(); - }); - lookAndFeelMenu.add(crossplatformLookAndFeel); - } - - JMenu testMenu = new JMenu("Тесты"); - testMenu.setMnemonic(KeyEvent.VK_T); - testMenu.getAccessibleContext().setAccessibleDescription( - "Тестовые команды"); - - { - JMenuItem addLogMessageItem = new JMenuItem("Сообщение в лог", KeyEvent.VK_S); - addLogMessageItem.addActionListener((event) -> { - Logger.debug("Новая строка"); - }); - testMenu.add(addLogMessageItem); - } - - menuBar.add(lookAndFeelMenu); - menuBar.add(testMenu); - return menuBar; - } - - private void setLookAndFeel(String className) - { - try - { - UIManager.setLookAndFeel(className); - SwingUtilities.updateComponentTreeUI(this); - } - catch (ClassNotFoundException | InstantiationException - | IllegalAccessException | UnsupportedLookAndFeelException e) - { - // just ignore - } - } -} diff --git a/robots/src/gui/RobotsProgram.java b/robots/src/gui/RobotsProgram.java deleted file mode 100644 index ae0930a8b..000000000 --- a/robots/src/gui/RobotsProgram.java +++ /dev/null @@ -1,25 +0,0 @@ -package gui; - -import java.awt.Frame; - -import javax.swing.SwingUtilities; -import javax.swing.UIManager; - -public class RobotsProgram -{ - public static void main(String[] args) { - try { - UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); -// UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); -// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); -// UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); - } catch (Exception e) { - e.printStackTrace(); - } - SwingUtilities.invokeLater(() -> { - MainApplicationFrame frame = new MainApplicationFrame(); - frame.pack(); - frame.setVisible(true); - frame.setExtendedState(Frame.MAXIMIZED_BOTH); - }); - }} diff --git a/robots/src/log/LogChangeListener.java b/robots/src/log/LogChangeListener.java deleted file mode 100644 index 0b0fb85dd..000000000 --- a/robots/src/log/LogChangeListener.java +++ /dev/null @@ -1,6 +0,0 @@ -package log; - -public interface LogChangeListener -{ - public void onLogChanged(); -} diff --git a/robots/src/log/LogWindowSource.java b/robots/src/log/LogWindowSource.java deleted file mode 100644 index ca0ce4426..000000000 --- a/robots/src/log/LogWindowSource.java +++ /dev/null @@ -1,89 +0,0 @@ -package log; - -import java.util.ArrayList; -import java.util.Collections; - -/** - * Что починить: - * 1. Этот класс порождает утечку ресурсов (связанные слушатели оказываются - * удерживаемыми в памяти) - * 2. Этот класс хранит активные сообщения лога, но в такой реализации он - * их лишь накапливает. Надо же, чтобы количество сообщений в логе было ограничено - * величиной m_iQueueLength (т.е. реально нужна очередь сообщений - * ограниченного размера) - */ -public class LogWindowSource -{ - private int m_iQueueLength; - - private ArrayList m_messages; - private final ArrayList m_listeners; - private volatile LogChangeListener[] m_activeListeners; - - public LogWindowSource(int iQueueLength) - { - m_iQueueLength = iQueueLength; - m_messages = new ArrayList(iQueueLength); - m_listeners = new ArrayList(); - } - - public void registerListener(LogChangeListener listener) - { - synchronized(m_listeners) - { - m_listeners.add(listener); - m_activeListeners = null; - } - } - - public void unregisterListener(LogChangeListener listener) - { - synchronized(m_listeners) - { - m_listeners.remove(listener); - m_activeListeners = null; - } - } - - public void append(LogLevel logLevel, String strMessage) - { - LogEntry entry = new LogEntry(logLevel, strMessage); - m_messages.add(entry); - LogChangeListener [] activeListeners = m_activeListeners; - if (activeListeners == null) - { - synchronized (m_listeners) - { - if (m_activeListeners == null) - { - activeListeners = m_listeners.toArray(new LogChangeListener [0]); - m_activeListeners = activeListeners; - } - } - } - for (LogChangeListener listener : activeListeners) - { - listener.onLogChanged(); - } - } - - public int size() - { - return m_messages.size(); - } - - public Iterable range(int startFrom, int count) - { - if (startFrom < 0 || startFrom >= m_messages.size()) - { - return Collections.emptyList(); - } - int indexTo = Math.min(startFrom + count, m_messages.size()); - return m_messages.subList(startFrom, indexTo); - } - - public Iterable all() - { - return m_messages; - } -} diff --git a/robots/src/main/java/gui/GameVisualizer.java b/robots/src/main/java/gui/GameVisualizer.java new file mode 100644 index 000000000..8657ed3a2 --- /dev/null +++ b/robots/src/main/java/gui/GameVisualizer.java @@ -0,0 +1,87 @@ +package main.java.gui; + +import model.*; + +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.geom.AffineTransform; +import java.util.Observable; +import java.util.Observer; + +import javax.swing.JPanel; + +import static main.java.tools.DrawTools.*; +import static main.java.tools.MathTools.*; + + +public class GameVisualizer extends JPanel implements Observer { + private final RobotModel robotModel; + private final TargetModel targetModel; + + public GameVisualizer(RobotModel robotModel, TargetModel targetModel) { + this.robotModel = robotModel; + this.targetModel = targetModel; + robotModel.addObserver(this); + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + targetModel.setTargetPosition(e.getPoint()); + repaint(); + } + }); + setDoubleBuffered(true); + } + + + protected void onRedrawEvent() { + EventQueue.invokeLater(this::repaint); + } + + @Override + public void update(Observable o, Object arg) { + if (arg.equals(RobotModel.ROBOT_POSITION_CHANGED)) EventQueue.invokeLater(this::onRedrawEvent); + } + + + @Override + public void paint(Graphics g) { + super.paint(g); + Graphics2D g2d = (Graphics2D) g.create(); + try { + drawRobot(g2d, robotModel); + drawTarget(g2d, targetModel); + } finally { + g2d.dispose(); + } + } + + private void drawTarget(Graphics2D g, TargetModel targetModel) { + int targetX = targetModel.getTargetX(); + int targetY = targetModel.getTargetY(); + AffineTransform t = new AffineTransform(); + g.setTransform(t); + g.setColor(Color.GREEN); + fillOval(g, targetX, targetY, 5, 5); + g.setColor(Color.BLACK); + drawOval(g, targetX, targetY, 5, 5); + } + + private void drawRobot(Graphics2D g, RobotModel robotModel) { + int robotCenterX = round(robotModel.getM_robotPositionX()); + int robotCenterY = round(robotModel.getM_robotPositionY()); + AffineTransform t = AffineTransform.getRotateInstance(robotModel.getM_robotDirection(), robotCenterX, robotCenterY); + g.setTransform(t); + g.setColor(Color.MAGENTA); + fillOval(g, robotCenterX, robotCenterY, 30, 10); + g.setColor(Color.BLACK); + drawOval(g, robotCenterX, robotCenterY, 30, 10); + g.setColor(Color.WHITE); + fillOval(g, robotCenterX + 10, robotCenterY, 5, 5); + g.setColor(Color.BLACK); + drawOval(g, robotCenterX + 10, robotCenterY, 5, 5); + } +} diff --git a/robots/src/main/java/gui/GameWindow.java b/robots/src/main/java/gui/GameWindow.java new file mode 100644 index 000000000..8208d345a --- /dev/null +++ b/robots/src/main/java/gui/GameWindow.java @@ -0,0 +1,23 @@ +package main.java.gui; + +import main.java.view.GameView; + +import javax.swing.*; +import java.awt.*; + +public class GameWindow extends JInternalFrame { + private final GameView gameView; + + public GameWindow(GameView gameView) { + super("Игровое поле", true, true, true, true); + this.gameView = gameView; + JPanel panel = new JPanel(new BorderLayout()); + panel.add(this.gameView, BorderLayout.CENTER); + getContentPane().add(panel); + pack(); + } + + public GameView getGameView() { + return this.gameView; + } +} \ No newline at end of file diff --git a/robots/src/gui/LogWindow.java b/robots/src/main/java/gui/LogWindow.java similarity index 67% rename from robots/src/gui/LogWindow.java rename to robots/src/main/java/gui/LogWindow.java index 723d3e2fc..40487fd4f 100644 --- a/robots/src/gui/LogWindow.java +++ b/robots/src/main/java/gui/LogWindow.java @@ -1,29 +1,28 @@ -package gui; +package main.java.gui; import java.awt.BorderLayout; import java.awt.EventQueue; import java.awt.TextArea; +import java.util.ResourceBundle; import javax.swing.JInternalFrame; import javax.swing.JPanel; -import log.LogChangeListener; -import log.LogEntry; -import log.LogWindowSource; +import main.java.log.LogChangeListener; +import main.java.log.LogEntry; +import main.java.log.LogWindowSource; -public class LogWindow extends JInternalFrame implements LogChangeListener -{ +public class LogWindow extends JInternalFrame implements LogChangeListener, Translatable { private LogWindowSource m_logSource; private TextArea m_logContent; - public LogWindow(LogWindowSource logSource) - { + public LogWindow(LogWindowSource logSource) { super("Протокол работы", true, true, true, true); m_logSource = logSource; m_logSource.registerListener(this); m_logContent = new TextArea(""); m_logContent.setSize(200, 500); - + JPanel panel = new JPanel(new BorderLayout()); panel.add(m_logContent, BorderLayout.CENTER); getContentPane().add(panel); @@ -31,20 +30,22 @@ public LogWindow(LogWindowSource logSource) updateLogContent(); } - private void updateLogContent() - { + private void updateLogContent() { StringBuilder content = new StringBuilder(); - for (LogEntry entry : m_logSource.all()) - { + for (LogEntry entry : m_logSource.all()) { content.append(entry.getMessage()).append("\n"); } m_logContent.setText(content.toString()); m_logContent.invalidate(); } - + @Override - public void onLogChanged() - { + public void onLogChanged() { EventQueue.invokeLater(this::updateLogContent); } + + @Override + public void translate(ResourceBundle bundle) { + setTitle(bundle.getString("logWindowHeader")); + } } diff --git a/robots/src/main/java/gui/MainApplicationFrame.java b/robots/src/main/java/gui/MainApplicationFrame.java new file mode 100644 index 000000000..02b6692b3 --- /dev/null +++ b/robots/src/main/java/gui/MainApplicationFrame.java @@ -0,0 +1,100 @@ +package main.java.gui; + +import main.java.log.Logger; +import main.java.view.ViewModel; +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; + +public class MainApplicationFrame extends JFrame { + private final JDesktopPane desktopPane = new JDesktopPane(); + + public MainApplicationFrame(ViewModel gameViewModel) { + + int inset = 50; + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + setBounds(inset, inset, + screenSize.width - inset * 2, + screenSize.height - inset * 2); + + setContentPane(desktopPane); + + LogWindow logWindow = createLogWindow(); + addWindow(logWindow); + + GameWindow gameWindow = gameViewModel.getGameWindow(); + addWindow(gameWindow); + + setJMenuBar(generateMenuBar()); + setDefaultCloseOperation(EXIT_ON_CLOSE); + } + + protected LogWindow createLogWindow() { + LogWindow logWindow = new LogWindow(Logger.getDefaultLogSource()); + logWindow.setLocation(610, 0); + logWindow.setSize(300, 800); + setMinimumSize(logWindow.getSize()); + logWindow.pack(); + Logger.debug("Протокол работает"); + return logWindow; + } + + protected void addWindow(JInternalFrame frame) { + desktopPane.add(frame); + frame.setVisible(true); + } + + private JMenu createMenu(String nameOfMenu, String description, int mnemonic) { + JMenu lookAndFeelMenu = new JMenu(nameOfMenu); + lookAndFeelMenu.setMnemonic(KeyEvent.VK_V); + lookAndFeelMenu.getAccessibleContext().setAccessibleDescription( + description); + return lookAndFeelMenu; + } + + private JMenuItem createMenuItem(String name, ActionListener l) { + JMenuItem systemLookAndFeel = new JMenuItem(name, KeyEvent.VK_S); + systemLookAndFeel.addActionListener(l); + + return systemLookAndFeel; + } + + private JMenuBar generateMenuBar() { + JMenuBar menuBar = new JMenuBar(); + + JMenu lookAndFeelMenu = createMenu("Режим отображения", + "Управление режимом отображения приложения", KeyEvent.VK_V); + JMenuItem systemLookAndFeel = createMenuItem("Системная схема", (event) -> { + setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + this.invalidate(); + }); + lookAndFeelMenu.add(systemLookAndFeel); + + JMenuItem crossplatformLookAndFeel = createMenuItem("Универсальная схема", (event) -> { + setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); + this.invalidate(); + }); + lookAndFeelMenu.add(crossplatformLookAndFeel); + + JMenu testMenu = createMenu("Тесты", "Тестовые команды", KeyEvent.VK_S); + + JMenuItem addLogMessageItem = createMenuItem("Сообщение в лог", + (event) -> Logger.debug("Новая строка")); + testMenu.add(addLogMessageItem); + + menuBar.add(lookAndFeelMenu); + menuBar.add(testMenu); + return menuBar; + } + + private void setLookAndFeel(String className) { + try { + UIManager.setLookAndFeel(className); + SwingUtilities.updateComponentTreeUI(this); + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException | UnsupportedLookAndFeelException e) { + // just ignore + } + } +} diff --git a/robots/src/main/java/gui/PositionWindow.java b/robots/src/main/java/gui/PositionWindow.java new file mode 100644 index 000000000..d7766c3ee --- /dev/null +++ b/robots/src/main/java/gui/PositionWindow.java @@ -0,0 +1,45 @@ +package main.java.gui; + +import model.RobotModel; + +import java.util.Observable; +import java.util.Observer; +import javax.swing.*; +import java.awt.*; +import java.util.ResourceBundle; + +public class PositionWindow extends JInternalFrame implements Observer, Translatable { + private final JLabel labelX; + private final JLabel labelY; + private final RobotModel m_RobotModel; + + public PositionWindow(RobotModel robotModel, int width, int height) { + super("Координаты робота", true, true, true, true); + m_RobotModel = robotModel; + JPanel panel = new JPanel(new BorderLayout()); + m_RobotModel.addObserver(this); + labelX = new JLabel("X: %f".formatted(m_RobotModel.getM_robotPositionX())); + labelY = new JLabel("Y: %f".formatted(m_RobotModel.getM_robotPositionY())); + panel.add(labelX, BorderLayout.BEFORE_FIRST_LINE); + panel.add(labelY, BorderLayout.CENTER); + getContentPane().add(panel); + pack(); + setSize(width, height); + setLocation(1600, 50); + } + + @Override + public void update(Observable o, Object arg) { + if (arg.equals(RobotModel.ROBOT_POSITION_CHANGED)) EventQueue.invokeLater(this::updateCoords); + } + + void updateCoords() { + labelX.setText("X: %f".formatted(m_RobotModel.getM_robotPositionX())); + labelY.setText("Y: %f".formatted(m_RobotModel.getM_robotPositionY())); + } + + @Override + public void translate(ResourceBundle bundle) { + setTitle(bundle.getString("positionWindowHeader")); + } +} diff --git a/robots/src/main/java/gui/RobotsProgram.java b/robots/src/main/java/gui/RobotsProgram.java new file mode 100644 index 000000000..f09ac8521 --- /dev/null +++ b/robots/src/main/java/gui/RobotsProgram.java @@ -0,0 +1,40 @@ +package main.java.gui; + +import model.RobotModel; +import model.TargetModel; +import main.java.view.GameView; +import model.Model; +import main.java.view.ViewModel; +import javax.swing.*; +import java.awt.*; + +public class RobotsProgram { + public static void main(String[] args) { + try { + UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); + } catch (Exception e) { + e.printStackTrace(); + } + Model gameModel = new Model(); + GameView gameView = new GameView(gameModel); + GameWindow gameWindow = new GameWindow(gameView); + + + TargetModel targetModel = new TargetModel(); + RobotModel robotModel = new RobotModel(targetModel); + + GameVisualizer gameVisualizer = new GameVisualizer(robotModel, targetModel); + PositionWindow positionWindow = new PositionWindow(robotModel, 800, 600); + gameVisualizer.onRedrawEvent(); + positionWindow.updateCoords(); + + ViewModel viewModel = new ViewModel(gameModel, gameWindow); + + SwingUtilities.invokeLater(() -> { + MainApplicationFrame frame = new MainApplicationFrame(viewModel); + frame.pack(); + frame.setVisible(true); + frame.setExtendedState(Frame.MAXIMIZED_BOTH); + }); + } +} diff --git a/robots/src/main/java/gui/Translatable.java b/robots/src/main/java/gui/Translatable.java new file mode 100644 index 000000000..31fb3f0b6 --- /dev/null +++ b/robots/src/main/java/gui/Translatable.java @@ -0,0 +1,7 @@ +package main.java.gui; + +import java.util.ResourceBundle; + +public interface Translatable { + void translate(ResourceBundle bundle); +} diff --git a/robots/src/main/java/log/LogChangeListener.java b/robots/src/main/java/log/LogChangeListener.java new file mode 100644 index 000000000..c9e263260 --- /dev/null +++ b/robots/src/main/java/log/LogChangeListener.java @@ -0,0 +1,6 @@ +package main.java.log; + +public interface LogChangeListener +{ + public void onLogChanged(); +} diff --git a/robots/src/log/LogEntry.java b/robots/src/main/java/log/LogEntry.java similarity index 92% rename from robots/src/log/LogEntry.java rename to robots/src/main/java/log/LogEntry.java index 3d9147107..a29b50e7e 100644 --- a/robots/src/log/LogEntry.java +++ b/robots/src/main/java/log/LogEntry.java @@ -1,24 +1,23 @@ -package log; +package main.java.log; public class LogEntry { private LogLevel m_logLevel; private String m_strMessage; - + public LogEntry(LogLevel logLevel, String strMessage) { m_strMessage = strMessage; m_logLevel = logLevel; } - + public String getMessage() { return m_strMessage; } - + public LogLevel getLevel() { return m_logLevel; } -} - +} \ No newline at end of file diff --git a/robots/src/log/LogLevel.java b/robots/src/main/java/log/LogLevel.java similarity index 90% rename from robots/src/log/LogLevel.java rename to robots/src/main/java/log/LogLevel.java index 582d010cc..db858dd9f 100644 --- a/robots/src/log/LogLevel.java +++ b/robots/src/main/java/log/LogLevel.java @@ -1,4 +1,4 @@ -package log; +package main.java.log; public enum LogLevel { @@ -8,14 +8,14 @@ public enum LogLevel Warning(3), Error(4), Fatal(5); - + private int m_iLevel; - + private LogLevel(int iLevel) { m_iLevel = iLevel; } - + public int level() { return m_iLevel; diff --git a/robots/src/main/java/log/LogWindowSource.java b/robots/src/main/java/log/LogWindowSource.java new file mode 100644 index 000000000..a283d2720 --- /dev/null +++ b/robots/src/main/java/log/LogWindowSource.java @@ -0,0 +1,65 @@ +package main.java.log; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.concurrent.CopyOnWriteArrayList; + +public class LogWindowSource { + private final int m_iQueueLength; + + private final ArrayList m_messages; + private final CopyOnWriteArrayList m_listeners; + private volatile LogChangeListener[] m_activeListeners; + + public LogWindowSource(int iQueueLength) { + m_iQueueLength = iQueueLength; + m_messages = new ArrayList<>(iQueueLength); + m_listeners = new CopyOnWriteArrayList<>(); + } + + public void registerListener(LogChangeListener listener) { + m_listeners.add(listener); + m_activeListeners = null; + } + + public void unregisterListener(LogChangeListener listener) { + m_listeners.remove(listener); + m_activeListeners = null; + } + + public void append(LogLevel logLevel, String strMessage) { + LogEntry entry = new LogEntry(logLevel, strMessage); + if (size() >= m_iQueueLength) m_messages.remove(0); + synchronized (this) { + m_messages.add(entry); + } + LogChangeListener[] activeListeners = m_activeListeners; + if (activeListeners == null) { + synchronized (m_listeners) { + if (m_activeListeners == null) { + activeListeners = m_listeners.toArray(new LogChangeListener[0]); + m_activeListeners = activeListeners; + } + } + } + for (LogChangeListener listener : activeListeners) { + listener.onLogChanged(); + } + } + + public synchronized int size() { + return m_messages.size(); + } + + public synchronized Iterable range(int startFrom, int count) { + if (startFrom < 0 || startFrom >= size()) { + return Collections.emptyList(); + } + int indexTo = Math.min(startFrom + count, size()); + return m_messages.subList(startFrom, indexTo); + } + + public synchronized Iterable all() { + return m_messages; + } +} diff --git a/robots/src/log/Logger.java b/robots/src/main/java/log/Logger.java similarity index 95% rename from robots/src/log/Logger.java rename to robots/src/main/java/log/Logger.java index b008a5d01..d7cf78f2f 100644 --- a/robots/src/log/Logger.java +++ b/robots/src/main/java/log/Logger.java @@ -1,4 +1,4 @@ -package log; +package main.java.log; public final class Logger { @@ -6,7 +6,7 @@ public final class Logger static { defaultLogSource = new LogWindowSource(100); } - + private Logger() { } @@ -15,7 +15,7 @@ public static void debug(String strMessage) { defaultLogSource.append(LogLevel.Debug, strMessage); } - + public static void error(String strMessage) { defaultLogSource.append(LogLevel.Error, strMessage); diff --git a/robots/src/main/java/model/Entity.java b/robots/src/main/java/model/Entity.java new file mode 100644 index 000000000..3a081d7e4 --- /dev/null +++ b/robots/src/main/java/model/Entity.java @@ -0,0 +1,12 @@ +package model; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +public interface Entity extends PropertyChangeListener { + void update(); + + void onStart(PropertyChangeSupport publisher); + + void onFinish(PropertyChangeSupport publisher); +} \ No newline at end of file diff --git a/robots/src/main/java/model/Model.java b/robots/src/main/java/model/Model.java new file mode 100644 index 000000000..fa7e212f8 --- /dev/null +++ b/robots/src/main/java/model/Model.java @@ -0,0 +1,66 @@ +package model; + +import java.awt.*; +import java.beans.PropertyChangeSupport; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +public class Model { + private final List entities; + private final PropertyChangeSupport support; + + public Model() { + this.support = new PropertyChangeSupport(this); + this.entities = initStateOfBacterias(2); + + Timer timer = initTimer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + System.out.println("timer"); + support.firePropertyChange("change satiety", null, -10); + } + }, 0, 1500); + } + + private static java.util.Timer initTimer() { + return new Timer("satiety generator", true); + } + + public void setDimension(Dimension dimension) { + support.firePropertyChange("set dimension", null, dimension); + } + + public Dimension getDimension() { + return ((Robot) entities.get(0)).getDimension(); + } + + public void updateModel() { + for (Entity entity : entities) { + entity.update(); + } + } + + public List getEntities() { + return entities; + } + + public void setTarget(Point point) { + support.firePropertyChange("new point", null, point); + } + + public List initStateOfBacterias(int amount) { + List entityList = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + Robot robot = new Robot(Math.random() * 400, Math.random() * 400); + robot.setTarget(new Point((int) (Math.random() * 400), (int) (Math.random() * 400))); + robot.onStart(support); + entityList.add(robot); + } + return entityList; + } +} + + diff --git a/robots/src/main/java/model/Robot.java b/robots/src/main/java/model/Robot.java new file mode 100644 index 000000000..f97ce7c79 --- /dev/null +++ b/robots/src/main/java/model/Robot.java @@ -0,0 +1,234 @@ +package model; + +import java.awt.*; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeSupport; + +public class Robot implements Entity { + private double positionX; + private double positionY; + private Target target; + private Dimension dimension; + private volatile double robotDirection; + public static final double maxVelocity = 0.1; + public static final double maxAngularVelocity = 0.01; + private static final int INITIAL_SATIETY = 50; + private static final int MAX_SATIETY = 100; + private int satiety; + private TypeRobot type; + private boolean isAlive; + private boolean isTargetAchieved; + + public Robot(double x, double y) { + this.positionX = x; + this.positionY = y; + this.target = new Target(); + this.robotDirection = Math.random() * 10;; + this.dimension = new Dimension(300, 300); + this.satiety = (int) (INITIAL_SATIETY + Math.random() * (MAX_SATIETY - INITIAL_SATIETY)); + this.isAlive = true; + this.type= TypeRobot.randomType(); + } + + public Robot() { + this.positionX = 300; + this.positionY = 300; + this.target = new Target(); + this.robotDirection = 0; + } + + private void setRandomType() { + this.type = TypeRobot.randomType(); + } + + public void setType(TypeRobot type) { + this.type = type; + } + public TypeRobot getType() { + return type; + } + + public int getSatiety() { + return satiety; + } + + public void changeSatiety(int satiety) { + this.satiety += satiety; + } + + public void setDimension(Dimension dimension) { + this.dimension = dimension; + if (!target.isPositionCorrect(dimension)) { + target = new Target((int) (Math.random() * dimension.width), (int) (Math.random() * dimension.height)); + } + } + + public Dimension getDimension() { + return this.dimension; + } + + public double getPositionX() { + return positionX; + } + + public void setPositionX(double positionX) { + this.positionX = positionX; + } + + public double getPositionY() { + return positionY; + } + + public void setPositionY(double positionY) { + this.positionY = positionY; + } + + public double getRobotDirection() { + return robotDirection; + } + + public void setRobotDirection(double robotDirection) { + this.robotDirection = robotDirection; + } + + private static double distance(double x1, double y1, double x2, double y2) { + double diffX = x1 - x2; + double diffY = y1 - y2; + return Math.sqrt(diffX * diffX + diffY * diffY); + } + + private static double angleTo(double fromX, double fromY, double toX, double toY) { + double diffX = toX - fromX; + double diffY = toY - fromY; + + return asNormalizedRadians(Math.atan2(diffY, diffX)); + } + + private static double asNormalizedRadians(double angle) { + while (angle < 0) { + angle += 2 * Math.PI; + } + while (angle >= 2 * Math.PI) { + angle -= 2 * Math.PI; + } + return angle; + } + + private double normalizedPositionX(double x) { + if (x < 0) + return 0; + if (x > dimension.width) + return dimension.width; + return x; + } + + private double normalizedPositionY(double y) { + if (y < 0) + return 0; + if (y > dimension.height) + return dimension.height; + return y; + } + + private static double applyLimits(double value, double min, double max) { + if (value < min) + return min; + if (value > max) + return max; + return value; + } + + public Target getTarget() { + return target; + } + + public void setTarget(Point point) { + this.target.setTargetPosition(point); + } + + private void moveRobot(double velocity, double angularVelocity, double duration) { + velocity = applyLimits(velocity, 0, Robot.maxVelocity); + angularVelocity = applyLimits(angularVelocity, -Robot.maxAngularVelocity, Robot.maxAngularVelocity); + double newX = getPositionX() + velocity / angularVelocity * + (Math.sin(getRobotDirection() + angularVelocity * duration) - + Math.sin(getRobotDirection())); + if (!Double.isFinite(newX)) { + newX = getPositionX() + velocity * duration * Math.cos(getRobotDirection()); + } + double newY = getPositionY() - velocity / angularVelocity * + (Math.cos(getRobotDirection() + angularVelocity * duration) - + Math.cos(getRobotDirection())); + if (!Double.isFinite(newY)) { + newY = getPositionY() + velocity * duration * Math.sin(getRobotDirection()); + } + setPositionX(normalizedPositionX(newX)); + setPositionY(normalizedPositionY(newY)); + double newDirection = asNormalizedRadians(getRobotDirection() + angularVelocity * duration); + setRobotDirection(newDirection); + } + + @Override + public void update() { + if (!this.isAlive) { + this.setType(TypeRobot.DEAD); + + return; + } + if (this.satiety < 50) { + if (this.satiety < 0) { + isAlive = false; + } + this.setType(TypeRobot.HUNGRY); + + } + double distance = distance(target.getX(), target.getY(), + getPositionX(), getPositionY()); + this.isTargetAchieved = false; + if (distance < 0.5) { + this.isTargetAchieved = true; + this.onTargetAchieved(); + + return; + } + double angleToTarget = angleTo(getPositionX(), getPositionY(), + target.getX(), target.getY()); + double angularVelocity = 0; + if (angleToTarget > getRobotDirection()) { + angularVelocity = Robot.maxAngularVelocity; + } + if (angleToTarget < getRobotDirection()) { + angularVelocity = -Robot.maxAngularVelocity; + } + + moveRobot(Robot.maxVelocity, angularVelocity, 10); + + } + + @Override + public void onStart(PropertyChangeSupport publisher) { + publisher.addPropertyChangeListener(this); + } + + @Override + public void onFinish(PropertyChangeSupport publisher) { + publisher.removePropertyChangeListener(this); + } + + private void onTargetAchieved() { + this.setTarget(new Point((int) (Math.random() * dimension.width), (int) (Math.random() * dimension.height))); + this.satiety += 25; + if (this.satiety > 50) { + this.setRandomType(); + } + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("new point")) + setTarget((Point) evt.getNewValue()); + if (evt.getPropertyName().equals("change satiety")) + changeSatiety((int) evt.getNewValue()); + if (evt.getPropertyName().equals("set dimension")) + setDimension((Dimension) evt.getNewValue()); + } +} diff --git a/robots/src/main/java/model/RobotModel.java b/robots/src/main/java/model/RobotModel.java new file mode 100644 index 000000000..952ba599b --- /dev/null +++ b/robots/src/main/java/model/RobotModel.java @@ -0,0 +1,64 @@ +package model; + +import java.util.Observable; + +import static main.java.tools.MathTools.*; + +public class RobotModel extends Observable { + private volatile double m_robotPositionX = 100; + private volatile double m_robotPositionY = 100; + private volatile double m_robotDirection = 0; + public static final double maxVelocity = 0.1; + public static final double maxAngularVelocity = 0.001; + private final TargetModel targetModel; + public final static String ROBOT_POSITION_CHANGED = "The robot's position has changed"; + + public RobotModel(TargetModel targetModel) { + this.targetModel = targetModel; + } + + public double getM_robotPositionX() { + return m_robotPositionX; + } + + public double getM_robotPositionY() { + return m_robotPositionY; + } + + public double getM_robotDirection() { + return m_robotDirection; + } + + public void moveRobot(double velocity, double angularVelocity, double duration) { + velocity = applyLimits(velocity, 0, maxVelocity); + angularVelocity = applyLimits(angularVelocity, -maxAngularVelocity, maxAngularVelocity); + double newX = m_robotPositionX + velocity / angularVelocity * + (Math.sin(m_robotDirection + angularVelocity * duration) - + Math.sin(m_robotDirection)); + double newY = m_robotPositionY - velocity / angularVelocity * + (Math.cos(m_robotDirection + angularVelocity * duration) - + Math.cos(m_robotDirection)); + + if (!Double.isFinite(newX)) newX = m_robotPositionX + velocity * duration * Math.cos(m_robotDirection); + if (!Double.isFinite(newY)) newY = m_robotPositionY + velocity * duration * Math.sin(m_robotDirection); + + m_robotPositionX = newX; + m_robotPositionY = newY; + m_robotDirection = asNormalizedRadians(m_robotDirection + angularVelocity * duration); + setChanged(); + notifyObservers(ROBOT_POSITION_CHANGED); + } + + public void updateRobotPosition() { + double distance = distance(targetModel.getTargetX(), targetModel.getTargetY(), m_robotPositionX, m_robotPositionY); + if (distance < 0.5) return; + + double angleToTarget = angleTo(m_robotPositionX, m_robotPositionY, targetModel.getTargetX(), targetModel.getTargetY()); + double angularVelocity = 0; + if (angleToTarget > m_robotDirection) angularVelocity = maxAngularVelocity; + if (angleToTarget < m_robotDirection) angularVelocity = -maxAngularVelocity; + if (Math.abs(angleToTarget - m_robotDirection) > Math.PI) angularVelocity = -angularVelocity; + moveRobot(maxVelocity, angularVelocity, 10); + + } +} diff --git a/robots/src/main/java/model/Target.java b/robots/src/main/java/model/Target.java new file mode 100644 index 000000000..3bbb9442b --- /dev/null +++ b/robots/src/main/java/model/Target.java @@ -0,0 +1,46 @@ +package model; + +import java.awt.*; + +public class Target { + private volatile int x; + private volatile int y; + + public Target() { + this.x = 100; + this.y = 100; + } + + public Target(int x, int y) { + this.x = x; + this.y = y; + } + + public void setX(int x) { + this.x = x; + } + + public void setY(int y) { + this.y = y; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public void setTargetPosition(Point p) { + setX(p.x); + setY(p.y); + } + + + + public boolean isPositionCorrect(Dimension dimension) { + return this.x <= dimension.width && this.y <= dimension.height; + } + +} diff --git a/robots/src/main/java/model/TargetModel.java b/robots/src/main/java/model/TargetModel.java new file mode 100644 index 000000000..bf62915ad --- /dev/null +++ b/robots/src/main/java/model/TargetModel.java @@ -0,0 +1,21 @@ +package model; + +import java.awt.*; + +public class TargetModel { + private volatile int m_targetPositionX = 150; + private volatile int m_targetPositionY = 100; + + public void setTargetPosition(Point p) { + m_targetPositionX = p.x; + m_targetPositionY = p.y; + } + + public int getTargetX() { + return m_targetPositionX; + } + + public int getTargetY() { + return m_targetPositionY; + } +} diff --git a/robots/src/main/java/model/TypeRobot.java b/robots/src/main/java/model/TypeRobot.java new file mode 100644 index 000000000..e733f7891 --- /dev/null +++ b/robots/src/main/java/model/TypeRobot.java @@ -0,0 +1,27 @@ +package model; + +import java.awt.*; +import java.util.List; +import java.util.Random; + +public enum TypeRobot { + CALM(Color.GREEN), + HUNGRY(Color.RED), + DEAD(Color.BLACK); + private final Color color; + private static final Random RANDOM = new Random(); + private static final List values = List.of(values()); + + public static TypeRobot randomType() { + return values.get(RANDOM.nextInt(values().length - 2)); + } + + TypeRobot(Color color) { + this.color = color; + } + + + public Color getColor() { + return color; + } +} \ No newline at end of file diff --git a/robots/src/main/java/tools/DrawTools.java b/robots/src/main/java/tools/DrawTools.java new file mode 100644 index 000000000..dae43b4f9 --- /dev/null +++ b/robots/src/main/java/tools/DrawTools.java @@ -0,0 +1,13 @@ +package main.java.tools; + +import java.awt.*; + +public class DrawTools { + public static void fillOval(Graphics g, int centerX, int centerY, int diam1, int diam2) { + g.fillOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, diam2); + } + + public static void drawOval(Graphics g, int centerX, int centerY, int diam1, int diam2) { + g.drawOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, diam2); + } +} diff --git a/robots/src/main/java/tools/MathTools.java b/robots/src/main/java/tools/MathTools.java new file mode 100644 index 000000000..ffe704340 --- /dev/null +++ b/robots/src/main/java/tools/MathTools.java @@ -0,0 +1,36 @@ +package main.java.tools; + +public class MathTools { + public static double distance(double x1, double y1, double x2, double y2) { + double diffX = x1 - x2; + double diffY = y1 - y2; + return Math.sqrt(diffX * diffX + diffY * diffY); + } + + public static double asNormalizedRadians(double angle) { + while (angle < 0) { + angle += 2 * Math.PI; + } + while (angle >= 2 * Math.PI) { + angle -= 2 * Math.PI; + } + return angle; + } + + public static double angleTo(double fromX, double fromY, double toX, double toY) { + double diffX = toX - fromX; + double diffY = toY - fromY; + + return asNormalizedRadians(Math.atan2(diffY, diffX)); + } + + public static double applyLimits(double value, double min, double max) { + if (value < min) + return min; + return Math.min(value, max); + } + + public static int round(double value) { + return (int) (value + 0.5); + } +} diff --git a/robots/src/main/java/view/GameDrawer.java b/robots/src/main/java/view/GameDrawer.java new file mode 100644 index 000000000..5d8991dcb --- /dev/null +++ b/robots/src/main/java/view/GameDrawer.java @@ -0,0 +1,20 @@ +package main.java.view; + +import model.Entity; + +import java.awt.*; + +public abstract class GameDrawer { + protected static void fillOval(Graphics g, int centerX, int centerY, int diam1, int diam2) { + g.fillOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, diam2); + } + + protected static void drawOval(Graphics g, int centerX, int centerY, int diam1, int diam2) { + g.drawOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, diam2); + } + + public abstract void draw(Graphics2D g, Entity entity); + + + public abstract Class getDrawingType(); +} diff --git a/robots/src/main/java/view/GameView.java b/robots/src/main/java/view/GameView.java new file mode 100644 index 000000000..c53358517 --- /dev/null +++ b/robots/src/main/java/view/GameView.java @@ -0,0 +1,47 @@ +package main.java.view; + +import model.Entity; +import model.Model; +import model.Target; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +public class GameView extends JPanel { + private final Model gameModel; + private final Map, GameDrawer> map; + public GameView(Model gameModel) { + this.gameModel = gameModel; + setDoubleBuffered(true); + map = new HashMap<>(); + map.put(new RobotDrawer().getDrawingType(), new RobotDrawer()); + map.put(new TargetDrawer().getDrawingType(), new TargetDrawer()); + this.setPreferredSize(new Dimension(600, 600)); + this.setSize(new Dimension(600, 600)); + this.setBorder(BorderFactory.createLineBorder(Color.RED)); + + } + + public void updateView() { + onRedrawEvent(); + } + + protected void onRedrawEvent() { + EventQueue.invokeLater(this::repaint); + } + + @Override + public void paint(Graphics g) { + super.paint(g); + Graphics2D g2d = (Graphics2D) g; + RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setRenderingHints(rh); + ArrayList entities = (ArrayList) gameModel.getEntities(); + for (Entity entity : entities) { + map.get(entity.getClass()).draw(g2d, entity); + map.get(Target.class).draw(g2d, entity); + } + } +} \ No newline at end of file diff --git a/robots/src/main/java/view/RobotDrawer.java b/robots/src/main/java/view/RobotDrawer.java new file mode 100644 index 000000000..ca98a56dc --- /dev/null +++ b/robots/src/main/java/view/RobotDrawer.java @@ -0,0 +1,55 @@ +package main.java.view; + +import model.Robot; +import model.Entity; +import model.TypeRobot; +import java.awt.*; +import java.awt.geom.AffineTransform; + +public class RobotDrawer extends GameDrawer { + @Override + public void draw(Graphics2D g, Entity entity) + { + Robot robot = (Robot) entity; + AffineTransform oldTransform = g.getTransform(); + int robotCenterX = (int) (Math.round(robot.getPositionX())); + int robotCenterY = (int) (Math.round(robot.getPositionY())); + AffineTransform l = new AffineTransform(oldTransform); + AffineTransform t = AffineTransform.getRotateInstance(robot.getRobotDirection(), robotCenterX, robotCenterY); + l.concatenate(t); + + g.setTransform(l); + + g.setColor(robot.getType().getColor()); + if (robot.getType().equals(TypeRobot.HUNGRY)) { + fillOval(g, robotCenterX, robotCenterY, 20, 10); + g.setColor(Color.BLACK); + drawOval(g, robotCenterX, robotCenterY, 20, 10); + g.setColor(Color.YELLOW); + } + + if (robot.getType().equals(TypeRobot.CALM)) { + fillOval(g, robotCenterX, robotCenterY, 25, 15); + g.setColor(Color.BLACK); + drawOval(g, robotCenterX, robotCenterY, 25, 15); + g.setColor(Color.WHITE); + } + + if (robot.getType().equals(TypeRobot.DEAD)) { + fillOval(g, robotCenterX, robotCenterY, 20, 10); + g.setColor(Color.WHITE); + drawOval(g, robotCenterX, robotCenterY, 20, 10); + g.setColor(Color.BLACK); + } + + fillOval(g, robotCenterX + 7, robotCenterY, 5, 5); + g.setColor(Color.BLACK); + drawOval(g, robotCenterX + 7, robotCenterY, 5, 5); + g.setTransform(oldTransform); + } + + @Override + public Class getDrawingType() { + return Robot.class; + } +} \ No newline at end of file diff --git a/robots/src/main/java/view/TargetDrawer.java b/robots/src/main/java/view/TargetDrawer.java new file mode 100644 index 000000000..9da29f084 --- /dev/null +++ b/robots/src/main/java/view/TargetDrawer.java @@ -0,0 +1,22 @@ +package main.java.view; + +import model.Entity; +import model.Robot; +import model.Target; + +import java.awt.*; + +public class TargetDrawer extends GameDrawer { + @Override + public void draw(Graphics2D g, Entity entity) { + Target target = ((Robot) entity).getTarget(); + g.setColor(Color.GREEN); + fillOval(g, target.getX(), target.getY(), 5, 5); + g.setColor(Color.BLACK); + drawOval(g, target.getX(), target.getY(), 5, 5); + } + @Override + public Class getDrawingType() { + return Target.class; + } +} diff --git a/robots/src/main/java/view/ViewModel.java b/robots/src/main/java/view/ViewModel.java new file mode 100644 index 000000000..f30db5da5 --- /dev/null +++ b/robots/src/main/java/view/ViewModel.java @@ -0,0 +1,76 @@ +package main.java.view; + +import main.java.gui.GameWindow; +import model.Model; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.Timer; +import java.util.TimerTask; + +public class ViewModel { + private final Model gameModel; + private final GameWindow gameWindow; + private final java.util.Timer timer = initTimer(); + + private static java.util.Timer initTimer() { + return new Timer("events generator", true); + } + + public ViewModel(Model gameModel, GameWindow gameWindow) { + this.gameModel = gameModel; + this.gameWindow = gameWindow; + initListeners(); + } + + private void initListeners() { + timer.schedule(new TimerTask() { + @Override + public void run() { + gameModel.setDimension(gameWindow.getSize()); + getGameView().updateView(); + } + }, 0, 5); + + timer.schedule(new TimerTask() { + @Override + public void run() { + gameModel.updateModel(); + } + }, 0, 5); + gameWindow.getGameView().addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + gameModel.setTarget(e.getPoint()); + getGameView().repaint(); + } + }); + gameWindow.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(final ComponentEvent e) { + super.componentResized(e); + System.out.println("resize"); + gameModel.setDimension((gameWindow.getSize())); + System.out.println(gameModel.getDimension()); + } + }); + + gameWindow.getGameView().addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + System.out.println(e.getPoint()); + gameModel.setTarget(e.getPoint()); + getGameView().repaint(); + } + }); + } + + public GameView getGameView() { + return gameWindow.getGameView(); + } + + public GameWindow getGameWindow() { + return gameWindow; + } +} \ No newline at end of file From 6fda9073481dc93ac32747298e347f45e5f94c55 Mon Sep 17 00:00:00 2001 From: vdrnvdrn Date: Thu, 9 Nov 2023 14:56:00 +0500 Subject: [PATCH 2/5] fixed --- robots/src/main/java/gui/GameVisualizer.java | 16 ++--- robots/src/main/java/gui/PositionWindow.java | 10 +-- robots/src/main/java/gui/RobotsProgram.java | 19 ++---- robots/src/main/java/model/Entity.java | 2 +- robots/src/main/java/model/Model.java | 24 +++++--- robots/src/main/java/model/Robot.java | 65 ++++++++++++++++---- robots/src/main/java/model/RobotModel.java | 64 ------------------- robots/src/main/java/model/Target.java | 36 ++++++++++- robots/src/main/java/model/TargetModel.java | 21 ------- robots/src/main/java/model/TypeRobot.java | 20 +++++- robots/src/main/java/tools/DrawTools.java | 13 ---- robots/src/main/java/view/GameDrawer.java | 2 +- robots/src/main/java/view/GameView.java | 12 ++-- robots/src/main/java/view/RobotDrawer.java | 6 +- robots/src/main/java/view/TargetDrawer.java | 8 +-- robots/src/main/java/view/ViewModel.java | 3 +- 16 files changed, 154 insertions(+), 167 deletions(-) delete mode 100644 robots/src/main/java/model/RobotModel.java delete mode 100644 robots/src/main/java/model/TargetModel.java delete mode 100644 robots/src/main/java/tools/DrawTools.java diff --git a/robots/src/main/java/gui/GameVisualizer.java b/robots/src/main/java/gui/GameVisualizer.java index 8657ed3a2..fa4c738ea 100644 --- a/robots/src/main/java/gui/GameVisualizer.java +++ b/robots/src/main/java/gui/GameVisualizer.java @@ -1,6 +1,7 @@ package main.java.gui; -import model.*; +import main.java.model.Robot; +import main.java.model.Target; import java.awt.Color; import java.awt.EventQueue; @@ -14,15 +15,14 @@ import javax.swing.JPanel; -import static main.java.tools.DrawTools.*; import static main.java.tools.MathTools.*; public class GameVisualizer extends JPanel implements Observer { - private final RobotModel robotModel; - private final TargetModel targetModel; + private final Robot robotModel; + private final Target targetModel; - public GameVisualizer(RobotModel robotModel, TargetModel targetModel) { + public GameVisualizer(Robot robotModel, Target targetModel) { this.robotModel = robotModel; this.targetModel = targetModel; robotModel.addObserver(this); @@ -43,7 +43,7 @@ protected void onRedrawEvent() { @Override public void update(Observable o, Object arg) { - if (arg.equals(RobotModel.ROBOT_POSITION_CHANGED)) EventQueue.invokeLater(this::onRedrawEvent); + if (arg.equals(Robot.ROBOT_POSITION_CHANGED)) EventQueue.invokeLater(this::onRedrawEvent); } @@ -59,7 +59,7 @@ public void paint(Graphics g) { } } - private void drawTarget(Graphics2D g, TargetModel targetModel) { + private void drawTarget(Graphics2D g, Target targetModel) { int targetX = targetModel.getTargetX(); int targetY = targetModel.getTargetY(); AffineTransform t = new AffineTransform(); @@ -70,7 +70,7 @@ private void drawTarget(Graphics2D g, TargetModel targetModel) { drawOval(g, targetX, targetY, 5, 5); } - private void drawRobot(Graphics2D g, RobotModel robotModel) { + private void drawRobot(Graphics2D g, Robot robotModel) { int robotCenterX = round(robotModel.getM_robotPositionX()); int robotCenterY = round(robotModel.getM_robotPositionY()); AffineTransform t = AffineTransform.getRotateInstance(robotModel.getM_robotDirection(), robotCenterX, robotCenterY); diff --git a/robots/src/main/java/gui/PositionWindow.java b/robots/src/main/java/gui/PositionWindow.java index d7766c3ee..927603fe6 100644 --- a/robots/src/main/java/gui/PositionWindow.java +++ b/robots/src/main/java/gui/PositionWindow.java @@ -1,7 +1,6 @@ package main.java.gui; -import model.RobotModel; - +import java.util.ArrayList; import java.util.Observable; import java.util.Observer; import javax.swing.*; @@ -11,9 +10,10 @@ public class PositionWindow extends JInternalFrame implements Observer, Translatable { private final JLabel labelX; private final JLabel labelY; - private final RobotModel m_RobotModel; + private final Robot m_RobotModel; + - public PositionWindow(RobotModel robotModel, int width, int height) { + public PositionWindow(Robot robotModel, int width, int height) { super("Координаты робота", true, true, true, true); m_RobotModel = robotModel; JPanel panel = new JPanel(new BorderLayout()); @@ -30,7 +30,7 @@ public PositionWindow(RobotModel robotModel, int width, int height) { @Override public void update(Observable o, Object arg) { - if (arg.equals(RobotModel.ROBOT_POSITION_CHANGED)) EventQueue.invokeLater(this::updateCoords); + if (arg.equals(Robot.ROBOT_POSITION_CHANGED)) EventQueue.invokeLater(this::updateCoords); } void updateCoords() { diff --git a/robots/src/main/java/gui/RobotsProgram.java b/robots/src/main/java/gui/RobotsProgram.java index f09ac8521..8c5b688af 100644 --- a/robots/src/main/java/gui/RobotsProgram.java +++ b/robots/src/main/java/gui/RobotsProgram.java @@ -1,9 +1,7 @@ package main.java.gui; -import model.RobotModel; -import model.TargetModel; +import main.java.model.Model; import main.java.view.GameView; -import model.Model; import main.java.view.ViewModel; import javax.swing.*; import java.awt.*; @@ -15,23 +13,18 @@ public static void main(String[] args) { } catch (Exception e) { e.printStackTrace(); } + Model gameModel = new Model(); GameView gameView = new GameView(gameModel); GameWindow gameWindow = new GameWindow(gameView); + ViewModel viewModel = new ViewModel(gameModel, gameWindow); - TargetModel targetModel = new TargetModel(); - RobotModel robotModel = new RobotModel(targetModel); - - GameVisualizer gameVisualizer = new GameVisualizer(robotModel, targetModel); - PositionWindow positionWindow = new PositionWindow(robotModel, 800, 600); - gameVisualizer.onRedrawEvent(); - positionWindow.updateCoords(); - - ViewModel viewModel = new ViewModel(gameModel, gameWindow); + viewModel = new ViewModel(gameModel, gameWindow); + ViewModel finalViewModel = viewModel; SwingUtilities.invokeLater(() -> { - MainApplicationFrame frame = new MainApplicationFrame(viewModel); + MainApplicationFrame frame = new MainApplicationFrame(finalViewModel); frame.pack(); frame.setVisible(true); frame.setExtendedState(Frame.MAXIMIZED_BOTH); diff --git a/robots/src/main/java/model/Entity.java b/robots/src/main/java/model/Entity.java index 3a081d7e4..1bc26e146 100644 --- a/robots/src/main/java/model/Entity.java +++ b/robots/src/main/java/model/Entity.java @@ -1,4 +1,4 @@ -package model; +package main.java.model; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; diff --git a/robots/src/main/java/model/Model.java b/robots/src/main/java/model/Model.java index fa7e212f8..6683d5311 100644 --- a/robots/src/main/java/model/Model.java +++ b/robots/src/main/java/model/Model.java @@ -1,4 +1,4 @@ -package model; +package main.java.model; import java.awt.*; import java.beans.PropertyChangeSupport; @@ -11,6 +11,12 @@ public class Model { private final List entities; private final PropertyChangeSupport support; + public static final String NEW_POINT_EVENT = "new point"; + public static final String CHANGE_SATIETY = "change satiety"; + public static final String SATIETY_GENERATOR = "satiety generator"; + public static final String SET_DIMENSION = "set dimension"; + + public Model() { this.support = new PropertyChangeSupport(this); this.entities = initStateOfBacterias(2); @@ -20,17 +26,17 @@ public Model() { @Override public void run() { System.out.println("timer"); - support.firePropertyChange("change satiety", null, -10); + support.firePropertyChange(CHANGE_SATIETY, null, -10); } }, 0, 1500); } - private static java.util.Timer initTimer() { - return new Timer("satiety generator", true); + private static Timer initTimer() { + return new Timer(SATIETY_GENERATOR, true); } public void setDimension(Dimension dimension) { - support.firePropertyChange("set dimension", null, dimension); + support.firePropertyChange(SET_DIMENSION, null, dimension); } public Dimension getDimension() { @@ -48,16 +54,16 @@ public List getEntities() { } public void setTarget(Point point) { - support.firePropertyChange("new point", null, point); + support.firePropertyChange(NEW_POINT_EVENT, null, point); } public List initStateOfBacterias(int amount) { List entityList = new ArrayList<>(); - for (int i = 0; i < 5; i++) { + for (int i = 0; i < amount; i++) { Robot robot = new Robot(Math.random() * 400, Math.random() * 400); - robot.setTarget(new Point((int) (Math.random() * 400), (int) (Math.random() * 400))); + robot.setTargetPosition(new Point((int) (Math.random() * 400), (int) (Math.random() * 400))); robot.onStart(support); - entityList.add(robot); + entityList.add((Entity) robot); } return entityList; } diff --git a/robots/src/main/java/model/Robot.java b/robots/src/main/java/model/Robot.java index f97ce7c79..9176fc1de 100644 --- a/robots/src/main/java/model/Robot.java +++ b/robots/src/main/java/model/Robot.java @@ -1,10 +1,15 @@ -package model; +package main.java.model; + +import main.java.gui.GameVisualizer; +import model.TypeRobot; import java.awt.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeSupport; +import java.util.ArrayList; public class Robot implements Entity { + public static final Object ROBOT_POSITION_CHANGED = "robot position changed"; private double positionX; private double positionY; private Target target; @@ -15,9 +20,10 @@ public class Robot implements Entity { private static final int INITIAL_SATIETY = 50; private static final int MAX_SATIETY = 100; private int satiety; - private TypeRobot type; + private model.TypeRobot type; private boolean isAlive; private boolean isTargetAchieved; + private Point targetPosition; public Robot(double x, double y) { this.positionX = x; @@ -27,7 +33,7 @@ public Robot(double x, double y) { this.dimension = new Dimension(300, 300); this.satiety = (int) (INITIAL_SATIETY + Math.random() * (MAX_SATIETY - INITIAL_SATIETY)); this.isAlive = true; - this.type= TypeRobot.randomType(); + this.type= model.TypeRobot.randomType(); } public Robot() { @@ -38,13 +44,13 @@ public Robot() { } private void setRandomType() { - this.type = TypeRobot.randomType(); + this.type = model.TypeRobot.randomType(); } - public void setType(TypeRobot type) { + public void setType(model.TypeRobot type) { this.type = type; } - public TypeRobot getType() { + public model.TypeRobot getType() { return type; } @@ -52,6 +58,16 @@ public int getSatiety() { return satiety; } +// public TypeRobot getType() { +// if (satiety >= MAX_SATIETY) { +// return TypeRobot.FAT; +// } else if (satiety >= MEDIUM_SATIETY) { +// return TypeRobot.NORMAL; +// } else { +// return TypeRobot.HUNGRY; +// } +// } + public void changeSatiety(int satiety) { this.satiety += satiety; } @@ -169,27 +185,41 @@ private void moveRobot(double velocity, double angularVelocity, double duration) @Override public void update() { + updateRobotState(); + if (needSkipUpdate()) { + return; + } + interactionWithEnvironment(); + transformRobot(); + } + + private void updateRobotState() { if (!this.isAlive) { this.setType(TypeRobot.DEAD); - - return; } if (this.satiety < 50) { if (this.satiety < 0) { isAlive = false; } this.setType(TypeRobot.HUNGRY); - } + } + + private boolean needSkipUpdate() { + return !this.isAlive || this.isTargetAchieved; + } + + private void interactionWithEnvironment() { double distance = distance(target.getX(), target.getY(), getPositionX(), getPositionY()); this.isTargetAchieved = false; if (distance < 0.5) { this.isTargetAchieved = true; this.onTargetAchieved(); - - return; } + } + + private void transformRobot() { double angleToTarget = angleTo(getPositionX(), getPositionY(), target.getX(), target.getY()); double angularVelocity = 0; @@ -201,7 +231,6 @@ public void update() { } moveRobot(Robot.maxVelocity, angularVelocity, 10); - } @Override @@ -218,7 +247,7 @@ private void onTargetAchieved() { this.setTarget(new Point((int) (Math.random() * dimension.width), (int) (Math.random() * dimension.height))); this.satiety += 25; if (this.satiety > 50) { - this.setRandomType(); + this.setType(TypeRobot.CALM); } } @@ -231,4 +260,14 @@ public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals("set dimension")) setDimension((Dimension) evt.getNewValue()); } + + public void setTargetPosition(Point targetPosition) { + this.targetPosition = targetPosition; + } + + private final ArrayList m_PositionWindowObservers = new ArrayList(); + + public void addObserver(GameVisualizer observer) { + m_PositionWindowObservers.add(observer); + } } diff --git a/robots/src/main/java/model/RobotModel.java b/robots/src/main/java/model/RobotModel.java deleted file mode 100644 index 952ba599b..000000000 --- a/robots/src/main/java/model/RobotModel.java +++ /dev/null @@ -1,64 +0,0 @@ -package model; - -import java.util.Observable; - -import static main.java.tools.MathTools.*; - -public class RobotModel extends Observable { - private volatile double m_robotPositionX = 100; - private volatile double m_robotPositionY = 100; - private volatile double m_robotDirection = 0; - public static final double maxVelocity = 0.1; - public static final double maxAngularVelocity = 0.001; - private final TargetModel targetModel; - public final static String ROBOT_POSITION_CHANGED = "The robot's position has changed"; - - public RobotModel(TargetModel targetModel) { - this.targetModel = targetModel; - } - - public double getM_robotPositionX() { - return m_robotPositionX; - } - - public double getM_robotPositionY() { - return m_robotPositionY; - } - - public double getM_robotDirection() { - return m_robotDirection; - } - - public void moveRobot(double velocity, double angularVelocity, double duration) { - velocity = applyLimits(velocity, 0, maxVelocity); - angularVelocity = applyLimits(angularVelocity, -maxAngularVelocity, maxAngularVelocity); - double newX = m_robotPositionX + velocity / angularVelocity * - (Math.sin(m_robotDirection + angularVelocity * duration) - - Math.sin(m_robotDirection)); - double newY = m_robotPositionY - velocity / angularVelocity * - (Math.cos(m_robotDirection + angularVelocity * duration) - - Math.cos(m_robotDirection)); - - if (!Double.isFinite(newX)) newX = m_robotPositionX + velocity * duration * Math.cos(m_robotDirection); - if (!Double.isFinite(newY)) newY = m_robotPositionY + velocity * duration * Math.sin(m_robotDirection); - - m_robotPositionX = newX; - m_robotPositionY = newY; - m_robotDirection = asNormalizedRadians(m_robotDirection + angularVelocity * duration); - setChanged(); - notifyObservers(ROBOT_POSITION_CHANGED); - } - - public void updateRobotPosition() { - double distance = distance(targetModel.getTargetX(), targetModel.getTargetY(), m_robotPositionX, m_robotPositionY); - if (distance < 0.5) return; - - double angleToTarget = angleTo(m_robotPositionX, m_robotPositionY, targetModel.getTargetX(), targetModel.getTargetY()); - double angularVelocity = 0; - if (angleToTarget > m_robotDirection) angularVelocity = maxAngularVelocity; - if (angleToTarget < m_robotDirection) angularVelocity = -maxAngularVelocity; - if (Math.abs(angleToTarget - m_robotDirection) > Math.PI) angularVelocity = -angularVelocity; - moveRobot(maxVelocity, angularVelocity, 10); - - } -} diff --git a/robots/src/main/java/model/Target.java b/robots/src/main/java/model/Target.java index 3bbb9442b..8eb617013 100644 --- a/robots/src/main/java/model/Target.java +++ b/robots/src/main/java/model/Target.java @@ -1,10 +1,13 @@ -package model; +package main.java.model; import java.awt.*; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeSupport; -public class Target { +public class Target implements Entity { private volatile int x; private volatile int y; + private Target target; public Target() { this.x = 100; @@ -35,6 +38,7 @@ public int getY() { public void setTargetPosition(Point p) { setX(p.x); setY(p.y); + this.target = new Target(p.x, p.y); } @@ -43,4 +47,32 @@ public boolean isPositionCorrect(Dimension dimension) { return this.x <= dimension.width && this.y <= dimension.height; } + @Override + public void update() { + + } + + @Override + public void onStart(PropertyChangeSupport publisher) { + + } + + @Override + public void onFinish(PropertyChangeSupport publisher) { + + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + + } + + + public Target getTarget() { + return target; + } + + public void setTarget(Target target) { + this.target = target; + } } diff --git a/robots/src/main/java/model/TargetModel.java b/robots/src/main/java/model/TargetModel.java deleted file mode 100644 index bf62915ad..000000000 --- a/robots/src/main/java/model/TargetModel.java +++ /dev/null @@ -1,21 +0,0 @@ -package model; - -import java.awt.*; - -public class TargetModel { - private volatile int m_targetPositionX = 150; - private volatile int m_targetPositionY = 100; - - public void setTargetPosition(Point p) { - m_targetPositionX = p.x; - m_targetPositionY = p.y; - } - - public int getTargetX() { - return m_targetPositionX; - } - - public int getTargetY() { - return m_targetPositionY; - } -} diff --git a/robots/src/main/java/model/TypeRobot.java b/robots/src/main/java/model/TypeRobot.java index e733f7891..b72a0115b 100644 --- a/robots/src/main/java/model/TypeRobot.java +++ b/robots/src/main/java/model/TypeRobot.java @@ -12,8 +12,26 @@ public enum TypeRobot { private static final Random RANDOM = new Random(); private static final List values = List.of(values()); + public static final int FAT = 0; + public static final int NORMAL = 1; + public static final int HUNG = 2; + + public static final int MAX_SATIETY = 100; + public static final int MEDIUM_SATIETY = 50; + + public static TypeRobot randomType() { - return values.get(RANDOM.nextInt(values().length - 2)); + return TypeRobot.values()[(int) (Math.random() * TypeRobot.values().length)]; + } + + public static int getTypeBySatiety(int satiety) { + if (satiety >= TypeRobot.MAX_SATIETY) { + return TypeRobot.FAT; + } else if (satiety >= TypeRobot.MEDIUM_SATIETY) { + return TypeRobot.NORMAL; + } else { + return TypeRobot.HUNG; + } } TypeRobot(Color color) { diff --git a/robots/src/main/java/tools/DrawTools.java b/robots/src/main/java/tools/DrawTools.java deleted file mode 100644 index dae43b4f9..000000000 --- a/robots/src/main/java/tools/DrawTools.java +++ /dev/null @@ -1,13 +0,0 @@ -package main.java.tools; - -import java.awt.*; - -public class DrawTools { - public static void fillOval(Graphics g, int centerX, int centerY, int diam1, int diam2) { - g.fillOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, diam2); - } - - public static void drawOval(Graphics g, int centerX, int centerY, int diam1, int diam2) { - g.drawOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, diam2); - } -} diff --git a/robots/src/main/java/view/GameDrawer.java b/robots/src/main/java/view/GameDrawer.java index 5d8991dcb..93c2fc185 100644 --- a/robots/src/main/java/view/GameDrawer.java +++ b/robots/src/main/java/view/GameDrawer.java @@ -1,6 +1,6 @@ package main.java.view; -import model.Entity; +import main.java.model.Entity; import java.awt.*; diff --git a/robots/src/main/java/view/GameView.java b/robots/src/main/java/view/GameView.java index c53358517..def76f25c 100644 --- a/robots/src/main/java/view/GameView.java +++ b/robots/src/main/java/view/GameView.java @@ -1,12 +1,11 @@ package main.java.view; -import model.Entity; -import model.Model; -import model.Target; +import main.java.model.Entity; +import main.java.model.Model; +import main.java.model.Target; import javax.swing.*; import java.awt.*; -import java.util.ArrayList; import java.util.HashMap; import java.util.Map; public class GameView extends JPanel { @@ -24,6 +23,7 @@ public GameView(Model gameModel) { } + public void updateView() { onRedrawEvent(); } @@ -38,8 +38,8 @@ public void paint(Graphics g) { Graphics2D g2d = (Graphics2D) g; RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHints(rh); - ArrayList entities = (ArrayList) gameModel.getEntities(); - for (Entity entity : entities) { + + for (Entity entity : gameModel.getEntities()) { map.get(entity.getClass()).draw(g2d, entity); map.get(Target.class).draw(g2d, entity); } diff --git a/robots/src/main/java/view/RobotDrawer.java b/robots/src/main/java/view/RobotDrawer.java index ca98a56dc..e41afbd65 100644 --- a/robots/src/main/java/view/RobotDrawer.java +++ b/robots/src/main/java/view/RobotDrawer.java @@ -1,7 +1,5 @@ package main.java.view; - -import model.Robot; -import model.Entity; +import main.java.model.Entity; import model.TypeRobot; import java.awt.*; import java.awt.geom.AffineTransform; @@ -10,7 +8,7 @@ public class RobotDrawer extends GameDrawer { @Override public void draw(Graphics2D g, Entity entity) { - Robot robot = (Robot) entity; + Robot robot = (Robot)entity; AffineTransform oldTransform = g.getTransform(); int robotCenterX = (int) (Math.round(robot.getPositionX())); int robotCenterY = (int) (Math.round(robot.getPositionY())); diff --git a/robots/src/main/java/view/TargetDrawer.java b/robots/src/main/java/view/TargetDrawer.java index 9da29f084..22b5c0d25 100644 --- a/robots/src/main/java/view/TargetDrawer.java +++ b/robots/src/main/java/view/TargetDrawer.java @@ -1,15 +1,13 @@ package main.java.view; -import model.Entity; -import model.Robot; -import model.Target; +import main.java.model.Entity; +import main.java.model.Target; import java.awt.*; public class TargetDrawer extends GameDrawer { - @Override public void draw(Graphics2D g, Entity entity) { - Target target = ((Robot) entity).getTarget(); + Target target = ((Target) entity).getTarget(); g.setColor(Color.GREEN); fillOval(g, target.getX(), target.getY(), 5, 5); g.setColor(Color.BLACK); diff --git a/robots/src/main/java/view/ViewModel.java b/robots/src/main/java/view/ViewModel.java index f30db5da5..21fdca177 100644 --- a/robots/src/main/java/view/ViewModel.java +++ b/robots/src/main/java/view/ViewModel.java @@ -1,7 +1,8 @@ package main.java.view; import main.java.gui.GameWindow; -import model.Model; +import main.java.model.Model; + import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.MouseAdapter; From 99a431a6d4b0b064d777508a940678c0a03c3b39 Mon Sep 17 00:00:00 2001 From: vdrnvdrn Date: Mon, 20 Nov 2023 20:57:06 +0500 Subject: [PATCH 3/5] temp --- .idea/.gitignore | 3 +++ .idea/.name | 1 + .idea/misc.xml | 6 ++++++ .idea/vcs.xml | 6 ++++++ robots/src/main/java/gui/RobotsProgram.java | 19 +++++++++++++------ 5 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/.name create mode 100644 .idea/misc.xml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..26d33521a --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 000000000..78d51c468 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +misc.xml \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 000000000..e304627cc --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..35eb1ddfb --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/robots/src/main/java/gui/RobotsProgram.java b/robots/src/main/java/gui/RobotsProgram.java index 8c5b688af..f09ac8521 100644 --- a/robots/src/main/java/gui/RobotsProgram.java +++ b/robots/src/main/java/gui/RobotsProgram.java @@ -1,7 +1,9 @@ package main.java.gui; -import main.java.model.Model; +import model.RobotModel; +import model.TargetModel; import main.java.view.GameView; +import model.Model; import main.java.view.ViewModel; import javax.swing.*; import java.awt.*; @@ -13,18 +15,23 @@ public static void main(String[] args) { } catch (Exception e) { e.printStackTrace(); } - Model gameModel = new Model(); GameView gameView = new GameView(gameModel); GameWindow gameWindow = new GameWindow(gameView); - ViewModel viewModel = new ViewModel(gameModel, gameWindow); - viewModel = new ViewModel(gameModel, gameWindow); + TargetModel targetModel = new TargetModel(); + RobotModel robotModel = new RobotModel(targetModel); + + GameVisualizer gameVisualizer = new GameVisualizer(robotModel, targetModel); + PositionWindow positionWindow = new PositionWindow(robotModel, 800, 600); + gameVisualizer.onRedrawEvent(); + positionWindow.updateCoords(); + + ViewModel viewModel = new ViewModel(gameModel, gameWindow); - ViewModel finalViewModel = viewModel; SwingUtilities.invokeLater(() -> { - MainApplicationFrame frame = new MainApplicationFrame(finalViewModel); + MainApplicationFrame frame = new MainApplicationFrame(viewModel); frame.pack(); frame.setVisible(true); frame.setExtendedState(Frame.MAXIMIZED_BOTH); From aabe3c548afd61c97dc7d613b839fea868485580 Mon Sep 17 00:00:00 2001 From: vdrnvdrn Date: Tue, 21 Nov 2023 00:12:26 +0500 Subject: [PATCH 4/5] try again.. --- .idea/compiler.xml | 13 + .idea/encodings.xml | 7 + .idea/jarRepositories.xml | 20 ++ .idea/misc.xml | 8 + .idea/uiDesigner.xml | 124 +++++++++ pom.xml | 17 ++ robots/src/main/java/gui/GameVisualizer.java | 87 ------ robots/src/main/java/gui/GameWindow.java | 12 +- robots/src/main/java/gui/LogWindow.java | 40 +-- .../main/java/gui/MainApplicationFrame.java | 77 +++--- robots/src/main/java/gui/PositionWindow.java | 51 ++-- robots/src/main/java/gui/RobotsProgram.java | 33 +-- robots/src/main/java/gui/Translatable.java | 2 +- .../src/main/java/log/LogChangeListener.java | 5 +- robots/src/main/java/log/LogEntry.java | 24 +- robots/src/main/java/log/LogLevel.java | 14 +- robots/src/main/java/log/LogWindowSource.java | 63 +++-- robots/src/main/java/log/Logger.java | 24 +- robots/src/main/java/model/Entity.java | 6 +- robots/src/main/java/model/GameModel.java | 81 ++++++ robots/src/main/java/model/Model.java | 72 ----- robots/src/main/java/model/Robot.java | 247 +++++++----------- robots/src/main/java/model/Target.java | 36 +-- robots/src/main/java/model/TypeRobot.java | 34 +-- robots/src/main/java/tools/MathTools.java | 36 --- robots/src/main/java/view/GameView.java | 53 ++-- robots/src/main/java/view/RobotDrawer.java | 27 +- robots/src/main/java/view/TargetDrawer.java | 22 +- robots/src/main/java/view/ViewModel.java | 62 ++--- 29 files changed, 633 insertions(+), 664 deletions(-) create mode 100644 .idea/compiler.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/uiDesigner.xml create mode 100644 pom.xml delete mode 100644 robots/src/main/java/gui/GameVisualizer.java create mode 100644 robots/src/main/java/model/GameModel.java delete mode 100644 robots/src/main/java/model/Model.java delete mode 100644 robots/src/main/java/tools/MathTools.java diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 000000000..6834da5ca --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 000000000..aa00ffab7 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 000000000..712ab9d98 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index e304627cc..59ad337eb 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,5 +1,13 @@ + + + + diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 000000000..2b63946d5 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 000000000..68a6b6524 --- /dev/null +++ b/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + org.example + Robots + 1.0-SNAPSHOT + + + 18 + 18 + UTF-8 + + + \ No newline at end of file diff --git a/robots/src/main/java/gui/GameVisualizer.java b/robots/src/main/java/gui/GameVisualizer.java deleted file mode 100644 index fa4c738ea..000000000 --- a/robots/src/main/java/gui/GameVisualizer.java +++ /dev/null @@ -1,87 +0,0 @@ -package main.java.gui; - -import main.java.model.Robot; -import main.java.model.Target; - -import java.awt.Color; -import java.awt.EventQueue; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.util.Observable; -import java.util.Observer; - -import javax.swing.JPanel; - -import static main.java.tools.MathTools.*; - - -public class GameVisualizer extends JPanel implements Observer { - private final Robot robotModel; - private final Target targetModel; - - public GameVisualizer(Robot robotModel, Target targetModel) { - this.robotModel = robotModel; - this.targetModel = targetModel; - robotModel.addObserver(this); - addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - targetModel.setTargetPosition(e.getPoint()); - repaint(); - } - }); - setDoubleBuffered(true); - } - - - protected void onRedrawEvent() { - EventQueue.invokeLater(this::repaint); - } - - @Override - public void update(Observable o, Object arg) { - if (arg.equals(Robot.ROBOT_POSITION_CHANGED)) EventQueue.invokeLater(this::onRedrawEvent); - } - - - @Override - public void paint(Graphics g) { - super.paint(g); - Graphics2D g2d = (Graphics2D) g.create(); - try { - drawRobot(g2d, robotModel); - drawTarget(g2d, targetModel); - } finally { - g2d.dispose(); - } - } - - private void drawTarget(Graphics2D g, Target targetModel) { - int targetX = targetModel.getTargetX(); - int targetY = targetModel.getTargetY(); - AffineTransform t = new AffineTransform(); - g.setTransform(t); - g.setColor(Color.GREEN); - fillOval(g, targetX, targetY, 5, 5); - g.setColor(Color.BLACK); - drawOval(g, targetX, targetY, 5, 5); - } - - private void drawRobot(Graphics2D g, Robot robotModel) { - int robotCenterX = round(robotModel.getM_robotPositionX()); - int robotCenterY = round(robotModel.getM_robotPositionY()); - AffineTransform t = AffineTransform.getRotateInstance(robotModel.getM_robotDirection(), robotCenterX, robotCenterY); - g.setTransform(t); - g.setColor(Color.MAGENTA); - fillOval(g, robotCenterX, robotCenterY, 30, 10); - g.setColor(Color.BLACK); - drawOval(g, robotCenterX, robotCenterY, 30, 10); - g.setColor(Color.WHITE); - fillOval(g, robotCenterX + 10, robotCenterY, 5, 5); - g.setColor(Color.BLACK); - drawOval(g, robotCenterX + 10, robotCenterY, 5, 5); - } -} diff --git a/robots/src/main/java/gui/GameWindow.java b/robots/src/main/java/gui/GameWindow.java index 8208d345a..76854c1ec 100644 --- a/robots/src/main/java/gui/GameWindow.java +++ b/robots/src/main/java/gui/GameWindow.java @@ -1,10 +1,10 @@ package main.java.gui; +import java.awt.BorderLayout; +import javax.swing.JInternalFrame; +import javax.swing.JPanel; import main.java.view.GameView; -import javax.swing.*; -import java.awt.*; - public class GameWindow extends JInternalFrame { private final GameView gameView; @@ -12,9 +12,9 @@ public GameWindow(GameView gameView) { super("Игровое поле", true, true, true, true); this.gameView = gameView; JPanel panel = new JPanel(new BorderLayout()); - panel.add(this.gameView, BorderLayout.CENTER); - getContentPane().add(panel); - pack(); + panel.add(this.gameView, "Center"); + this.getContentPane().add(panel); + this.pack(); } public GameView getGameView() { diff --git a/robots/src/main/java/gui/LogWindow.java b/robots/src/main/java/gui/LogWindow.java index 40487fd4f..b3ba182c9 100644 --- a/robots/src/main/java/gui/LogWindow.java +++ b/robots/src/main/java/gui/LogWindow.java @@ -3,49 +3,49 @@ import java.awt.BorderLayout; import java.awt.EventQueue; import java.awt.TextArea; +import java.util.Iterator; import java.util.ResourceBundle; - import javax.swing.JInternalFrame; import javax.swing.JPanel; - import main.java.log.LogChangeListener; import main.java.log.LogEntry; import main.java.log.LogWindowSource; public class LogWindow extends JInternalFrame implements LogChangeListener, Translatable { - private LogWindowSource m_logSource; - private TextArea m_logContent; + private LogWindowSource mLogSource; + private TextArea mLogContent; public LogWindow(LogWindowSource logSource) { super("Протокол работы", true, true, true, true); - m_logSource = logSource; - m_logSource.registerListener(this); - m_logContent = new TextArea(""); - m_logContent.setSize(200, 500); - + this.mLogSource = logSource; + this.mLogSource.registerListener(this); + this.mLogContent = new TextArea(""); + this.mLogContent.setSize(200, 500); JPanel panel = new JPanel(new BorderLayout()); - panel.add(m_logContent, BorderLayout.CENTER); - getContentPane().add(panel); - pack(); - updateLogContent(); + panel.add(this.mLogContent, "Center"); + this.getContentPane().add(panel); + this.pack(); + this.updateLogContent(); } private void updateLogContent() { StringBuilder content = new StringBuilder(); - for (LogEntry entry : m_logSource.all()) { + Iterator var2 = this.mLogSource.all().iterator(); + + while(var2.hasNext()) { + LogEntry entry = (LogEntry)var2.next(); content.append(entry.getMessage()).append("\n"); } - m_logContent.setText(content.toString()); - m_logContent.invalidate(); + + this.mLogContent.setText(content.toString()); + this.mLogContent.invalidate(); } - @Override public void onLogChanged() { EventQueue.invokeLater(this::updateLogContent); } - @Override - public void translate(ResourceBundle bundle) { - setTitle(bundle.getString("logWindowHeader")); + public void setTranslate(ResourceBundle bundle) { + this.setTitle(bundle.getString("logWindowHeader")); } } diff --git a/robots/src/main/java/gui/MainApplicationFrame.java b/robots/src/main/java/gui/MainApplicationFrame.java index 02b6692b3..f5185185d 100644 --- a/robots/src/main/java/gui/MainApplicationFrame.java +++ b/robots/src/main/java/gui/MainApplicationFrame.java @@ -1,88 +1,82 @@ package main.java.gui; +import java.awt.Dimension; +import java.awt.Toolkit; +import java.awt.event.ActionListener; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; import main.java.log.Logger; import main.java.view.ViewModel; -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; public class MainApplicationFrame extends JFrame { private final JDesktopPane desktopPane = new JDesktopPane(); public MainApplicationFrame(ViewModel gameViewModel) { - int inset = 50; Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - setBounds(inset, inset, - screenSize.width - inset * 2, - screenSize.height - inset * 2); - - setContentPane(desktopPane); - - LogWindow logWindow = createLogWindow(); - addWindow(logWindow); - + this.setBounds(inset, inset, screenSize.width - inset * 2, screenSize.height - inset * 2); + this.setContentPane(this.desktopPane); + LogWindow logWindow = this.createLogWindow(); + this.addWindow(logWindow); GameWindow gameWindow = gameViewModel.getGameWindow(); - addWindow(gameWindow); - - setJMenuBar(generateMenuBar()); - setDefaultCloseOperation(EXIT_ON_CLOSE); + this.addWindow(gameWindow); + this.setJMenuBar(this.generateMenuBar()); + this.setDefaultCloseOperation(3); } protected LogWindow createLogWindow() { LogWindow logWindow = new LogWindow(Logger.getDefaultLogSource()); logWindow.setLocation(610, 0); logWindow.setSize(300, 800); - setMinimumSize(logWindow.getSize()); + this.setMinimumSize(logWindow.getSize()); logWindow.pack(); Logger.debug("Протокол работает"); return logWindow; } protected void addWindow(JInternalFrame frame) { - desktopPane.add(frame); + this.desktopPane.add(frame); frame.setVisible(true); } private JMenu createMenu(String nameOfMenu, String description, int mnemonic) { JMenu lookAndFeelMenu = new JMenu(nameOfMenu); - lookAndFeelMenu.setMnemonic(KeyEvent.VK_V); - lookAndFeelMenu.getAccessibleContext().setAccessibleDescription( - description); + lookAndFeelMenu.setMnemonic(86); + lookAndFeelMenu.getAccessibleContext().setAccessibleDescription(description); return lookAndFeelMenu; } private JMenuItem createMenuItem(String name, ActionListener l) { - JMenuItem systemLookAndFeel = new JMenuItem(name, KeyEvent.VK_S); + JMenuItem systemLookAndFeel = new JMenuItem(name, 83); systemLookAndFeel.addActionListener(l); - return systemLookAndFeel; } private JMenuBar generateMenuBar() { JMenuBar menuBar = new JMenuBar(); - - JMenu lookAndFeelMenu = createMenu("Режим отображения", - "Управление режимом отображения приложения", KeyEvent.VK_V); - JMenuItem systemLookAndFeel = createMenuItem("Системная схема", (event) -> { - setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + JMenu lookAndFeelMenu = this.createMenu("Режим отображения", "Управление режимом отображения приложения", 86); + JMenuItem systemLookAndFeel = this.createMenuItem("Системная схема", (event) -> { + this.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); this.invalidate(); }); lookAndFeelMenu.add(systemLookAndFeel); - - JMenuItem crossplatformLookAndFeel = createMenuItem("Универсальная схема", (event) -> { - setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); + JMenuItem crossplatformLookAndFeel = this.createMenuItem("Универсальная схема", (event) -> { + this.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); this.invalidate(); }); lookAndFeelMenu.add(crossplatformLookAndFeel); - - JMenu testMenu = createMenu("Тесты", "Тестовые команды", KeyEvent.VK_S); - - JMenuItem addLogMessageItem = createMenuItem("Сообщение в лог", - (event) -> Logger.debug("Новая строка")); + JMenu testMenu = this.createMenu("Тесты", "Тестовые команды", 83); + JMenuItem addLogMessageItem = this.createMenuItem("Сообщение в лог", (event) -> { + Logger.debug("Новая строка"); + }); testMenu.add(addLogMessageItem); - menuBar.add(lookAndFeelMenu); menuBar.add(testMenu); return menuBar; @@ -92,9 +86,8 @@ private void setLookAndFeel(String className) { try { UIManager.setLookAndFeel(className); SwingUtilities.updateComponentTreeUI(this); - } catch (ClassNotFoundException | InstantiationException - | IllegalAccessException | UnsupportedLookAndFeelException e) { - // just ignore + } catch (InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException | ClassNotFoundException var3) { } + } } diff --git a/robots/src/main/java/gui/PositionWindow.java b/robots/src/main/java/gui/PositionWindow.java index 927603fe6..efa17c83e 100644 --- a/robots/src/main/java/gui/PositionWindow.java +++ b/robots/src/main/java/gui/PositionWindow.java @@ -1,45 +1,48 @@ package main.java.gui; -import java.util.ArrayList; +import java.awt.BorderLayout; +import java.awt.EventQueue; import java.util.Observable; import java.util.Observer; -import javax.swing.*; -import java.awt.*; import java.util.ResourceBundle; +import javax.swing.JInternalFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import main.java.model.Robot; public class PositionWindow extends JInternalFrame implements Observer, Translatable { private final JLabel labelX; private final JLabel labelY; - private final Robot m_RobotModel; + private final Robot robot; - - public PositionWindow(Robot robotModel, int width, int height) { + public PositionWindow(Robot robot, int width, int height) { super("Координаты робота", true, true, true, true); - m_RobotModel = robotModel; + this.robot = robot; JPanel panel = new JPanel(new BorderLayout()); - m_RobotModel.addObserver(this); - labelX = new JLabel("X: %f".formatted(m_RobotModel.getM_robotPositionX())); - labelY = new JLabel("Y: %f".formatted(m_RobotModel.getM_robotPositionY())); - panel.add(labelX, BorderLayout.BEFORE_FIRST_LINE); - panel.add(labelY, BorderLayout.CENTER); - getContentPane().add(panel); - pack(); - setSize(width, height); - setLocation(1600, 50); + robot.addObserver(this); + this.labelX = new JLabel("X: %f".formatted(robot.getPositionX())); + this.labelY = new JLabel("Y: %f".formatted(robot.getPositionY())); + panel.add(this.labelX, "First"); + panel.add(this.labelY, "Center"); + this.getContentPane().add(panel); + this.pack(); + this.setSize(width, height); + this.setLocation(1600, 50); } - @Override public void update(Observable o, Object arg) { - if (arg.equals(Robot.ROBOT_POSITION_CHANGED)) EventQueue.invokeLater(this::updateCoords); + if (arg.equals("The robot's position has changed")) { + EventQueue.invokeLater(this::updateCoords); + } + } - void updateCoords() { - labelX.setText("X: %f".formatted(m_RobotModel.getM_robotPositionX())); - labelY.setText("Y: %f".formatted(m_RobotModel.getM_robotPositionY())); + public void updateCoords() { + this.labelX.setText("X: %f".formatted(this.robot.getPositionX())); + this.labelY.setText("Y: %f".formatted(this.robot.getPositionY())); } - @Override - public void translate(ResourceBundle bundle) { - setTitle(bundle.getString("positionWindowHeader")); + public void setTranslate(ResourceBundle bundle) { + this.setTitle(bundle.getString("positionWindowHeader")); } } diff --git a/robots/src/main/java/gui/RobotsProgram.java b/robots/src/main/java/gui/RobotsProgram.java index f09ac8521..1b0bee484 100644 --- a/robots/src/main/java/gui/RobotsProgram.java +++ b/robots/src/main/java/gui/RobotsProgram.java @@ -1,40 +1,35 @@ package main.java.gui; -import model.RobotModel; -import model.TargetModel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import main.java.model.GameModel; +import main.java.model.Robot; import main.java.view.GameView; -import model.Model; import main.java.view.ViewModel; -import javax.swing.*; -import java.awt.*; public class RobotsProgram { + public RobotsProgram() { + } + public static void main(String[] args) { try { UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); - } catch (Exception e) { - e.printStackTrace(); + } catch (Exception var7) { + var7.printStackTrace(); } - Model gameModel = new Model(); + + GameModel gameModel = new GameModel(); GameView gameView = new GameView(gameModel); GameWindow gameWindow = new GameWindow(gameView); - - - TargetModel targetModel = new TargetModel(); - RobotModel robotModel = new RobotModel(targetModel); - - GameVisualizer gameVisualizer = new GameVisualizer(robotModel, targetModel); - PositionWindow positionWindow = new PositionWindow(robotModel, 800, 600); - gameVisualizer.onRedrawEvent(); + Robot robot = new Robot(); + PositionWindow positionWindow = new PositionWindow(robot, 800, 600); positionWindow.updateCoords(); - ViewModel viewModel = new ViewModel(gameModel, gameWindow); - SwingUtilities.invokeLater(() -> { MainApplicationFrame frame = new MainApplicationFrame(viewModel); frame.pack(); frame.setVisible(true); - frame.setExtendedState(Frame.MAXIMIZED_BOTH); + frame.setExtendedState(6); }); } } diff --git a/robots/src/main/java/gui/Translatable.java b/robots/src/main/java/gui/Translatable.java index 31fb3f0b6..4a6ee20ec 100644 --- a/robots/src/main/java/gui/Translatable.java +++ b/robots/src/main/java/gui/Translatable.java @@ -3,5 +3,5 @@ import java.util.ResourceBundle; public interface Translatable { - void translate(ResourceBundle bundle); + void setTranslate(ResourceBundle var1); } diff --git a/robots/src/main/java/log/LogChangeListener.java b/robots/src/main/java/log/LogChangeListener.java index c9e263260..d9608308c 100644 --- a/robots/src/main/java/log/LogChangeListener.java +++ b/robots/src/main/java/log/LogChangeListener.java @@ -1,6 +1,5 @@ package main.java.log; -public interface LogChangeListener -{ - public void onLogChanged(); +public interface LogChangeListener { + void onLogChanged(); } diff --git a/robots/src/main/java/log/LogEntry.java b/robots/src/main/java/log/LogEntry.java index a29b50e7e..8c6a12eb0 100644 --- a/robots/src/main/java/log/LogEntry.java +++ b/robots/src/main/java/log/LogEntry.java @@ -1,23 +1,19 @@ package main.java.log; -public class LogEntry -{ - private LogLevel m_logLevel; - private String m_strMessage; +public class LogEntry { + private LogLevel mLogLevel; + private String mStrMessage; - public LogEntry(LogLevel logLevel, String strMessage) - { - m_strMessage = strMessage; - m_logLevel = logLevel; + public LogEntry(LogLevel logLevel, String strMessage) { + this.mStrMessage = strMessage; + this.mLogLevel = logLevel; } - public String getMessage() - { - return m_strMessage; + public String getMessage() { + return this.mStrMessage; } - public LogLevel getLevel() - { - return m_logLevel; + public LogLevel getLevel() { + return this.mLogLevel; } } \ No newline at end of file diff --git a/robots/src/main/java/log/LogLevel.java b/robots/src/main/java/log/LogLevel.java index db858dd9f..d6ffe0ad2 100644 --- a/robots/src/main/java/log/LogLevel.java +++ b/robots/src/main/java/log/LogLevel.java @@ -1,7 +1,6 @@ package main.java.log; -public enum LogLevel -{ +public enum LogLevel { Trace(0), Debug(1), Info(2), @@ -11,14 +10,13 @@ public enum LogLevel private int m_iLevel; - private LogLevel(int iLevel) - { - m_iLevel = iLevel; + private LogLevel(int iLevel) { + this.m_iLevel = iLevel; } - public int level() - { - return m_iLevel; + public int level() { + return this.m_iLevel; } } + diff --git a/robots/src/main/java/log/LogWindowSource.java b/robots/src/main/java/log/LogWindowSource.java index a283d2720..8243b2a2c 100644 --- a/robots/src/main/java/log/LogWindowSource.java +++ b/robots/src/main/java/log/LogWindowSource.java @@ -5,61 +5,66 @@ import java.util.concurrent.CopyOnWriteArrayList; public class LogWindowSource { - private final int m_iQueueLength; - - private final ArrayList m_messages; - private final CopyOnWriteArrayList m_listeners; - private volatile LogChangeListener[] m_activeListeners; + private final int mIQueueLength; + private final ArrayList mMessages; + private final CopyOnWriteArrayList mListeners; + private volatile LogChangeListener[] mActivelisteners; public LogWindowSource(int iQueueLength) { - m_iQueueLength = iQueueLength; - m_messages = new ArrayList<>(iQueueLength); - m_listeners = new CopyOnWriteArrayList<>(); + this.mIQueueLength = iQueueLength; + this.mMessages = new ArrayList(iQueueLength); + this.mListeners = new CopyOnWriteArrayList(); } public void registerListener(LogChangeListener listener) { - m_listeners.add(listener); - m_activeListeners = null; - } - - public void unregisterListener(LogChangeListener listener) { - m_listeners.remove(listener); - m_activeListeners = null; + this.mListeners.add(listener); + this.mActivelisteners = null; } public void append(LogLevel logLevel, String strMessage) { LogEntry entry = new LogEntry(logLevel, strMessage); - if (size() >= m_iQueueLength) m_messages.remove(0); - synchronized (this) { - m_messages.add(entry); + if (this.size() >= this.mIQueueLength) { + this.mMessages.remove(0); + } + + synchronized(this) { + this.mMessages.add(entry); } - LogChangeListener[] activeListeners = m_activeListeners; + + LogChangeListener[] activeListeners = this.mActivelisteners; if (activeListeners == null) { - synchronized (m_listeners) { - if (m_activeListeners == null) { - activeListeners = m_listeners.toArray(new LogChangeListener[0]); - m_activeListeners = activeListeners; + synchronized(this.mListeners) { + if (this.mActivelisteners == null) { + activeListeners = (LogChangeListener[])this.mListeners.toArray(new LogChangeListener[0]); + this.mActivelisteners = activeListeners; } } } - for (LogChangeListener listener : activeListeners) { + + LogChangeListener[] var5 = activeListeners; + int var6 = activeListeners.length; + + for(int var7 = 0; var7 < var6; ++var7) { + LogChangeListener listener = var5[var7]; listener.onLogChanged(); } + } public synchronized int size() { - return m_messages.size(); + return this.mMessages.size(); } public synchronized Iterable range(int startFrom, int count) { - if (startFrom < 0 || startFrom >= size()) { + if (startFrom >= 0 && startFrom < this.size()) { + int indexTo = Math.min(startFrom + count, this.size()); + return this.mMessages.subList(startFrom, indexTo); + } else { return Collections.emptyList(); } - int indexTo = Math.min(startFrom + count, size()); - return m_messages.subList(startFrom, indexTo); } public synchronized Iterable all() { - return m_messages; + return this.mMessages; } } diff --git a/robots/src/main/java/log/Logger.java b/robots/src/main/java/log/Logger.java index d7cf78f2f..005635194 100644 --- a/robots/src/main/java/log/Logger.java +++ b/robots/src/main/java/log/Logger.java @@ -1,28 +1,16 @@ package main.java.log; -public final class Logger -{ - private static final LogWindowSource defaultLogSource; - static { - defaultLogSource = new LogWindowSource(100); - } +public final class Logger { + private static final LogWindowSource defaultLogSource = new LogWindowSource(100); - private Logger() - { + private Logger() { } - public static void debug(String strMessage) - { + public static void debug(String strMessage) { defaultLogSource.append(LogLevel.Debug, strMessage); } - public static void error(String strMessage) - { - defaultLogSource.append(LogLevel.Error, strMessage); - } - - public static LogWindowSource getDefaultLogSource() - { + public static LogWindowSource getDefaultLogSource() { return defaultLogSource; } -} +} \ No newline at end of file diff --git a/robots/src/main/java/model/Entity.java b/robots/src/main/java/model/Entity.java index 1bc26e146..c1b7d3f7b 100644 --- a/robots/src/main/java/model/Entity.java +++ b/robots/src/main/java/model/Entity.java @@ -6,7 +6,7 @@ public interface Entity extends PropertyChangeListener { void update(); - void onStart(PropertyChangeSupport publisher); + default void onStart(PropertyChangeSupport var1) { - void onFinish(PropertyChangeSupport publisher); -} \ No newline at end of file + } +} diff --git a/robots/src/main/java/model/GameModel.java b/robots/src/main/java/model/GameModel.java new file mode 100644 index 000000000..ad2105cea --- /dev/null +++ b/robots/src/main/java/model/GameModel.java @@ -0,0 +1,81 @@ +package main.java.model; + +import java.awt.Dimension; +import java.awt.Point; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeSupport; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +public class GameModel implements Entity { + public static final String CHANGE_SATIETY_EVENT = "change satiety"; + public static final String SET_DIMENSION_EVENT = "set dimension"; + public static final String NEW_POINT_EVENT = "new point"; + private final List entities = this.initStateOfBacterias(2); + private final PropertyChangeSupport support = new PropertyChangeSupport(this); + + public GameModel() { + Timer timer = initTimer(); + timer.schedule(new TimerTask() { + public void run() { + System.out.println("timer"); + GameModel.this.support.firePropertyChange("change satiety", (Object)null, -10); + } + }, 0L, 1500L); + } + + private static Timer initTimer() { + return new Timer("satiety generator", true); + } + + public void setDimension(Dimension dimension) { + this.support.firePropertyChange("set dimension", (Object)null, dimension); + } + + public Dimension getDimension() { + return ((Robot)this.entities.get(0)).getDimension(); + } + + public void updateModel() { + Iterator var1 = this.entities.iterator(); + + while(var1.hasNext()) { + Entity entity = (Entity)var1.next(); + entity.update(); + } + + } + + public List getEntities() { + return this.entities; + } + + public void setTarget(Point point) { + this.support.firePropertyChange("new point", (Object)null, point); + } + + public List initStateOfBacterias(int amount) { + List entityList = new ArrayList(); + + for(int i = 0; i < amount; ++i) { + Robot robot = new Robot(Math.random() * 400.0, Math.random() * 400.0); + robot.setTarget(new Point((int)(Math.random() * 400.0), (int)(Math.random() * 400.0))); + robot.onStart(this.support); + entityList.add(robot); + } + + return entityList; + } + + public void update() { + } + + public void onStart(PropertyChangeSupport publisher) { + } + + public void propertyChange(PropertyChangeEvent evt) { + } +} diff --git a/robots/src/main/java/model/Model.java b/robots/src/main/java/model/Model.java deleted file mode 100644 index 6683d5311..000000000 --- a/robots/src/main/java/model/Model.java +++ /dev/null @@ -1,72 +0,0 @@ -package main.java.model; - -import java.awt.*; -import java.beans.PropertyChangeSupport; -import java.util.ArrayList; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; - -public class Model { - private final List entities; - private final PropertyChangeSupport support; - - public static final String NEW_POINT_EVENT = "new point"; - public static final String CHANGE_SATIETY = "change satiety"; - public static final String SATIETY_GENERATOR = "satiety generator"; - public static final String SET_DIMENSION = "set dimension"; - - - public Model() { - this.support = new PropertyChangeSupport(this); - this.entities = initStateOfBacterias(2); - - Timer timer = initTimer(); - timer.schedule(new TimerTask() { - @Override - public void run() { - System.out.println("timer"); - support.firePropertyChange(CHANGE_SATIETY, null, -10); - } - }, 0, 1500); - } - - private static Timer initTimer() { - return new Timer(SATIETY_GENERATOR, true); - } - - public void setDimension(Dimension dimension) { - support.firePropertyChange(SET_DIMENSION, null, dimension); - } - - public Dimension getDimension() { - return ((Robot) entities.get(0)).getDimension(); - } - - public void updateModel() { - for (Entity entity : entities) { - entity.update(); - } - } - - public List getEntities() { - return entities; - } - - public void setTarget(Point point) { - support.firePropertyChange(NEW_POINT_EVENT, null, point); - } - - public List initStateOfBacterias(int amount) { - List entityList = new ArrayList<>(); - for (int i = 0; i < amount; i++) { - Robot robot = new Robot(Math.random() * 400, Math.random() * 400); - robot.setTargetPosition(new Point((int) (Math.random() * 400), (int) (Math.random() * 400))); - robot.onStart(support); - entityList.add((Entity) robot); - } - return entityList; - } -} - - diff --git a/robots/src/main/java/model/Robot.java b/robots/src/main/java/model/Robot.java index 9176fc1de..3a9f20892 100644 --- a/robots/src/main/java/model/Robot.java +++ b/robots/src/main/java/model/Robot.java @@ -1,82 +1,58 @@ package main.java.model; -import main.java.gui.GameVisualizer; -import model.TypeRobot; - -import java.awt.*; +import java.awt.Dimension; +import java.awt.Point; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeSupport; -import java.util.ArrayList; - -public class Robot implements Entity { - public static final Object ROBOT_POSITION_CHANGED = "robot position changed"; +import java.util.Observable; + +public class Robot extends Observable implements Entity { + public static final String ROBOT_POSITION_CHANGED = "The robot's position has changed"; + public static final double MAX_VELOCITY = 0.1; + public static final double MAX_ANGULAR_VELOCITY = 0.01; + public static final int INITIAL_SATIETY = 50; + public static final int MAX_SATIETY = 100; private double positionX; private double positionY; private Target target; private Dimension dimension; private volatile double robotDirection; - public static final double maxVelocity = 0.1; - public static final double maxAngularVelocity = 0.01; - private static final int INITIAL_SATIETY = 50; - private static final int MAX_SATIETY = 100; private int satiety; - private model.TypeRobot type; - private boolean isAlive; - private boolean isTargetAchieved; - private Point targetPosition; + private TypeRobot type; + + public Robot() { + this(300.0, 300.0); + } public Robot(double x, double y) { this.positionX = x; this.positionY = y; this.target = new Target(); - this.robotDirection = Math.random() * 10;; + this.robotDirection = Math.random() * 10.0; this.dimension = new Dimension(300, 300); - this.satiety = (int) (INITIAL_SATIETY + Math.random() * (MAX_SATIETY - INITIAL_SATIETY)); - this.isAlive = true; - this.type= model.TypeRobot.randomType(); - } - - public Robot() { - this.positionX = 300; - this.positionY = 300; - this.target = new Target(); - this.robotDirection = 0; - } - - private void setRandomType() { - this.type = model.TypeRobot.randomType(); + this.satiety = (int)(50.0 + Math.random() * 50.0); + this.type = getType(this.satiety); } - public void setType(model.TypeRobot type) { + public void setType(TypeRobot type) { this.type = type; } - public model.TypeRobot getType() { - return type; - } - public int getSatiety() { - return satiety; + public TypeRobot getType() { + return this.type; } -// public TypeRobot getType() { -// if (satiety >= MAX_SATIETY) { -// return TypeRobot.FAT; -// } else if (satiety >= MEDIUM_SATIETY) { -// return TypeRobot.NORMAL; -// } else { -// return TypeRobot.HUNGRY; -// } -// } - public void changeSatiety(int satiety) { this.satiety += satiety; + this.type = getType(this.satiety); } public void setDimension(Dimension dimension) { this.dimension = dimension; - if (!target.isPositionCorrect(dimension)) { - target = new Target((int) (Math.random() * dimension.width), (int) (Math.random() * dimension.height)); + if (!this.target.isPositionCorrect(dimension)) { + this.target = new Target((int)(Math.random() * (double)dimension.width), (int)(Math.random() * (double)dimension.height)); } + } public Dimension getDimension() { @@ -84,7 +60,7 @@ public Dimension getDimension() { } public double getPositionX() { - return positionX; + return this.positionX; } public void setPositionX(double positionX) { @@ -92,7 +68,7 @@ public void setPositionX(double positionX) { } public double getPositionY() { - return positionY; + return this.positionY; } public void setPositionY(double positionY) { @@ -100,7 +76,7 @@ public void setPositionY(double positionY) { } public double getRobotDirection() { - return robotDirection; + return this.robotDirection; } public void setRobotDirection(double robotDirection) { @@ -116,46 +92,47 @@ private static double distance(double x1, double y1, double x2, double y2) { private static double angleTo(double fromX, double fromY, double toX, double toY) { double diffX = toX - fromX; double diffY = toY - fromY; - return asNormalizedRadians(Math.atan2(diffY, diffX)); } private static double asNormalizedRadians(double angle) { - while (angle < 0) { - angle += 2 * Math.PI; + while(angle < 0.0) { + angle += 6.283185307179586; } - while (angle >= 2 * Math.PI) { - angle -= 2 * Math.PI; + + while(angle >= 6.283185307179586) { + angle -= 6.283185307179586; } + return angle; } private double normalizedPositionX(double x) { - if (x < 0) - return 0; - if (x > dimension.width) - return dimension.width; - return x; + if (x < 0.0) { + return 0.0; + } else { + return x > (double)this.dimension.width ? (double)this.dimension.width : x; + } } private double normalizedPositionY(double y) { - if (y < 0) - return 0; - if (y > dimension.height) - return dimension.height; - return y; + if (y < 0.0) { + return 0.0; + } else { + return y > (double)this.dimension.height ? (double)this.dimension.height : y; + } } private static double applyLimits(double value, double min, double max) { - if (value < min) + if (value < min) { return min; - if (value > max) - return max; - return value; + } else { + return value > max ? max : value; + } } public Target getTarget() { - return target; + return this.target; } public void setTarget(Point point) { @@ -163,111 +140,81 @@ public void setTarget(Point point) { } private void moveRobot(double velocity, double angularVelocity, double duration) { - velocity = applyLimits(velocity, 0, Robot.maxVelocity); - angularVelocity = applyLimits(angularVelocity, -Robot.maxAngularVelocity, Robot.maxAngularVelocity); - double newX = getPositionX() + velocity / angularVelocity * - (Math.sin(getRobotDirection() + angularVelocity * duration) - - Math.sin(getRobotDirection())); + velocity = applyLimits(velocity, 0.0, 0.1); + angularVelocity = applyLimits(angularVelocity, -0.01, 0.01); + double newX = this.getPositionX() + velocity / angularVelocity * (Math.sin(this.getRobotDirection() + angularVelocity * duration) - Math.sin(this.getRobotDirection())); if (!Double.isFinite(newX)) { - newX = getPositionX() + velocity * duration * Math.cos(getRobotDirection()); + newX = this.getPositionX() + velocity * duration * Math.cos(this.getRobotDirection()); } - double newY = getPositionY() - velocity / angularVelocity * - (Math.cos(getRobotDirection() + angularVelocity * duration) - - Math.cos(getRobotDirection())); + + double newY = this.getPositionY() - velocity / angularVelocity * (Math.cos(this.getRobotDirection() + angularVelocity * duration) - Math.cos(this.getRobotDirection())); if (!Double.isFinite(newY)) { - newY = getPositionY() + velocity * duration * Math.sin(getRobotDirection()); + newY = this.getPositionY() + velocity * duration * Math.sin(this.getRobotDirection()); } - setPositionX(normalizedPositionX(newX)); - setPositionY(normalizedPositionY(newY)); - double newDirection = asNormalizedRadians(getRobotDirection() + angularVelocity * duration); - setRobotDirection(newDirection); + + this.setPositionX(this.normalizedPositionX(newX)); + this.setPositionY(this.normalizedPositionY(newY)); + double newDirection = asNormalizedRadians(this.getRobotDirection() + angularVelocity * duration); + this.setRobotDirection(newDirection); + this.setChanged(); + this.notifyObservers("The robot's position has changed"); } - @Override public void update() { - updateRobotState(); - if (needSkipUpdate()) { - return; - } - interactionWithEnvironment(); - transformRobot(); - } + if (this.type != TypeRobot.DEAD) { + if (this.interactionWithEnvironment()) { + this.onTargetAchieved(); + } - private void updateRobotState() { - if (!this.isAlive) { - this.setType(TypeRobot.DEAD); - } - if (this.satiety < 50) { - if (this.satiety < 0) { - isAlive = false; + double angleToTarget = angleTo(this.getPositionX(), this.getPositionY(), (double)this.target.getX(), (double)this.target.getY()); + double angularVelocity = 0.0; + if (angleToTarget > this.getRobotDirection()) { + angularVelocity = 0.01; } - this.setType(TypeRobot.HUNGRY); - } - } - private boolean needSkipUpdate() { - return !this.isAlive || this.isTargetAchieved; - } + if (angleToTarget < this.getRobotDirection()) { + angularVelocity = -0.01; + } - private void interactionWithEnvironment() { - double distance = distance(target.getX(), target.getY(), - getPositionX(), getPositionY()); - this.isTargetAchieved = false; - if (distance < 0.5) { - this.isTargetAchieved = true; - this.onTargetAchieved(); + this.moveRobot(0.1, angularVelocity, 10.0); } } - private void transformRobot() { - double angleToTarget = angleTo(getPositionX(), getPositionY(), - target.getX(), target.getY()); - double angularVelocity = 0; - if (angleToTarget > getRobotDirection()) { - angularVelocity = Robot.maxAngularVelocity; - } - if (angleToTarget < getRobotDirection()) { - angularVelocity = -Robot.maxAngularVelocity; - } - - moveRobot(Robot.maxVelocity, angularVelocity, 10); + private boolean interactionWithEnvironment() { + double distance = distance((double)this.target.getX(), (double)this.target.getY(), this.getPositionX(), this.getPositionY()); + return distance < 0.5; } - @Override public void onStart(PropertyChangeSupport publisher) { publisher.addPropertyChangeListener(this); } - @Override - public void onFinish(PropertyChangeSupport publisher) { - publisher.removePropertyChangeListener(this); - } - private void onTargetAchieved() { - this.setTarget(new Point((int) (Math.random() * dimension.width), (int) (Math.random() * dimension.height))); + this.setTarget(new Point((int)(Math.random() * (double)this.dimension.width), (int)(Math.random() * (double)this.dimension.height))); this.satiety += 25; - if (this.satiety > 50) { - this.setType(TypeRobot.CALM); + this.type = getType(this.satiety); + } + + private static TypeRobot getType(int satiety) { + if (satiety > 50) { + return TypeRobot.CALM; + } else { + return satiety <= 0 ? TypeRobot.DEAD : TypeRobot.HUNGRY; } } - @Override public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals("new point")) - setTarget((Point) evt.getNewValue()); - if (evt.getPropertyName().equals("change satiety")) - changeSatiety((int) evt.getNewValue()); - if (evt.getPropertyName().equals("set dimension")) - setDimension((Dimension) evt.getNewValue()); - } + if (evt.getPropertyName().equals("new point")) { + this.setTarget((Point)evt.getNewValue()); + } - public void setTargetPosition(Point targetPosition) { - this.targetPosition = targetPosition; - } + if (evt.getPropertyName().equals("change satiety")) { + this.changeSatiety((Integer)evt.getNewValue()); + } - private final ArrayList m_PositionWindowObservers = new ArrayList(); + if (evt.getPropertyName().equals("set dimension")) { + this.setDimension((Dimension)evt.getNewValue()); + } - public void addObserver(GameVisualizer observer) { - m_PositionWindowObservers.add(observer); } -} +} \ No newline at end of file diff --git a/robots/src/main/java/model/Target.java b/robots/src/main/java/model/Target.java index 8eb617013..4689da897 100644 --- a/robots/src/main/java/model/Target.java +++ b/robots/src/main/java/model/Target.java @@ -1,13 +1,13 @@ package main.java.model; -import java.awt.*; +import java.awt.Dimension; +import java.awt.Point; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeSupport; public class Target implements Entity { private volatile int x; private volatile int y; - private Target target; public Target() { this.x = 100; @@ -28,51 +28,29 @@ public void setY(int y) { } public int getX() { - return x; + return this.x; } public int getY() { - return y; + return this.y; } public void setTargetPosition(Point p) { - setX(p.x); - setY(p.y); - this.target = new Target(p.x, p.y); + this.setX(p.x); + this.setY(p.y); } - - public boolean isPositionCorrect(Dimension dimension) { return this.x <= dimension.width && this.y <= dimension.height; } - @Override public void update() { - } - @Override public void onStart(PropertyChangeSupport publisher) { - - } - - @Override - public void onFinish(PropertyChangeSupport publisher) { - + publisher.addPropertyChangeListener(this); } - @Override public void propertyChange(PropertyChangeEvent evt) { - - } - - - public Target getTarget() { - return target; - } - - public void setTarget(Target target) { - this.target = target; } } diff --git a/robots/src/main/java/model/TypeRobot.java b/robots/src/main/java/model/TypeRobot.java index b72a0115b..5d169b871 100644 --- a/robots/src/main/java/model/TypeRobot.java +++ b/robots/src/main/java/model/TypeRobot.java @@ -1,6 +1,6 @@ -package model; +package main.java.model; -import java.awt.*; +import java.awt.Color; import java.util.List; import java.util.Random; @@ -8,38 +8,20 @@ public enum TypeRobot { CALM(Color.GREEN), HUNGRY(Color.RED), DEAD(Color.BLACK); + private final Color color; private static final Random RANDOM = new Random(); - private static final List values = List.of(values()); - - public static final int FAT = 0; - public static final int NORMAL = 1; - public static final int HUNG = 2; - - public static final int MAX_SATIETY = 100; - public static final int MEDIUM_SATIETY = 50; - + private static final List VALUES = List.of(values()); public static TypeRobot randomType() { - return TypeRobot.values()[(int) (Math.random() * TypeRobot.values().length)]; + return (TypeRobot)VALUES.get(RANDOM.nextInt(values().length - 2)); } - public static int getTypeBySatiety(int satiety) { - if (satiety >= TypeRobot.MAX_SATIETY) { - return TypeRobot.FAT; - } else if (satiety >= TypeRobot.MEDIUM_SATIETY) { - return TypeRobot.NORMAL; - } else { - return TypeRobot.HUNG; - } - } - - TypeRobot(Color color) { + private TypeRobot(Color color) { this.color = color; } - public Color getColor() { - return color; + return this.color; } -} \ No newline at end of file +} diff --git a/robots/src/main/java/tools/MathTools.java b/robots/src/main/java/tools/MathTools.java deleted file mode 100644 index ffe704340..000000000 --- a/robots/src/main/java/tools/MathTools.java +++ /dev/null @@ -1,36 +0,0 @@ -package main.java.tools; - -public class MathTools { - public static double distance(double x1, double y1, double x2, double y2) { - double diffX = x1 - x2; - double diffY = y1 - y2; - return Math.sqrt(diffX * diffX + diffY * diffY); - } - - public static double asNormalizedRadians(double angle) { - while (angle < 0) { - angle += 2 * Math.PI; - } - while (angle >= 2 * Math.PI) { - angle -= 2 * Math.PI; - } - return angle; - } - - public static double angleTo(double fromX, double fromY, double toX, double toY) { - double diffX = toX - fromX; - double diffY = toY - fromY; - - return asNormalizedRadians(Math.atan2(diffY, diffX)); - } - - public static double applyLimits(double value, double min, double max) { - if (value < min) - return min; - return Math.min(value, max); - } - - public static int round(double value) { - return (int) (value + 0.5); - } -} diff --git a/robots/src/main/java/view/GameView.java b/robots/src/main/java/view/GameView.java index def76f25c..bc33ab0b1 100644 --- a/robots/src/main/java/view/GameView.java +++ b/robots/src/main/java/view/GameView.java @@ -1,47 +1,58 @@ package main.java.view; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import javax.swing.BorderFactory; +import javax.swing.JPanel; import main.java.model.Entity; -import main.java.model.Model; +import main.java.model.GameModel; +import main.java.model.Robot; import main.java.model.Target; -import javax.swing.*; -import java.awt.*; -import java.util.HashMap; -import java.util.Map; public class GameView extends JPanel { - private final Model gameModel; + private final GameModel gameModel; private final Map, GameDrawer> map; - public GameView(Model gameModel) { + + public GameView(GameModel gameModel) { this.gameModel = gameModel; - setDoubleBuffered(true); - map = new HashMap<>(); - map.put(new RobotDrawer().getDrawingType(), new RobotDrawer()); - map.put(new TargetDrawer().getDrawingType(), new TargetDrawer()); + this.setDoubleBuffered(true); + this.map = new HashMap(); + this.map.put((new RobotDrawer()).getDrawingType(), new RobotDrawer()); + this.map.put((new TargetDrawer()).getDrawingType(), new TargetDrawer()); this.setPreferredSize(new Dimension(600, 600)); this.setSize(new Dimension(600, 600)); this.setBorder(BorderFactory.createLineBorder(Color.RED)); - } - public void updateView() { - onRedrawEvent(); + this.onRedrawEvent(); } protected void onRedrawEvent() { EventQueue.invokeLater(this::repaint); } - @Override public void paint(Graphics g) { super.paint(g); - Graphics2D g2d = (Graphics2D) g; + Graphics2D g2d = (Graphics2D)g; RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHints(rh); - - for (Entity entity : gameModel.getEntities()) { - map.get(entity.getClass()).draw(g2d, entity); - map.get(Target.class).draw(g2d, entity); + Iterator var4 = this.gameModel.getEntities().iterator(); + + while(var4.hasNext()) { + Entity entity = (Entity)var4.next(); + ((GameDrawer)this.map.get(entity.getClass())).draw(g2d, entity); + if (entity instanceof Robot) { + ((GameDrawer)this.map.get(Target.class)).draw(g2d, ((Robot)entity).getTarget()); + } } + } -} \ No newline at end of file +} diff --git a/robots/src/main/java/view/RobotDrawer.java b/robots/src/main/java/view/RobotDrawer.java index e41afbd65..e2abec51e 100644 --- a/robots/src/main/java/view/RobotDrawer.java +++ b/robots/src/main/java/view/RobotDrawer.java @@ -1,23 +1,25 @@ package main.java.view; -import main.java.model.Entity; -import model.TypeRobot; -import java.awt.*; + +import java.awt.Color; +import java.awt.Graphics2D; import java.awt.geom.AffineTransform; +import main.java.model.Entity; +import main.java.model.Robot; +import main.java.model.TypeRobot; public class RobotDrawer extends GameDrawer { - @Override - public void draw(Graphics2D g, Entity entity) - { + public RobotDrawer() { + } + + public void draw(Graphics2D g, Entity entity) { Robot robot = (Robot)entity; AffineTransform oldTransform = g.getTransform(); - int robotCenterX = (int) (Math.round(robot.getPositionX())); - int robotCenterY = (int) (Math.round(robot.getPositionY())); + int robotCenterX = (int)Math.round(robot.getPositionX()); + int robotCenterY = (int)Math.round(robot.getPositionY()); AffineTransform l = new AffineTransform(oldTransform); - AffineTransform t = AffineTransform.getRotateInstance(robot.getRobotDirection(), robotCenterX, robotCenterY); + AffineTransform t = AffineTransform.getRotateInstance(robot.getRobotDirection(), (double)robotCenterX, (double)robotCenterY); l.concatenate(t); - g.setTransform(l); - g.setColor(robot.getType().getColor()); if (robot.getType().equals(TypeRobot.HUNGRY)) { fillOval(g, robotCenterX, robotCenterY, 20, 10); @@ -46,8 +48,7 @@ public void draw(Graphics2D g, Entity entity) g.setTransform(oldTransform); } - @Override public Class getDrawingType() { return Robot.class; } -} \ No newline at end of file +} diff --git a/robots/src/main/java/view/TargetDrawer.java b/robots/src/main/java/view/TargetDrawer.java index 22b5c0d25..5cc58da8f 100644 --- a/robots/src/main/java/view/TargetDrawer.java +++ b/robots/src/main/java/view/TargetDrawer.java @@ -1,19 +1,25 @@ package main.java.view; +import java.awt.Color; +import java.awt.Graphics2D; import main.java.model.Entity; import main.java.model.Target; -import java.awt.*; - public class TargetDrawer extends GameDrawer { + public TargetDrawer() { + } + public void draw(Graphics2D g, Entity entity) { - Target target = ((Target) entity).getTarget(); - g.setColor(Color.GREEN); - fillOval(g, target.getX(), target.getY(), 5, 5); - g.setColor(Color.BLACK); - drawOval(g, target.getX(), target.getY(), 5, 5); + Target target = (Target)entity; + if (target != null) { + g.setColor(Color.GREEN); + fillOval(g, target.getX(), target.getY(), 5, 5); + g.setColor(Color.BLACK); + drawOval(g, target.getX(), target.getY(), 5, 5); + } + } - @Override + public Class getDrawingType() { return Target.class; } diff --git a/robots/src/main/java/view/ViewModel.java b/robots/src/main/java/view/ViewModel.java index 21fdca177..9ac8c8250 100644 --- a/robots/src/main/java/view/ViewModel.java +++ b/robots/src/main/java/view/ViewModel.java @@ -1,77 +1,69 @@ package main.java.view; -import main.java.gui.GameWindow; -import main.java.model.Model; - import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Timer; import java.util.TimerTask; +import main.java.gui.GameWindow; +import main.java.model.GameModel; public class ViewModel { - private final Model gameModel; + private final GameModel gameModel; private final GameWindow gameWindow; - private final java.util.Timer timer = initTimer(); + private final Timer timer = initTimer(); - private static java.util.Timer initTimer() { + private static Timer initTimer() { return new Timer("events generator", true); } - public ViewModel(Model gameModel, GameWindow gameWindow) { + public ViewModel(GameModel gameModel, GameWindow gameWindow) { this.gameModel = gameModel; this.gameWindow = gameWindow; - initListeners(); + this.initListeners(); } private void initListeners() { - timer.schedule(new TimerTask() { - @Override + this.timer.schedule(new TimerTask() { public void run() { - gameModel.setDimension(gameWindow.getSize()); - getGameView().updateView(); + ViewModel.this.gameModel.setDimension(ViewModel.this.gameWindow.getSize()); + ViewModel.this.getGameView().updateView(); } - }, 0, 5); - - timer.schedule(new TimerTask() { - @Override + }, 0L, 5L); + this.timer.schedule(new TimerTask() { public void run() { - gameModel.updateModel(); + ViewModel.this.gameModel.updateModel(); } - }, 0, 5); - gameWindow.getGameView().addMouseListener(new MouseAdapter() { - @Override + }, 0L, 5L); + this.gameWindow.getGameView().addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { - gameModel.setTarget(e.getPoint()); - getGameView().repaint(); + ViewModel.this.gameModel.setTarget(e.getPoint()); + ViewModel.this.getGameView().repaint(); } }); - gameWindow.addComponentListener(new ComponentAdapter() { - @Override - public void componentResized(final ComponentEvent e) { + this.gameWindow.addComponentListener(new ComponentAdapter() { + public void componentResized(ComponentEvent e) { super.componentResized(e); System.out.println("resize"); - gameModel.setDimension((gameWindow.getSize())); - System.out.println(gameModel.getDimension()); + ViewModel.this.gameModel.setDimension(ViewModel.this.gameWindow.getSize()); + System.out.println(ViewModel.this.gameModel.getDimension()); } }); - - gameWindow.getGameView().addMouseListener(new MouseAdapter() { - @Override + this.gameWindow.getGameView().addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { System.out.println(e.getPoint()); - gameModel.setTarget(e.getPoint()); - getGameView().repaint(); + ViewModel.this.gameModel.setTarget(e.getPoint()); + ViewModel.this.getGameView().repaint(); } }); } public GameView getGameView() { - return gameWindow.getGameView(); + return this.gameWindow.getGameView(); } public GameWindow getGameWindow() { - return gameWindow; + return this.gameWindow; } -} \ No newline at end of file +} From 62870c9ae6cb80ed76cd3da7b20dd4ee328ca19a Mon Sep 17 00:00:00 2001 From: vdrnvdrn Date: Tue, 21 Nov 2023 00:13:45 +0500 Subject: [PATCH 5/5] try again.. --- target/classes/main/java/gui/GameWindow.class | Bin 0 -> 988 bytes target/classes/main/java/gui/LogWindow.class | Bin 0 -> 3059 bytes .../main/java/gui/MainApplicationFrame.class | Bin 0 -> 5686 bytes .../classes/main/java/gui/PositionWindow.class | Bin 0 -> 3024 bytes target/classes/main/java/gui/RobotsProgram.class | Bin 0 -> 2459 bytes target/classes/main/java/gui/Translatable.class | Bin 0 -> 174 bytes .../main/java/log/LogChangeListener.class | Bin 0 -> 158 bytes target/classes/main/java/log/LogEntry.class | Bin 0 -> 699 bytes target/classes/main/java/log/LogLevel.class | Bin 0 -> 1401 bytes .../classes/main/java/log/LogWindowSource.class | Bin 0 -> 2748 bytes target/classes/main/java/log/Logger.class | Bin 0 -> 837 bytes target/classes/main/java/model/Entity.class | Bin 0 -> 414 bytes target/classes/main/java/model/GameModel$1.class | Bin 0 -> 1018 bytes target/classes/main/java/model/GameModel.class | Bin 0 -> 3382 bytes target/classes/main/java/model/Robot.class | Bin 0 -> 6324 bytes target/classes/main/java/model/Target.class | Bin 0 -> 1793 bytes target/classes/main/java/model/TypeRobot.class | Bin 0 -> 1855 bytes target/classes/main/java/view/GameDrawer.class | Bin 0 -> 851 bytes target/classes/main/java/view/GameView.class | Bin 0 -> 3475 bytes target/classes/main/java/view/RobotDrawer.class | Bin 0 -> 2200 bytes target/classes/main/java/view/TargetDrawer.class | Bin 0 -> 1079 bytes target/classes/main/java/view/ViewModel$1.class | Bin 0 -> 989 bytes target/classes/main/java/view/ViewModel$2.class | Bin 0 -> 705 bytes target/classes/main/java/view/ViewModel$3.class | Bin 0 -> 1013 bytes target/classes/main/java/view/ViewModel$4.class | Bin 0 -> 1232 bytes target/classes/main/java/view/ViewModel$5.class | Bin 0 -> 1158 bytes target/classes/main/java/view/ViewModel.class | Bin 0 -> 1730 bytes 27 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 target/classes/main/java/gui/GameWindow.class create mode 100644 target/classes/main/java/gui/LogWindow.class create mode 100644 target/classes/main/java/gui/MainApplicationFrame.class create mode 100644 target/classes/main/java/gui/PositionWindow.class create mode 100644 target/classes/main/java/gui/RobotsProgram.class create mode 100644 target/classes/main/java/gui/Translatable.class create mode 100644 target/classes/main/java/log/LogChangeListener.class create mode 100644 target/classes/main/java/log/LogEntry.class create mode 100644 target/classes/main/java/log/LogLevel.class create mode 100644 target/classes/main/java/log/LogWindowSource.class create mode 100644 target/classes/main/java/log/Logger.class create mode 100644 target/classes/main/java/model/Entity.class create mode 100644 target/classes/main/java/model/GameModel$1.class create mode 100644 target/classes/main/java/model/GameModel.class create mode 100644 target/classes/main/java/model/Robot.class create mode 100644 target/classes/main/java/model/Target.class create mode 100644 target/classes/main/java/model/TypeRobot.class create mode 100644 target/classes/main/java/view/GameDrawer.class create mode 100644 target/classes/main/java/view/GameView.class create mode 100644 target/classes/main/java/view/RobotDrawer.class create mode 100644 target/classes/main/java/view/TargetDrawer.class create mode 100644 target/classes/main/java/view/ViewModel$1.class create mode 100644 target/classes/main/java/view/ViewModel$2.class create mode 100644 target/classes/main/java/view/ViewModel$3.class create mode 100644 target/classes/main/java/view/ViewModel$4.class create mode 100644 target/classes/main/java/view/ViewModel$5.class create mode 100644 target/classes/main/java/view/ViewModel.class diff --git a/target/classes/main/java/gui/GameWindow.class b/target/classes/main/java/gui/GameWindow.class new file mode 100644 index 0000000000000000000000000000000000000000..335ba1ee73bbc7d4c254883febdcea17eaced525 GIT binary patch literal 988 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 z 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 Kh1d8U$^QV6G>0qz literal 0 HcmV?d00001 diff --git a/target/classes/main/java/gui/Translatable.class b/target/classes/main/java/gui/Translatable.class new file mode 100644 index 0000000000000000000000000000000000000000..04aa1cd4ffb66f550e459ba831f997622bcf3ce2 GIT binary patch literal 174 zcmX^0Z`VEs1_nC@PId++Mh2yyBe1lEkE(RCWdyMg{?} zR8C@Ey1su>R%&tyBLh!yY6(nTDkFoeh7VXxX-Q^|eo$(0erZv1s#9rRN=~Y^W*8#_ uS1?$_Ei(tGSP-TWWPu(?9~&bBBLg$gMGOp#K>Ju3*gz}>b|A^bzySam9WGM< literal 0 HcmV?d00001 diff --git a/target/classes/main/java/log/LogChangeListener.class b/target/classes/main/java/log/LogChangeListener.class new file mode 100644 index 0000000000000000000000000000000000000000..490acfe49e7e0c08d4788d9cdd95cd00e03e7a24 GIT binary patch literal 158 zcmX^0Z`VEs1_nC@PId++Mh5xZ#LPVXti-ZJ{ha)CeV_bv=ZwU>^i-eB;*!+7)FO5U z7DfgEh&)hS-#;lUHMxY5fhRu?t~P~{fmuT{jFEvWIKQ+gIn^yQCzX*w3@#5dOAllW c8zTcyInV_R42(ddSsBDN7|5f* zknss<@iF%ps@4*v%(NKJ>g#gL^o=fqdKo^Fc;0dYemnAeJi51go-8Nq+g{g>T=AX- z)%eLBuGE(;k$&2nSE&ydy3-vV&s#0m8_U%Ymj28-tkI9PJ?fos6!rPFE9%Vs&huQ1 z563hzg|?>9p}9$qwm^3RjMi5qTcX#4SSj84<~vyPbONn;GC}TD0yfE(ppvDfi)GT; zfQ~Xnj;1hdp+YYrz&6P+=~YQcA%6$8nT$!d$R(R^&|b(s$%O{Oyg4-F>n_N1~uz=PJNa1?hMst=97E8^OS*E%#oDUca9hW1Iz1BLUfnr zaqcq=T}LOrj-U=hN1u+UjzLa&Y+xBHTsG0i5yNOA*;P0y@d74q*4~q5eFev}UpJ~H z+uyZHE_vpzNuKOB35IB)R<_(d%Xc`v9Ygl4Dus$()sHr%{=uO#)r;Bv@)#`?o?%Vg)3OkXXM6z( zGDoCl$4+rOHU16BF9O4J_R=j7rrf>gq2H6oiV>4XTo?WDuMO%*!X|kG*rH51Y`5!6 z)5+^oQeTn$BmkGKL`Aq(X-X?xB*d4pP2LcN0jY@k3#=$LA(=(F3C%1jO&U*8Z6a(I zwI(8FQE#H(yegKC=hR|L+>bOW{_OvxXwiF;bc*>CNWxl>WnpQ;dY~x63JL3>stPMC ztVK-|Rzz4!x-P8#Gdwy$j4Rig)&w;AmPt1SW297y>}BYrOc1-IR-mm{9xn+Oz^i|? CuLL;& literal 0 HcmV?d00001 diff --git a/target/classes/main/java/log/LogWindowSource.class b/target/classes/main/java/log/LogWindowSource.class new file mode 100644 index 0000000000000000000000000000000000000000..358e3cb6f68f9f4a74916e51f36f85fd6df878ac GIT binary patch literal 2748 zcmah~T~iZR7=8}<*bo+>kq;w&MM0AwMp3a6L@i>Q8ng<9qPBGj+pw7I(#-~?(;GXz z>zx;!>GY!38*h4{GX-p&YNx$$ru`%R4Nj|l&TfD}Xr0XD?D=@#_j#Z9dC&Rd<W2Hg4-Bv*YZPT)-e#j)IK2*l&pYMmxFSyRy2fTKvO7?4_3Et7)tB1}sV z-C>-@83kumyoDiwEuJu?m`5}zKVQ)>1p@I*#!GNm#d*9*(Q~#svxVX9H=dv zTix_vTHs=p#cM>liJ$d_a2@)GtZ5=?${MDAv0R+e?J;etz?DeW%4vmh%{Jt`vgmha z3?{j|7GibF6Q^pdYx!nd&r6xxD>@eF+(e)o@Fm6tLWN3u2*hfmZZM!qwYfRnWdHf+ zHT#4#xALy+1-8|idkw+9FFAJQZjp(vDW=jOlnd_=dtp;2UU5jF=C<=nhNMYiIPML7 zyaq=dEq8N7n{&BTKq=Ptv5QE-?7B=bZf$Ok7UTW zJi&q}ypr|XV-^Kiax~jHZ(BvCm9xqw72o?GhMQ<;O^ZIQKtydTBHtMC@TMF8>oM#- z8Rrctz?KaU$st)5#CTKH@zwGpB3~bVMda%Mwg$iJaEWu?<*W1ecnk2lQ*==ZtPKPH=qdFo6#$AulkXJk^x^5z+1??3_r7Ma0$uY=Mv4Ep*<>5N%bC zn^qk+VG>te$JdbX9E(2*sh*bio}g>8``|JTTud$@$uP?IP&q_=OE@%r+~l*5G}#M+2=&Z+|En`U(94Un=6ktG^x*=RTy+ORT+o0OUA= zBIY>Gq3n)6NUE=p1t5wrwv&qv?BZ`9pVxyVydQgUhO=Q-b%Zb881`ct2QW)MZu7+F z=)oOE`HJt>T^zwT{QeHdTsE(hr@K&G4nz2op0Be^3S-?{W%wRG#7AUSu6>LfELj*| zL&FrSbB6OAlL;lpdh3mufX7fLQg`$%@DVFhHG4kQ6gWq12w#8P8M_h>=i} zr=-ZgAY?zsu8wc9r$cJuKDKr2xFNqDV{lNq?bx}5a}OWmorgT=u^(}b(sVq4cAO%l z({7+7*W1a4#T}_s$-O7{F4oS2(S=X>Rp)ZygNRky(x#IVoC>Z~C9i-4Amdgib*?I@ QKqZ3L+hv-~yQgpc3-Y{q9{>OV literal 0 HcmV?d00001 diff --git a/target/classes/main/java/log/Logger.class b/target/classes/main/java/log/Logger.class new file mode 100644 index 0000000000000000000000000000000000000000..bb1a92cfd9fa2908a698aa77d616253c1cf4eb34 GIT binary patch literal 837 zcmZ`%U2oGc6g_U!rA;zcwr-5EF$N5hN>Cx5P^Y~xAt42L7%Jk?ZA|c#B~zM?zXd~L z5=i_2eiY(3sh}d@2iy1h`kec5e*FCU9l#;_4jO3MuspP|B+xyP=W>w9G#t2N#||?^Nn^Q2oi`L72s{%83%GcXE~#w2!k{K2ZX@VJ-BH zPNVEY6)^1J3RY}%JzT}Az(y@PROc!YXdS8XEEd?TB(`C>ogt)Bg3*~dUiv=@}CDI9#6A~g|37;RWE0!W0k*_nZE3ld^+D))`fGuKWL@7jULU{z6TsGA)#`(Lp3H;h9#cLB!59o#Kp_Hl0x xvt5EPJHmYA8zsTrWC=>Hjr+ed-Y211%iqv@+l?-9{WEMsx%kDR<o&6`f0C(coYc}1qPAWLCkZ>_>p3AdI&;E0!qqtavpj3-+E_RB z72%ARAq-Nbn&H|i%12k)8!2kdN literal 0 HcmV?d00001 diff --git a/target/classes/main/java/model/GameModel$1.class b/target/classes/main/java/model/GameModel$1.class new file mode 100644 index 0000000000000000000000000000000000000000..8d07e96cfa779cc8affdb7a747475a7ddb66b670 GIT binary patch literal 1018 zcmaJ=T~8B16g|_HZo90d6hW|n6|1&IS?V{|@Y49vq<~2Y@6$4r!To4FCr ze}F&8N8_Ds6^O!4c4qeOx#ymlIrHP!x9EUy!+eJQSCB7>{})50VyhMAZwQqr+^r7MD69)2LESJIPelOb8D z?q!j~l!3g3X%rapafZXazTFvyO1OmbBgHV=j{ivCeji9rbyOg@+sNQL!-Ue@CgyO% zz`TV8-27AeBAme(=w!zuzRHMjR7z2}-_U9nv1DM`!Yz~-7A{>WQH9Z9;0GjaWyI7K z+zUyaKM;W$HVy6J^{raL>YhR2ZhuR^IZI=!<}A9CIfU zI|mGNl~(nf;4y;syM|Q*4=g;y8bc}OxIzd+;XnrBqDY2~|7^y&YCGK{(Nm3oBh@{I z<;oR)(128vEW|L?mY&#-+^)7k*P%$E?f1B|#{;Rq$HA1g8N<@$q~&^pOc6wMh-Sx+ zf}VIIHC^tnUDxzBP{r3?&+$V#*)5?C{e6bawg}ZbKcqvmTAn9@ro+QfgecKX$k3%= z`MkahG)vGs2^$RS@nuQG5wo`X8LajN#>W^_r#?*>kog|Pz0Nc77*A-_GtI`RJ%u&q z+CnPMD1O4V!ptdVYbRhQC>CzB{LinrbBgL2c@9aUnJ01NYHGTOCIX7%A}KthuLPds W1&t{(a26YJWDzfEGzqOm(eoS5Uh+o( literal 0 HcmV?d00001 diff --git a/target/classes/main/java/model/GameModel.class b/target/classes/main/java/model/GameModel.class new file mode 100644 index 0000000000000000000000000000000000000000..5b1a8227737e23789b79f35d8f0c42b1790c4117 GIT binary patch literal 3382 zcmai0XZ}?l*sck6Pb5GYJ6-(x*4~-Z|&obKdiwbMJ5e{`?DoE_@e; z5B?AW3WBH*Sbs*HQX^T_7?1RioY6*Yfr?Ju(Csb(e@km7j7n665LQqPMWA6))s2Xw zGnpIHvXLX|q?V8~fjX&{vQ=B_KYd6YwKY>$ErAU!@zy>^qhRaVNS|)m(JES9t6&}0 z3sh=`t=qar(e+E^LZ}sJc9cgn)vzK1W-hOp_H@q#J=Ri%d_HH|Vbq{b#exrgL(IikM<4fz4nkj=SkIC7LhH#TWa1h-B3QhDDLy=*7nN-i&kjyRPWT z;-K#1sY`>3$_#sE?Z(z1>#3i&ZsUL`Uls-c~0&gXQ)4&i=sb-|l%(^RJ=l3|>L zKa2-(Duf3WJcQvQ*v{bz)t;bDQ#HnNla9l^6$htXPD(6CC1=J2f-Swht(g!`7qumb z1M=iBG)zb-T}s8{vXgY;tb#0Pu!?+2tEQ984IWuas-(Y^%_+#^5#p9J*i=m7cC#nB zTEV&$vJ}`T&~bH)US78+46$ML9PLgXi4CW^)A3k(a5$EUCDY7a88N*&UJnA%|X0NIUbSjn}?u{p6$yB^QSv0pU89O;V&>v5xi#t^*ecVv(g2|d~ za}O)E#?EDJ!OeBFi{%jLVW(vi=+g}?S(qHr%(OZpE5EicH>zecDmyOM-e$m_(AiWQ zmsu?JY?=((ZbPdn^TTattQ2OcR1pH3$`V!DX0n*hv4wi7a}6!7CV^^~pWanb;q?4z zfg6@N=Y`8)r&N=z$FsM%-k1+^V)Sf6&3nOClS_`ObCJ{*OR0n_L+x0$xhmK}r-DkC z(gHmRnkkzK5n1NF(`|T`Aniq*C8SQ~3I;{PZp3aEt6!Y1>3lI|yGo6%2kDSJK-2qPtOG`zqxUo1#BX?)=&m-D`HUcD>4SMHxXVS1?Dl!@4Bg+7gF$%kIMb zCN;}WXp)oUoDw&9!}MfT%hD`t-L<{lp~9G~WDiZdU7cel+#w6z6i5W0djZS$xZdwiD4q+{!UeocOG4gip2aA2Soipf?j`+$P+3A>6Tw%|o zz$+y@FYt?>IyhSPc?`IYx`vVPud1%EC7rieRXE8p5GYtXBg&7zf4S_kB zKAe2sFD_sEu|q~1a1h?c(|~(89$;x4B(mK&#DDjqhcAHx7{X!4^E>DhA9r{U?^83( z;`;y}I!QfM;?ODP^Fu~cNzIR0WP_9AEsOiGdYNe2K59 Z>c=JL?62_+e*@gvf^RtsJ2Osz{{RnT0@VNj literal 0 HcmV?d00001 diff --git a/target/classes/main/java/model/Robot.class b/target/classes/main/java/model/Robot.class new file mode 100644 index 0000000000000000000000000000000000000000..37c96380a8d939b4e02a3703e1d2f44423f1cfee GIT binary patch literal 6324 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 J_%c-K{{X4eS~CCu literal 0 HcmV?d00001 diff --git a/target/classes/main/java/model/Target.class b/target/classes/main/java/model/Target.class new file mode 100644 index 0000000000000000000000000000000000000000..0d6518bbc37d18b3e21a57d2f8e65cc41269598c GIT binary patch literal 1793 zcmaKsU31e`5Qg95FJVV^Vkb=kaoa%nupNpipKU`^N(hh{1DOevA?=kMYhqDH^2l-^ zzlRHMdea$5XL`{e&>z+5yGOEQio=DEtaEms-FzX7b{NdYOO4P;DYkyDs? zWgS_~p5-1ipSNGx`+-94p5r>fxSpI=c zC-sKEEwL_{m=;rYoJU!FD+(p;VZ9ET+n(bF1)9y7_yY3^nSmX=}#hJbj9+#i3?(u>)Osim!U4=l7Y)6uAru{ ztexAog}Cjzwi01r}wVYOTI&pfN$J zO*e3YW0tx>VuLopd3=sEV zt^SKbzLT_ME`cRR3dNnk+W+mT)sO1S4f`D{VD*OQ@<=*x=`$)vZPF>{`@?q68FZyH z7fx@?$c1Cr|ET2(E1!w9d1SkRj+3^JnAP&>5kgai!j3oe_w7fHbaN`y{hAC6&U2_! zP^fc#AXkZ(@qyeEKBu_PyU2BwZ;!PdP;UGQ)tKpgfT7poA3RLqD%T1!TurV;6i~tp zLEq>d#kGuUX!0r0>k)L1o@wq)Yv__Ns~_+QvP@(JdCU?zr;*E{TZAM)=PqHUb@oyd zuW=M+oncZu%QYlKlCXSpfCVPBsHyXzRZPuAR3*255^F5ekhMfs^%Rz<%6Z1OxDm0M z`W?tN-oyBvsf0R;%6P<72b`<$3LrLxB#_D^_oM2X-3ny4i z#3^ZsuW&$W>|}kcs8J`Sr+08y7x5jwkI=tH=&BS&>e5?O__xTv%Wq+1-XW8gbkllf z!dkD6(W|liRs4W8Qt#0^i`2RMqTY}3M9Nf(P%6neq+K5?Ud76-<0qPnQ#=l1EomAAOi&~(B(yYrTgZy*fu)BmY5T8Q z(welMdi>lU<#Fcj2B|M8AGmw(edd{&XJ+od&;Nc3Uunte8=3~&5j+^+`jF!v*R9^K&5z2;ym7=6px~h zdxito?qtgLuB%Y*N?gQygsSE$g$+_JF@~y|&Q7mO(F$CWxQzD+ry|=GIG-|(SHnPB z!xf1SuqY5$87kKvDdp%`zqlpGrJAKmMri^WENQqV@gY7sl4KOCK(K8Qbef=J`H#tY zL*gbrrT~|1$97i)X2zBCg(?|!uIwigpCZdO>UDa3iq4}ne|9r@KFLNAj#1-%u3=Ro z$55|CBLvy5Rg1+6OOt2M1%b+<-Djl?9cv6|g>On1D0V^s#-rq$mxn;kmIyg>lt7&30QUd!y%&A!bHK269myTs-< zq8b~&d;)r3wIq+ez&RSNw~sjm>OQooQ&0I}jf$5wNUkXLlPWfOIvUZJ2)bWxb^K29 z1yYglc>SM1daXC;x2!uhi!wEOrmpe~tX`wC&eF4{tFZC#^}I zOtsP+lhs%B9l+P|BtJ{^t&ttgB;7Pr<${6;&0Z|Faw?iioMwvWF~ zTx_8yMEVdj&mb5d_z(VDI*}d<-{E`O#qa}u^cj{Aq7&fE5c5M^IK;x!@XlkT{=(G& ze72yVzZHdAR56Tg0)6y2(8u# z524py*EI?YRo{4zs>;8+Psld0OxB+r;PyU(YF{LtJ8G|~eTf+Fs=a=Q`}>%D0;6$& tFZPw5hp6pio>lR5OsdSIRQ(t(K*tjGz)ehI6;q^**B=kiCVT)7UjTsFhpzwt literal 0 HcmV?d00001 diff --git a/target/classes/main/java/view/GameDrawer.class b/target/classes/main/java/view/GameDrawer.class new file mode 100644 index 0000000000000000000000000000000000000000..141239f18a17afce04d29d60afdce1d87cbd171e GIT binary patch literal 851 zcmbVK!A{#i5Pg%_abipYxS@rR77A^X9O@SJ7L*IL2q`KDP*jc^XKNPO4sx7Cd{!?Y z_0SLKM^&A*QK<@*s_tRt&Fq_*H*0_Y@%0;k9$wifplHExV4_4=x)3wrg(42Th|6>3PYC7DDh!WjA|zO?BR+Xm)j>^{ zlt+n}>uU?kgtbVh*vq=il$?8qB9aG8kO{%qACDxV)>pCoIE{ufITgc@Gb{bEFT#OH zl#XwcMtZJzdZYi>j$OiftA9^%H`hp@fZ#rG&wKbXPG$0mIY+;uGlDr%B6@r4cUiIC zjqv7yDZ2;V-;_nXS?IlwQTAHlBeqUXKpm@Dw1CH)(Zz}zne5$8qiKetjk>|MSvRg>-L=xc8c^W^J8SnYFToS6 zah{8@jz%`Z#RenIcF|;1%+OOt28*cu!`Q_?$1d{N>i>^52+yzyu;0RS7P-xm3fN)v IB112K0?Ch`Pyhe` literal 0 HcmV?d00001 diff --git a/target/classes/main/java/view/GameView.class b/target/classes/main/java/view/GameView.class new file mode 100644 index 0000000000000000000000000000000000000000..8912b410bfbff97e54ae769d79bf298ca5fdf840 GIT binary patch literal 3475 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 literal 0 HcmV?d00001 diff --git a/target/classes/main/java/view/TargetDrawer.class b/target/classes/main/java/view/TargetDrawer.class new file mode 100644 index 0000000000000000000000000000000000000000..0e428003e340af90d6da023bc2403d1839bc43db GIT binary patch literal 1079 zcmaJ=U2hUW6g|TNyWo~jTl-#ejfja5qK{L$($QsUmTgJ@j=w;C zsKy85lMntTW4yBqg0;HI&Yih)=iGDdo%#Or^A`XmY(^1)q9UjxgfPQQhYQj zHOgJ9OF*HW=iA#ghD7zxonjOTBvqtzq;ZiU{d;@I;fDvJ)hkpOw4Uh>fYO<>2-#*7 zDyDQ?!ZbsW$h`3Q?n?Kpj=7=xWfb#RP;o`aRV*^hjih+OeI-Nb+ACpM&yKmpFguoW zNUOL@U$!ZAU)OO%iVkg6AC;fTBsX>3k{Psps-uq)EK{`@;#FarwWH3S=`{GBMV?f( z+u~M}J3_7p&Y*iBdJOZ`|4=NFSc%WDb`HNnr8sujZ`HQ#3iqU#Z8ESn!{n%vLsfK& znr?b=4AcKYpcvO{`*|^b83|{i?()`~r~GgrDn_l5)fINTadJq~)0wPK!Qyt?C|kVO zqhpb}XxrR9awuZz?}*J@iGrf_?vc|n9}8K+L72u2t=7ph zvZ35Zu=g|xAWNfs5b$S;3D2b*Uc?KLPBMhv0 zyf$zf1!5c`&pP=P+#xg#><89WLT0#&d$ce4=4mAbD=GCI8DFlf1~5G)RT-qY@5MZz J{fFMH_zV4-=K25t literal 0 HcmV?d00001 diff --git a/target/classes/main/java/view/ViewModel$1.class b/target/classes/main/java/view/ViewModel$1.class new file mode 100644 index 0000000000000000000000000000000000000000..452ca5abfdd29c64a139540bc62d1d8923bc8eeb GIT binary patch literal 989 zcmZ`&ZEq4m5PlYrgJVmvt;cUKbsl}W|K z5B>mulyUZ;AdOsdvp2KPKJ(1%-0wd>e*xIT%QRw$8%S_mLy}>==SXFJa?Ty=T#A9! zB6H|wgXa%8|6mLsY#kgjzid!m2h_@9aBl~gj=V~AI4 ztu(S&G?3%CjwOcGdDIN)uG15d8itL3B=odE>+R)cQ!}n`+(4ee)Mq|Q)$s_z&fDvlrKF+R9h$+D0AGzErzve zL05z_a9;$IgA9f0|M+SxlM1SE+`(Oj45inl>YJf9kc26JbY+*Dq@#+OfjY;wzKX&e z9Q7#t(s6<@<7V|L;baDywH8BSpSsPkXiFuI!rrOA(^HosOSac`+?Laq+8+lKdSn=i zb2%%GCXGQqR3zir3;S*HMryX~B(FGV>pQ|Wg#D(Ky6lKC(EL0Mni%St+D)~F?@o<<9 zWE5-@%K4en!4|8!!(<%~6;xe#K5Fm@lNMFvDhiKPEVE;wFBtSyB`V(~jI=g-Rn#%= zqTyo#O~ULjG@*JbVrktF=HFO|jluB8^H28h0aGrfeasjSA76?8DG9aW*FfaY(8bmp z>ihF|HhKhSk1G+zyDE`KMSNn;a}sf+*-iT*>WNI5{Zr5}?IJ7;Wd_?FZb4Qg1n*~B zWPSNv8Cw0N>t9U!xZt;>AEjC)r-w2>O9wvI%)!P?7rRR5GLacqsvJq3@25H^_y-Bc z_9CIR)L7aw7l3`dP9ui6hJ=9|ND|fuwsfs8_QKt$`z#bb6TXqI z4EG7~irGmci)9Tt12>T;6c$Mk(tUd%B3CRhV`ZR>TJNtn*~=~5*05?|4Fy8+e_jrh zEkddyHYds60udhDKGP9aD)U5UN9R*+8@P)d zLWWVwtx7VVgmtIHQTDGl*+3chH9RozP-S&(0gj;g;*2ZE;+vIuwn;4;W`~eya<&M| zE$NEG;owC0$M%WCk$lVR+D^yzrCMJF6RPxtjfI@$dV^pLRC$|@?0ywJ!q&|BXUZR? zJn}#+SDNPN9}GeNP;`GoBOt&vU$tB3ZoRS!axr<>xP8_3h07 literal 0 HcmV?d00001 diff --git a/target/classes/main/java/view/ViewModel$4.class b/target/classes/main/java/view/ViewModel$4.class new file mode 100644 index 0000000000000000000000000000000000000000..660924a0e8d0aa532e57575387ba85b6dcc3427b GIT binary patch literal 1232 zcmZ`&YflqF6g^WaOUnQiq`c)})wU=L1)oI}%hMDz*3{2SJ1IlU46~LYZT-Ti8G22ME4@g| ziBlG4VvAwWKbKx&oxJk>+_F&&A)+D5F$~VI7(f|UzAkFQ_Vt`&T{<>>?Us#8U$_Li zEp6%VFbpJ9MHM~DF@_jJtaR)9S$OihC^M`i^ZoGl6?`^Tj9?rS8t!pSB2FNIziHSN zz3|QRg++Oss?RXlK$4FB$(6QW@Lge8*&$3*MQ)HUidoEQnCDo)eTInusoS4HyHwGp zO@PhX8o7KjSAueuu&iN);{g&3)BSj3h*S(q1XMH3b?|E`_VvTt!)ydgc*OA-NrtG3 z`6}(QbJg9HN>v6SjWcRW8mk(fa6H9YR~6lkbf1dw3q&?UJeg{fy(cYUd(yE9Y8@LI zG8~&ANzAk_)Ke$}_k`aHWSHt`Udv1rDa7X-FH~im(zni3170ciU-z*4@$5pBRI?ct zk{wiaD>gU}=ZHRrvAnd!Y1KLt?ib_CB+Gc-DH&$baHaZh8pBH94D)?46I)pZM&XNX zZhC~>5F+)a;8fj`IFKsaXlstvl#HmLeY<2j9*N{c_~%ZU<4}#uh?<4GB%#{ErAmfQ zh36kR9toBo+hog`hUW>7G!UXu0az@i2A94<^bR8nhV5XoLxCllUi}4@zJc~5@OeY) zAo+llutRIS;f1$&M}I&xK%+aV8Ej(J$VZ`P(yKQZ`H8#ZQ+3RwufeXd*w`M{k*Y(d zv!=O@XLY=6=Zq6BpwqgJ5o}-?8Co|xYRI%|$Y2-mDR&q-iV0y4`?QDY&IdROEK4}1 LJxV^RE_(h0si-L^ literal 0 HcmV?d00001 diff --git a/target/classes/main/java/view/ViewModel$5.class b/target/classes/main/java/view/ViewModel$5.class new file mode 100644 index 0000000000000000000000000000000000000000..e674289d2bc097acf466e6d6b641f75ce9dce567 GIT binary patch literal 1158 zcmZ`(YflqF6g^WaOP2*|kvAyPs%=pg9|&4RvEm~sNCN5irJa<;?Jn7!Li|}8#KaH& z0DqM6%oZp?y2;LV?wmRI+&gFb=kKrI0M@XPLIOPok``{DS75T~xW0Yh969!pE066e zhs~faz1)&OuiAH`+#*qxZm^PxKBNqo7W!ccOvO~rv9jfn^p(9Cv?94)cMg>dNx16z zu38i5$rq|A3}VPY+QLm_1k&+N&+!}f&eurECQ(6435-d2eCF zz^H{Wj0;R$mv=);5a?@2wH(afjKgOKolHrrRIR7b)vL9vH}5D4@vt zI*eD4q>QB6bwXB2`DgMv^%bfn#XYp}2nz!JMCl~@oGF0q=n%&SIA5fIMLag}#KKd3 zuwz|t>`f>SX(A?{$zNr=uoHVEkSw!EfuV})%dJ*(PlmhBp2tY064V^8>V&SIp9PcJ zeFD>6Ide-T0jsGUR`%T57g-m$eX0IS4vd`;YYo+!~+7Id$-s<)YXk%Ag`qq~rRrhVlNPP?kYb?Z-0+EX7we5l778{11rYPZ-}~%yW*t#DJ(}j-zc9R`7x|z>L`h5ie0X z?NSqG6nI2#O(AFp426TTu#asA8i=F`z9p9r(A9cjDS))5&h&R=f;5 zQ(~vg^a6TOojzxGF&|boGkfyB=i_(vT-3l$S4Mh#eE zex9+qHm~>J>4QLFI44$P7&may!UQfUOg9|YvqRHES0C9GzBZdxT~`UVWcSwmvKcQ8AuKa7ysAls)aOW7_sIwbR2!A+(m8(pj|puhLNvX_zKq*O!4`} z^{UMyg>;Wot?h;`k**+l%~`l1sh=0-W!Dd+jJ|=J^z5Sb=XvwKi7e)&Xtx!v<$4hM z4GRmEB>N{%QrdFI!d=``NcjhEb+ujB1c@8dEz*wT|617CSYXfXvq&tNSj4=EB|I?j z(84ml>FZ5@vI?U$9Z0>TT?#Yo&Om;r%7TH_vw$C%SP|d?)(m`aaXcR@T=_yU4wX}_ zZZ_M#KCQ08T%5FX6xiYT+I2V2)b;tL$k2!9M$q63j_H!lqZ$j2Alw4$)ZR+`D;DB%NltqGXVDtoPcVam4 z5y=lcD!k(R9Hj(M+?{glP{$C11L^!njO72sg=0+S?;K+~fA<)fdwd4lXN8QdC~ zM6QE;bhRi~Uw5xE9o#>`irjwN!FM#uoM2s!KXg!(V`xy4o0l{gWS(J}ZeSj_v5I?~ zs%7kAEo5$y6R;OESF+AA%Oy(DrQ+~X&8QktH6Qo*r#|_=!H==O9s4K6f6%$uL|;