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/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
new file mode 100644
index 000000000..59ad337eb
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
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/.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/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/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/LogWindow.java b/robots/src/gui/LogWindow.java
deleted file mode 100644
index 723d3e2fc..000000000
--- a/robots/src/gui/LogWindow.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package gui;
-
-import java.awt.BorderLayout;
-import java.awt.EventQueue;
-import java.awt.TextArea;
-
-import javax.swing.JInternalFrame;
-import javax.swing.JPanel;
-
-import log.LogChangeListener;
-import log.LogEntry;
-import log.LogWindowSource;
-
-public class LogWindow extends JInternalFrame implements LogChangeListener
-{
- private LogWindowSource m_logSource;
- private TextArea m_logContent;
-
- 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);
- pack();
- updateLogContent();
- }
-
- private void updateLogContent()
- {
- StringBuilder content = new StringBuilder();
- for (LogEntry entry : m_logSource.all())
- {
- content.append(entry.getMessage()).append("\n");
- }
- m_logContent.setText(content.toString());
- m_logContent.invalidate();
- }
-
- @Override
- public void onLogChanged()
- {
- EventQueue.invokeLater(this::updateLogContent);
- }
-}
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/LogEntry.java b/robots/src/log/LogEntry.java
deleted file mode 100644
index 3d9147107..000000000
--- a/robots/src/log/LogEntry.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package 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;
- }
-}
-
diff --git a/robots/src/log/LogLevel.java b/robots/src/log/LogLevel.java
deleted file mode 100644
index 582d010cc..000000000
--- a/robots/src/log/LogLevel.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package log;
-
-public enum LogLevel
-{
- Trace(0),
- Debug(1),
- Info(2),
- 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/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/log/Logger.java b/robots/src/log/Logger.java
deleted file mode 100644
index b008a5d01..000000000
--- a/robots/src/log/Logger.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package log;
-
-public final class Logger
-{
- private static final LogWindowSource defaultLogSource;
- static {
- defaultLogSource = new LogWindowSource(100);
- }
-
- private Logger()
- {
- }
-
- 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()
- {
- return defaultLogSource;
- }
-}
diff --git a/robots/src/main/java/gui/GameWindow.java b/robots/src/main/java/gui/GameWindow.java
new file mode 100644
index 000000000..76854c1ec
--- /dev/null
+++ b/robots/src/main/java/gui/GameWindow.java
@@ -0,0 +1,23 @@
+package main.java.gui;
+
+import java.awt.BorderLayout;
+import javax.swing.JInternalFrame;
+import javax.swing.JPanel;
+import main.java.view.GameView;
+
+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, "Center");
+ this.getContentPane().add(panel);
+ this.pack();
+ }
+
+ public GameView getGameView() {
+ return this.gameView;
+ }
+}
\ No newline at end of file
diff --git a/robots/src/main/java/gui/LogWindow.java b/robots/src/main/java/gui/LogWindow.java
new file mode 100644
index 000000000..b3ba182c9
--- /dev/null
+++ b/robots/src/main/java/gui/LogWindow.java
@@ -0,0 +1,51 @@
+package main.java.gui;
+
+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 mLogSource;
+ private TextArea mLogContent;
+
+ public LogWindow(LogWindowSource logSource) {
+ super("Протокол работы", true, true, true, true);
+ this.mLogSource = logSource;
+ this.mLogSource.registerListener(this);
+ this.mLogContent = new TextArea("");
+ this.mLogContent.setSize(200, 500);
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.add(this.mLogContent, "Center");
+ this.getContentPane().add(panel);
+ this.pack();
+ this.updateLogContent();
+ }
+
+ private void updateLogContent() {
+ StringBuilder content = new StringBuilder();
+ Iterator var2 = this.mLogSource.all().iterator();
+
+ while(var2.hasNext()) {
+ LogEntry entry = (LogEntry)var2.next();
+ content.append(entry.getMessage()).append("\n");
+ }
+
+ this.mLogContent.setText(content.toString());
+ this.mLogContent.invalidate();
+ }
+
+ public void onLogChanged() {
+ EventQueue.invokeLater(this::updateLogContent);
+ }
+
+ 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
new file mode 100644
index 000000000..f5185185d
--- /dev/null
+++ b/robots/src/main/java/gui/MainApplicationFrame.java
@@ -0,0 +1,93 @@
+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;
+
+public class MainApplicationFrame extends JFrame {
+ private final JDesktopPane desktopPane = new JDesktopPane();
+
+ public MainApplicationFrame(ViewModel gameViewModel) {
+ int inset = 50;
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ 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();
+ 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);
+ this.setMinimumSize(logWindow.getSize());
+ logWindow.pack();
+ Logger.debug("Протокол работает");
+ return logWindow;
+ }
+
+ protected void addWindow(JInternalFrame frame) {
+ this.desktopPane.add(frame);
+ frame.setVisible(true);
+ }
+
+ private JMenu createMenu(String nameOfMenu, String description, int mnemonic) {
+ JMenu lookAndFeelMenu = new JMenu(nameOfMenu);
+ lookAndFeelMenu.setMnemonic(86);
+ lookAndFeelMenu.getAccessibleContext().setAccessibleDescription(description);
+ return lookAndFeelMenu;
+ }
+
+ private JMenuItem createMenuItem(String name, ActionListener l) {
+ JMenuItem systemLookAndFeel = new JMenuItem(name, 83);
+ systemLookAndFeel.addActionListener(l);
+ return systemLookAndFeel;
+ }
+
+ private JMenuBar generateMenuBar() {
+ JMenuBar menuBar = new JMenuBar();
+ JMenu lookAndFeelMenu = this.createMenu("Режим отображения", "Управление режимом отображения приложения", 86);
+ JMenuItem systemLookAndFeel = this.createMenuItem("Системная схема", (event) -> {
+ this.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ this.invalidate();
+ });
+ lookAndFeelMenu.add(systemLookAndFeel);
+ JMenuItem crossplatformLookAndFeel = this.createMenuItem("Универсальная схема", (event) -> {
+ this.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
+ this.invalidate();
+ });
+ lookAndFeelMenu.add(crossplatformLookAndFeel);
+ JMenu testMenu = this.createMenu("Тесты", "Тестовые команды", 83);
+ JMenuItem addLogMessageItem = this.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 (InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException | ClassNotFoundException var3) {
+ }
+
+ }
+}
diff --git a/robots/src/main/java/gui/PositionWindow.java b/robots/src/main/java/gui/PositionWindow.java
new file mode 100644
index 000000000..efa17c83e
--- /dev/null
+++ b/robots/src/main/java/gui/PositionWindow.java
@@ -0,0 +1,48 @@
+package main.java.gui;
+
+import java.awt.BorderLayout;
+import java.awt.EventQueue;
+import java.util.Observable;
+import java.util.Observer;
+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 robot;
+
+ public PositionWindow(Robot robot, int width, int height) {
+ super("Координаты робота", true, true, true, true);
+ this.robot = robot;
+ JPanel panel = new JPanel(new BorderLayout());
+ 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);
+ }
+
+ public void update(Observable o, Object arg) {
+ if (arg.equals("The robot's position has changed")) {
+ EventQueue.invokeLater(this::updateCoords);
+ }
+
+ }
+
+ public void updateCoords() {
+ this.labelX.setText("X: %f".formatted(this.robot.getPositionX()));
+ this.labelY.setText("Y: %f".formatted(this.robot.getPositionY()));
+ }
+
+ 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
new file mode 100644
index 000000000..1b0bee484
--- /dev/null
+++ b/robots/src/main/java/gui/RobotsProgram.java
@@ -0,0 +1,35 @@
+package main.java.gui;
+
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import main.java.model.GameModel;
+import main.java.model.Robot;
+import main.java.view.GameView;
+import main.java.view.ViewModel;
+
+public class RobotsProgram {
+ public RobotsProgram() {
+ }
+
+ public static void main(String[] args) {
+ try {
+ UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
+ } catch (Exception var7) {
+ var7.printStackTrace();
+ }
+
+ GameModel gameModel = new GameModel();
+ GameView gameView = new GameView(gameModel);
+ GameWindow gameWindow = new GameWindow(gameView);
+ 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(6);
+ });
+ }
+}
diff --git a/robots/src/main/java/gui/Translatable.java b/robots/src/main/java/gui/Translatable.java
new file mode 100644
index 000000000..4a6ee20ec
--- /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 setTranslate(ResourceBundle var1);
+}
diff --git a/robots/src/main/java/log/LogChangeListener.java b/robots/src/main/java/log/LogChangeListener.java
new file mode 100644
index 000000000..d9608308c
--- /dev/null
+++ b/robots/src/main/java/log/LogChangeListener.java
@@ -0,0 +1,5 @@
+package main.java.log;
+
+public interface LogChangeListener {
+ void onLogChanged();
+}
diff --git a/robots/src/main/java/log/LogEntry.java b/robots/src/main/java/log/LogEntry.java
new file mode 100644
index 000000000..8c6a12eb0
--- /dev/null
+++ b/robots/src/main/java/log/LogEntry.java
@@ -0,0 +1,19 @@
+package main.java.log;
+
+public class LogEntry {
+ private LogLevel mLogLevel;
+ private String mStrMessage;
+
+ public LogEntry(LogLevel logLevel, String strMessage) {
+ this.mStrMessage = strMessage;
+ this.mLogLevel = logLevel;
+ }
+
+ public String getMessage() {
+ return this.mStrMessage;
+ }
+
+ 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
new file mode 100644
index 000000000..d6ffe0ad2
--- /dev/null
+++ b/robots/src/main/java/log/LogLevel.java
@@ -0,0 +1,22 @@
+package main.java.log;
+
+public enum LogLevel {
+ Trace(0),
+ Debug(1),
+ Info(2),
+ Warning(3),
+ Error(4),
+ Fatal(5);
+
+ private int m_iLevel;
+
+ private LogLevel(int iLevel) {
+ this.m_iLevel = 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
new file mode 100644
index 000000000..8243b2a2c
--- /dev/null
+++ b/robots/src/main/java/log/LogWindowSource.java
@@ -0,0 +1,70 @@
+package main.java.log;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public class LogWindowSource {
+ private final int mIQueueLength;
+ private final ArrayList mMessages;
+ private final CopyOnWriteArrayList mListeners;
+ private volatile LogChangeListener[] mActivelisteners;
+
+ public LogWindowSource(int iQueueLength) {
+ this.mIQueueLength = iQueueLength;
+ this.mMessages = new ArrayList(iQueueLength);
+ this.mListeners = new CopyOnWriteArrayList();
+ }
+
+ public void registerListener(LogChangeListener listener) {
+ this.mListeners.add(listener);
+ this.mActivelisteners = null;
+ }
+
+ public void append(LogLevel logLevel, String strMessage) {
+ LogEntry entry = new LogEntry(logLevel, strMessage);
+ if (this.size() >= this.mIQueueLength) {
+ this.mMessages.remove(0);
+ }
+
+ synchronized(this) {
+ this.mMessages.add(entry);
+ }
+
+ LogChangeListener[] activeListeners = this.mActivelisteners;
+ if (activeListeners == null) {
+ synchronized(this.mListeners) {
+ if (this.mActivelisteners == null) {
+ activeListeners = (LogChangeListener[])this.mListeners.toArray(new LogChangeListener[0]);
+ this.mActivelisteners = 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 this.mMessages.size();
+ }
+
+ public synchronized Iterable range(int startFrom, int count) {
+ if (startFrom >= 0 && startFrom < this.size()) {
+ int indexTo = Math.min(startFrom + count, this.size());
+ return this.mMessages.subList(startFrom, indexTo);
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ public synchronized Iterable all() {
+ return this.mMessages;
+ }
+}
diff --git a/robots/src/main/java/log/Logger.java b/robots/src/main/java/log/Logger.java
new file mode 100644
index 000000000..005635194
--- /dev/null
+++ b/robots/src/main/java/log/Logger.java
@@ -0,0 +1,16 @@
+package main.java.log;
+
+public final class Logger {
+ private static final LogWindowSource defaultLogSource = new LogWindowSource(100);
+
+ private Logger() {
+ }
+
+ public static void debug(String strMessage) {
+ defaultLogSource.append(LogLevel.Debug, strMessage);
+ }
+
+ 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
new file mode 100644
index 000000000..c1b7d3f7b
--- /dev/null
+++ b/robots/src/main/java/model/Entity.java
@@ -0,0 +1,12 @@
+package main.java.model;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+public interface Entity extends PropertyChangeListener {
+ void update();
+
+ default void onStart(PropertyChangeSupport var1) {
+
+ }
+}
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/Robot.java b/robots/src/main/java/model/Robot.java
new file mode 100644
index 000000000..3a9f20892
--- /dev/null
+++ b/robots/src/main/java/model/Robot.java
@@ -0,0 +1,220 @@
+package main.java.model;
+
+import java.awt.Dimension;
+import java.awt.Point;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeSupport;
+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;
+ private int satiety;
+ 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.0;
+ this.dimension = new Dimension(300, 300);
+ this.satiety = (int)(50.0 + Math.random() * 50.0);
+ this.type = getType(this.satiety);
+ }
+
+ public void setType(TypeRobot type) {
+ this.type = type;
+ }
+
+ public TypeRobot getType() {
+ return this.type;
+ }
+
+ public void changeSatiety(int satiety) {
+ this.satiety += satiety;
+ this.type = getType(this.satiety);
+ }
+
+ public void setDimension(Dimension dimension) {
+ this.dimension = dimension;
+ if (!this.target.isPositionCorrect(dimension)) {
+ this.target = new Target((int)(Math.random() * (double)dimension.width), (int)(Math.random() * (double)dimension.height));
+ }
+
+ }
+
+ public Dimension getDimension() {
+ return this.dimension;
+ }
+
+ public double getPositionX() {
+ return this.positionX;
+ }
+
+ public void setPositionX(double positionX) {
+ this.positionX = positionX;
+ }
+
+ public double getPositionY() {
+ return this.positionY;
+ }
+
+ public void setPositionY(double positionY) {
+ this.positionY = positionY;
+ }
+
+ public double getRobotDirection() {
+ return this.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.0) {
+ angle += 6.283185307179586;
+ }
+
+ while(angle >= 6.283185307179586) {
+ angle -= 6.283185307179586;
+ }
+
+ return angle;
+ }
+
+ private double normalizedPositionX(double 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.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) {
+ return min;
+ } else {
+ return value > max ? max : value;
+ }
+ }
+
+ public Target getTarget() {
+ return this.target;
+ }
+
+ public void setTarget(Point point) {
+ this.target.setTargetPosition(point);
+ }
+
+ private void moveRobot(double velocity, double angularVelocity, double duration) {
+ 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 = this.getPositionX() + velocity * duration * Math.cos(this.getRobotDirection());
+ }
+
+ double newY = this.getPositionY() - velocity / angularVelocity * (Math.cos(this.getRobotDirection() + angularVelocity * duration) - Math.cos(this.getRobotDirection()));
+ if (!Double.isFinite(newY)) {
+ newY = this.getPositionY() + velocity * duration * Math.sin(this.getRobotDirection());
+ }
+
+ 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");
+ }
+
+ public void update() {
+ if (this.type != TypeRobot.DEAD) {
+ if (this.interactionWithEnvironment()) {
+ this.onTargetAchieved();
+ }
+
+ 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;
+ }
+
+ if (angleToTarget < this.getRobotDirection()) {
+ angularVelocity = -0.01;
+ }
+
+ this.moveRobot(0.1, angularVelocity, 10.0);
+ }
+ }
+
+ private boolean interactionWithEnvironment() {
+ double distance = distance((double)this.target.getX(), (double)this.target.getY(), this.getPositionX(), this.getPositionY());
+ return distance < 0.5;
+ }
+
+ public void onStart(PropertyChangeSupport publisher) {
+ publisher.addPropertyChangeListener(this);
+ }
+
+ private void onTargetAchieved() {
+ this.setTarget(new Point((int)(Math.random() * (double)this.dimension.width), (int)(Math.random() * (double)this.dimension.height)));
+ this.satiety += 25;
+ 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;
+ }
+ }
+
+ public void propertyChange(PropertyChangeEvent evt) {
+ if (evt.getPropertyName().equals("new point")) {
+ this.setTarget((Point)evt.getNewValue());
+ }
+
+ if (evt.getPropertyName().equals("change satiety")) {
+ this.changeSatiety((Integer)evt.getNewValue());
+ }
+
+ if (evt.getPropertyName().equals("set dimension")) {
+ this.setDimension((Dimension)evt.getNewValue());
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/robots/src/main/java/model/Target.java b/robots/src/main/java/model/Target.java
new file mode 100644
index 000000000..4689da897
--- /dev/null
+++ b/robots/src/main/java/model/Target.java
@@ -0,0 +1,56 @@
+package main.java.model;
+
+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;
+
+ 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 this.x;
+ }
+
+ public int getY() {
+ return this.y;
+ }
+
+ public void setTargetPosition(Point p) {
+ this.setX(p.x);
+ this.setY(p.y);
+ }
+
+ public boolean isPositionCorrect(Dimension dimension) {
+ return this.x <= dimension.width && this.y <= dimension.height;
+ }
+
+ public void update() {
+ }
+
+ public void onStart(PropertyChangeSupport publisher) {
+ publisher.addPropertyChangeListener(this);
+ }
+
+ public void propertyChange(PropertyChangeEvent evt) {
+ }
+}
diff --git a/robots/src/main/java/model/TypeRobot.java b/robots/src/main/java/model/TypeRobot.java
new file mode 100644
index 000000000..5d169b871
--- /dev/null
+++ b/robots/src/main/java/model/TypeRobot.java
@@ -0,0 +1,27 @@
+package main.java.model;
+
+import java.awt.Color;
+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 (TypeRobot)VALUES.get(RANDOM.nextInt(values().length - 2));
+ }
+
+ private TypeRobot(Color color) {
+ this.color = color;
+ }
+
+ public Color getColor() {
+ return this.color;
+ }
+}
diff --git a/robots/src/main/java/view/GameDrawer.java b/robots/src/main/java/view/GameDrawer.java
new file mode 100644
index 000000000..93c2fc185
--- /dev/null
+++ b/robots/src/main/java/view/GameDrawer.java
@@ -0,0 +1,20 @@
+package main.java.view;
+
+import main.java.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..bc33ab0b1
--- /dev/null
+++ b/robots/src/main/java/view/GameView.java
@@ -0,0 +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.GameModel;
+import main.java.model.Robot;
+import main.java.model.Target;
+
+public class GameView extends JPanel {
+ private final GameModel gameModel;
+ private final Map, GameDrawer> map;
+
+ public GameView(GameModel gameModel) {
+ this.gameModel = gameModel;
+ 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() {
+ this.onRedrawEvent();
+ }
+
+ protected void onRedrawEvent() {
+ EventQueue.invokeLater(this::repaint);
+ }
+
+ 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);
+ 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());
+ }
+ }
+
+ }
+}
diff --git a/robots/src/main/java/view/RobotDrawer.java b/robots/src/main/java/view/RobotDrawer.java
new file mode 100644
index 000000000..e2abec51e
--- /dev/null
+++ b/robots/src/main/java/view/RobotDrawer.java
@@ -0,0 +1,54 @@
+package main.java.view;
+
+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 {
+ 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());
+ AffineTransform l = new AffineTransform(oldTransform);
+ 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);
+ 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);
+ }
+
+ public Class> getDrawingType() {
+ return Robot.class;
+ }
+}
diff --git a/robots/src/main/java/view/TargetDrawer.java b/robots/src/main/java/view/TargetDrawer.java
new file mode 100644
index 000000000..5cc58da8f
--- /dev/null
+++ b/robots/src/main/java/view/TargetDrawer.java
@@ -0,0 +1,26 @@
+package main.java.view;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import main.java.model.Entity;
+import main.java.model.Target;
+
+public class TargetDrawer extends GameDrawer {
+ public TargetDrawer() {
+ }
+
+ public void draw(Graphics2D g, Entity entity) {
+ 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);
+ }
+
+ }
+
+ 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..9ac8c8250
--- /dev/null
+++ b/robots/src/main/java/view/ViewModel.java
@@ -0,0 +1,69 @@
+package main.java.view;
+
+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 GameModel gameModel;
+ private final GameWindow gameWindow;
+ private final Timer timer = initTimer();
+
+ private static Timer initTimer() {
+ return new Timer("events generator", true);
+ }
+
+ public ViewModel(GameModel gameModel, GameWindow gameWindow) {
+ this.gameModel = gameModel;
+ this.gameWindow = gameWindow;
+ this.initListeners();
+ }
+
+ private void initListeners() {
+ this.timer.schedule(new TimerTask() {
+ public void run() {
+ ViewModel.this.gameModel.setDimension(ViewModel.this.gameWindow.getSize());
+ ViewModel.this.getGameView().updateView();
+ }
+ }, 0L, 5L);
+ this.timer.schedule(new TimerTask() {
+ public void run() {
+ ViewModel.this.gameModel.updateModel();
+ }
+ }, 0L, 5L);
+ this.gameWindow.getGameView().addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ ViewModel.this.gameModel.setTarget(e.getPoint());
+ ViewModel.this.getGameView().repaint();
+ }
+ });
+ this.gameWindow.addComponentListener(new ComponentAdapter() {
+ public void componentResized(ComponentEvent e) {
+ super.componentResized(e);
+ System.out.println("resize");
+ ViewModel.this.gameModel.setDimension(ViewModel.this.gameWindow.getSize());
+ System.out.println(ViewModel.this.gameModel.getDimension());
+ }
+ });
+ this.gameWindow.getGameView().addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ System.out.println(e.getPoint());
+ ViewModel.this.gameModel.setTarget(e.getPoint());
+ ViewModel.this.getGameView().repaint();
+ }
+ });
+ }
+
+ public GameView getGameView() {
+ return this.gameWindow.getGameView();
+ }
+
+ public GameWindow getGameWindow() {
+ return this.gameWindow;
+ }
+}
diff --git a/target/classes/main/java/gui/GameWindow.class b/target/classes/main/java/gui/GameWindow.class
new file mode 100644
index 000000000..335ba1ee7
Binary files /dev/null and b/target/classes/main/java/gui/GameWindow.class differ
diff --git a/target/classes/main/java/gui/LogWindow.class b/target/classes/main/java/gui/LogWindow.class
new file mode 100644
index 000000000..72799906e
Binary files /dev/null and b/target/classes/main/java/gui/LogWindow.class differ
diff --git a/target/classes/main/java/gui/MainApplicationFrame.class b/target/classes/main/java/gui/MainApplicationFrame.class
new file mode 100644
index 000000000..89647e6c5
Binary files /dev/null and b/target/classes/main/java/gui/MainApplicationFrame.class differ
diff --git a/target/classes/main/java/gui/PositionWindow.class b/target/classes/main/java/gui/PositionWindow.class
new file mode 100644
index 000000000..68b457143
Binary files /dev/null and b/target/classes/main/java/gui/PositionWindow.class differ
diff --git a/target/classes/main/java/gui/RobotsProgram.class b/target/classes/main/java/gui/RobotsProgram.class
new file mode 100644
index 000000000..83e760373
Binary files /dev/null and b/target/classes/main/java/gui/RobotsProgram.class differ
diff --git a/target/classes/main/java/gui/Translatable.class b/target/classes/main/java/gui/Translatable.class
new file mode 100644
index 000000000..04aa1cd4f
Binary files /dev/null and b/target/classes/main/java/gui/Translatable.class differ
diff --git a/target/classes/main/java/log/LogChangeListener.class b/target/classes/main/java/log/LogChangeListener.class
new file mode 100644
index 000000000..490acfe49
Binary files /dev/null and b/target/classes/main/java/log/LogChangeListener.class differ
diff --git a/target/classes/main/java/log/LogEntry.class b/target/classes/main/java/log/LogEntry.class
new file mode 100644
index 000000000..851ee5c3f
Binary files /dev/null and b/target/classes/main/java/log/LogEntry.class differ
diff --git a/target/classes/main/java/log/LogLevel.class b/target/classes/main/java/log/LogLevel.class
new file mode 100644
index 000000000..88eaf72a4
Binary files /dev/null and b/target/classes/main/java/log/LogLevel.class differ
diff --git a/target/classes/main/java/log/LogWindowSource.class b/target/classes/main/java/log/LogWindowSource.class
new file mode 100644
index 000000000..358e3cb6f
Binary files /dev/null and b/target/classes/main/java/log/LogWindowSource.class differ
diff --git a/target/classes/main/java/log/Logger.class b/target/classes/main/java/log/Logger.class
new file mode 100644
index 000000000..bb1a92cfd
Binary files /dev/null and b/target/classes/main/java/log/Logger.class differ
diff --git a/target/classes/main/java/model/Entity.class b/target/classes/main/java/model/Entity.class
new file mode 100644
index 000000000..254baba41
Binary files /dev/null and b/target/classes/main/java/model/Entity.class differ
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 000000000..8d07e96cf
Binary files /dev/null and b/target/classes/main/java/model/GameModel$1.class differ
diff --git a/target/classes/main/java/model/GameModel.class b/target/classes/main/java/model/GameModel.class
new file mode 100644
index 000000000..5b1a82277
Binary files /dev/null and b/target/classes/main/java/model/GameModel.class differ
diff --git a/target/classes/main/java/model/Robot.class b/target/classes/main/java/model/Robot.class
new file mode 100644
index 000000000..37c96380a
Binary files /dev/null and b/target/classes/main/java/model/Robot.class differ
diff --git a/target/classes/main/java/model/Target.class b/target/classes/main/java/model/Target.class
new file mode 100644
index 000000000..0d6518bbc
Binary files /dev/null and b/target/classes/main/java/model/Target.class differ
diff --git a/target/classes/main/java/model/TypeRobot.class b/target/classes/main/java/model/TypeRobot.class
new file mode 100644
index 000000000..3d97ff4e2
Binary files /dev/null and b/target/classes/main/java/model/TypeRobot.class differ
diff --git a/target/classes/main/java/view/GameDrawer.class b/target/classes/main/java/view/GameDrawer.class
new file mode 100644
index 000000000..141239f18
Binary files /dev/null and b/target/classes/main/java/view/GameDrawer.class differ
diff --git a/target/classes/main/java/view/GameView.class b/target/classes/main/java/view/GameView.class
new file mode 100644
index 000000000..8912b410b
Binary files /dev/null and b/target/classes/main/java/view/GameView.class differ
diff --git a/target/classes/main/java/view/RobotDrawer.class b/target/classes/main/java/view/RobotDrawer.class
new file mode 100644
index 000000000..00c3e89e4
Binary files /dev/null and b/target/classes/main/java/view/RobotDrawer.class differ
diff --git a/target/classes/main/java/view/TargetDrawer.class b/target/classes/main/java/view/TargetDrawer.class
new file mode 100644
index 000000000..0e428003e
Binary files /dev/null and b/target/classes/main/java/view/TargetDrawer.class differ
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 000000000..452ca5abf
Binary files /dev/null and b/target/classes/main/java/view/ViewModel$1.class differ
diff --git a/target/classes/main/java/view/ViewModel$2.class b/target/classes/main/java/view/ViewModel$2.class
new file mode 100644
index 000000000..3227a5e49
Binary files /dev/null and b/target/classes/main/java/view/ViewModel$2.class differ
diff --git a/target/classes/main/java/view/ViewModel$3.class b/target/classes/main/java/view/ViewModel$3.class
new file mode 100644
index 000000000..4896743d4
Binary files /dev/null and b/target/classes/main/java/view/ViewModel$3.class differ
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 000000000..660924a0e
Binary files /dev/null and b/target/classes/main/java/view/ViewModel$4.class differ
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 000000000..e674289d2
Binary files /dev/null and b/target/classes/main/java/view/ViewModel$5.class differ
diff --git a/target/classes/main/java/view/ViewModel.class b/target/classes/main/java/view/ViewModel.class
new file mode 100644
index 000000000..d26139efb
Binary files /dev/null and b/target/classes/main/java/view/ViewModel.class differ