From 5183612c4555c86e0f16b5afe4de8350a22816cf Mon Sep 17 00:00:00 2001 From: massshasch Date: Wed, 24 May 2023 13:18:46 +0500 Subject: [PATCH 1/3] all tasks --- .idea/.gitignore | 3 + .idea/Robots.iml | 11 ++ .idea/modules.xml | 8 + .idea/vcs.xml | 6 + robots/src/gui/CoordinatesDrawer.java | 46 +++++ robots/src/gui/CoordinatesWindow.java | 32 +++ robots/src/gui/GameDrawer.java | 97 +++++++++ robots/src/gui/GameVisualizer.java | 210 -------------------- robots/src/gui/GameWindow.java | 20 +- robots/src/gui/LogWindow.java | 19 +- robots/src/gui/MainApplicationFrame.java | 238 ++++++++++++++++------- robots/src/gui/Parameters.java | 32 +++ robots/src/gui/RobotModel.java | 105 ++++++++++ robots/src/gui/RobotsProgram.java | 33 ++-- text.txt | 12 ++ 15 files changed, 550 insertions(+), 322 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/Robots.iml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 robots/src/gui/CoordinatesDrawer.java create mode 100644 robots/src/gui/CoordinatesWindow.java create mode 100644 robots/src/gui/GameDrawer.java delete mode 100644 robots/src/gui/GameVisualizer.java create mode 100644 robots/src/gui/Parameters.java create mode 100644 robots/src/gui/RobotModel.java create mode 100644 text.txt 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/Robots.iml b/.idea/Robots.iml new file mode 100644 index 000000000..8df936b5d --- /dev/null +++ b/.idea/Robots.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..650a13293 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ 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/gui/CoordinatesDrawer.java b/robots/src/gui/CoordinatesDrawer.java new file mode 100644 index 000000000..dea259afb --- /dev/null +++ b/robots/src/gui/CoordinatesDrawer.java @@ -0,0 +1,46 @@ +package gui; + +import javax.swing.*; +import java.awt.*; +import java.util.Timer; +import java.util.TimerTask; + +public class CoordinatesDrawer extends JPanel { + + private final java.util.Timer m_timer = initTimer(); + public Parameters parameters; + + private static java.util.Timer initTimer() { + java.util.Timer timer = new Timer("events generator", true); + return timer; + } + + public CoordinatesDrawer(Parameters parameters) { + this.parameters = parameters; + m_timer.schedule(new TimerTask() { + @Override + public void run() { + onRedrawEvent(); + } + }, 0, 50); + } + + + protected void onRedrawEvent() { + EventQueue.invokeLater(this::repaint); + } + + @Override + public void paint(Graphics g) { + super.paint(g); + Graphics2D g2d = (Graphics2D) g; + g2d.drawString("X: " + String.valueOf(parameters.m_robotPositionX), 25, 25); + g2d.drawString("Y: " + String.valueOf(parameters.m_robotPositionY), 25, 45); + g2d.drawString("DIRECTION: " + String.valueOf(parameters.m_robotDirection), 25, 65); + g2d.drawString("Target X: " + String.valueOf(parameters.m_targetPositionX), 25, 85); + g2d.drawString("Target Y: " + String.valueOf(parameters.m_targetPositionY), 25, 105); + setDoubleBuffered(true); + } + + +} diff --git a/robots/src/gui/CoordinatesWindow.java b/robots/src/gui/CoordinatesWindow.java new file mode 100644 index 000000000..4002e9767 --- /dev/null +++ b/robots/src/gui/CoordinatesWindow.java @@ -0,0 +1,32 @@ +package gui; + + +import javax.swing.*; +import java.awt.*; +import java.util.Observable; +import java.util.Observer; + +public class CoordinatesWindow extends JInternalFrame implements Observer { + + private CoordinatesDrawer drawer; + + public CoordinatesWindow(Parameters parameters) { + super("Текущие координаты робота", true, true, true, true); + + + drawer = new CoordinatesDrawer(parameters); + + JPanel panel = new JPanel(new BorderLayout()); + panel.add(drawer, BorderLayout.CENTER); + getContentPane().add(panel); + pack(); + + } + + @Override + public void update(Observable o, Object arg) { + var t = (Parameters) o; + drawer.parameters = t; + + } +} \ No newline at end of file diff --git a/robots/src/gui/GameDrawer.java b/robots/src/gui/GameDrawer.java new file mode 100644 index 000000000..39dbea2c5 --- /dev/null +++ b/robots/src/gui/GameDrawer.java @@ -0,0 +1,97 @@ +package gui; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.geom.AffineTransform; +import java.util.Observable; +import java.util.Observer; +import java.util.Timer; +import java.util.TimerTask; + + +public class GameDrawer extends JPanel implements Observer { + private final Timer m_timer = initTimer(); + private Parameters parameters; + + private static Timer initTimer() { + Timer timer = new Timer("events generator", true); + return timer; + } + + public GameDrawer(Parameters parameters) { + this.parameters = parameters; + m_timer.schedule(new TimerTask() { + @Override + public void run() { + onRedrawEvent(); + } + }, 0, 50); + + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + parameters.updateTarget(e.getPoint()); + repaint(); + } + }); + setDoubleBuffered(true); + + } + + protected void onRedrawEvent() { + EventQueue.invokeLater(this::repaint); + } + + @Override + public void paint(Graphics g) { + super.paint(g); + Graphics2D g2d = (Graphics2D) g; + drawRobot(g2d, round(parameters.m_robotPositionX), round(parameters.m_robotPositionY), parameters.m_robotDirection); + drawTarget(g2d, parameters.m_targetPositionX, parameters.m_targetPositionY); + setDoubleBuffered(true); + } + + 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(parameters.m_robotPositionX); + int robotCenterY = round(parameters.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); + } + + private static int round(double value) { + return (int) (value + 0.5); + } + + @Override + public void update(Observable o, Object arg) { + parameters = (Parameters) o; + repaint(); + } +} 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 index ecb63c00f..617b0aafb 100644 --- a/robots/src/gui/GameWindow.java +++ b/robots/src/gui/GameWindow.java @@ -1,20 +1,24 @@ package gui; import java.awt.BorderLayout; +import java.util.Observable; import javax.swing.JInternalFrame; import javax.swing.JPanel; -public class GameWindow extends JInternalFrame -{ - private final GameVisualizer m_visualizer; - public GameWindow() - { +public class GameWindow extends JInternalFrame { + private final GameDrawer m_drawer; + private final RobotModel m_robot; + + public GameWindow(Parameters parameters) { super("Игровое поле", true, true, true, true); - m_visualizer = new GameVisualizer(); + m_robot = new RobotModel(parameters); + m_drawer = new GameDrawer(parameters); + parameters.addObserver(m_drawer); + JPanel panel = new JPanel(new BorderLayout()); - panel.add(m_visualizer, BorderLayout.CENTER); + panel.add(m_drawer, BorderLayout.CENTER); getContentPane().add(panel); pack(); } -} +} \ No newline at end of file diff --git a/robots/src/gui/LogWindow.java b/robots/src/gui/LogWindow.java index 723d3e2fc..54884b614 100644 --- a/robots/src/gui/LogWindow.java +++ b/robots/src/gui/LogWindow.java @@ -11,19 +11,17 @@ import log.LogEntry; import log.LogWindowSource; -public class LogWindow extends JInternalFrame implements LogChangeListener -{ +public class LogWindow extends JInternalFrame implements LogChangeListener { 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 +29,17 @@ 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); } } diff --git a/robots/src/gui/MainApplicationFrame.java b/robots/src/gui/MainApplicationFrame.java index 62e943ee1..9fc25c900 100644 --- a/robots/src/gui/MainApplicationFrame.java +++ b/robots/src/gui/MainApplicationFrame.java @@ -3,107 +3,105 @@ import java.awt.Dimension; import java.awt.Toolkit; import java.awt.event.KeyEvent; +import java.beans.PropertyVetoException; +import java.io.*; -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 javax.swing.*; import log.Logger; +import static java.lang.Integer.parseInt; + /** * Что требуется сделать: - * 1. Метод создания меню перегружен функционалом и трудно читается. + * 1. Метод создания меню перегружен функционалом и трудно читается. * Следует разделить его на серию более простых методов (или вообще выделить отдельный класс). - * */ -public class MainApplicationFrame extends JFrame -{ +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; + int inset = 50; Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); setBounds(inset, inset, - screenSize.width - inset*2, - screenSize.height - inset*2); + screenSize.width - inset * 2, + screenSize.height - inset * 2); setContentPane(desktopPane); - - + + CreateInternalWindows(); + + setJMenuBar(generateMenuBar()); + setDefaultCloseOperation(EXIT_ON_CLOSE); + ReadPreviousSettings(); + + } + + private void ReadPreviousSettings() { + try (FileReader fr = new FileReader("text.txt");) { + var t = ""; + var c = 0; + while ((c = fr.read()) != -1) { + + t += (char) c; + } + SetPreviousParameters(t); + } catch (IOException ex) { + + System.out.println("не считали"); + } + } + + private void CreateInternalWindows() { LogWindow logWindow = createLogWindow(); addWindow(logWindow); + var parameters = new Parameters(); + + CoordinatesWindow coordinatesWindow = createCoordinatesWindow(parameters); + coordinatesWindow.setSize(300, 150); + coordinatesWindow.setMinimumSize(coordinatesWindow.getSize()); + addWindow(coordinatesWindow); - GameWindow gameWindow = new GameWindow(); - gameWindow.setSize(400, 400); + parameters.addObserver(coordinatesWindow); + + GameWindow gameWindow = new GameWindow(parameters); + gameWindow.setSize(400, 400); addWindow(gameWindow); + } - setJMenuBar(generateMenuBar()); - setDefaultCloseOperation(EXIT_ON_CLOSE); + private CoordinatesWindow createCoordinatesWindow(Parameters parameters) { + var coordinatesWindow = new CoordinatesWindow(parameters); + coordinatesWindow.setLocation(400, 400); + coordinatesWindow.pack(); + return coordinatesWindow; } - - protected LogWindow createLogWindow() - { + + protected LogWindow createLogWindow() { LogWindow logWindow = new LogWindow(Logger.getDefaultLogSource()); - logWindow.setLocation(10,10); + logWindow.setLocation(10, 10); logWindow.setSize(300, 800); setMinimumSize(logWindow.getSize()); logWindow.pack(); Logger.debug("Протокол работает"); return logWindow; } - - protected void addWindow(JInternalFrame frame) - { + + 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() - { + + 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) -> { @@ -122,11 +120,29 @@ private JMenuBar generateMenuBar() lookAndFeelMenu.add(crossplatformLookAndFeel); } + + JMenu file = new JMenu("Файл"); + file.setMnemonic(KeyEvent.VK_V); + file.getAccessibleContext().setAccessibleDescription( + "Управление приложением"); + { + JMenuItem closeMenu = new JMenuItem("Закрыть приложение", KeyEvent.VK_S); + closeMenu.addActionListener((event) -> { + int res = JOptionPane.showOptionDialog(null, "Закрыть приложение?", null, JOptionPane.YES_NO_OPTION, + JOptionPane.PLAIN_MESSAGE, null, new Object[]{"Да", "Нет"}, null); + if (res == 0) { + SaveParameters(); + System.exit(0); + } + }); + file.add(closeMenu); + } + JMenu testMenu = new JMenu("Тесты"); testMenu.setMnemonic(KeyEvent.VK_T); testMenu.getAccessibleContext().setAccessibleDescription( "Тестовые команды"); - + { JMenuItem addLogMessageItem = new JMenuItem("Сообщение в лог", KeyEvent.VK_S); addLogMessageItem.addActionListener((event) -> { @@ -135,21 +151,95 @@ private JMenuBar generateMenuBar() testMenu.add(addLogMessageItem); } + menuBar.add(file); menuBar.add(lookAndFeelMenu); menuBar.add(testMenu); return menuBar; } - - private void setLookAndFeel(String className) - { - try - { + + private void SaveParameters() { + //var temp =""; + try (FileWriter writer = new FileWriter("text.txt", false)) { + + var t = this.desktopPane.getAllFrames(); + + for (int i = 0; i < t.length; i++) { + var location = t[i].getLocation(); + var size = t[i].getSize(); + var isShowing = t[i].isShowing(); + + t[i].setResizable(true); + var temp = t[i].getTitle() + "\n" + location.x + " " + location.y + "\n" + size.width + " " + size.height + "\n" + (isShowing ? "T" : "F") + "\n"; +// writer.write(location.x+" "+ location.y + "\n"); +// writer.write(size.width+" "+ size.height + "\n"); +// writer.write(isShowing?"T":"F"); +// writer.write("\n"); + writer.write(temp); + } + writer.flush(); + } catch (IOException ex) { + + System.out.println("не сохранили"); + } + + //System.out.println(temp); + } + + private void SetPreviousParameters(String text) { + if (text.length() == 0) + return; + var t = this.desktopPane.getAllFrames(); + var arr = text.split("\n"); + var p = 0; + var counter = 0; + while (counter < t.length) { + for (int i = 0; i < t.length; i++) { + var name = arr[0 + p + counter]; + if (t[i].getTitle().equals(name)) { + var current = t[i]; + var location = arr[counter + p + 1].split(" "); + current.setLocation(parseInt(location[0]), parseInt(location[1])); + var size = arr[counter + 2 + p].split(" "); + current.setSize(parseInt(size[0]), parseInt(size[1])); + var showing = arr[counter + 3 + p]; + current.setBounds(parseInt(location[0]), parseInt(location[1]), parseInt(size[0]), parseInt(size[1])); + if (showing.equals("F")) { + try { + current.setIcon(true); + } catch (PropertyVetoException e) { + throw new RuntimeException(e); + } + } + p += 3; + counter += 1; + break; + } + } + } +// for (int i = 0; i parameters.m_robotDirection) { + angularVelocity = maxAngularVelocity; + } + if (angleToTarget < parameters.m_robotDirection) { + angularVelocity = -maxAngularVelocity; + } + + + moveRobot(velocity, angularVelocity, 10); + } + + 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 void moveRobot(double velocity, double angularVelocity, double duration) { + velocity = applyLimits(velocity, 0, maxVelocity); + angularVelocity = applyLimits(angularVelocity, -maxAngularVelocity, maxAngularVelocity); + double newX = parameters.m_robotPositionX + velocity / angularVelocity * + (Math.sin(parameters.m_robotDirection + angularVelocity * duration) - + Math.sin(parameters.m_robotDirection)); + if (!Double.isFinite(newX)) { + newX = parameters.m_robotPositionX + velocity * duration * Math.cos(parameters.m_robotDirection); + } + double newY = parameters.m_robotPositionY - velocity / angularVelocity * + (Math.cos(parameters.m_robotDirection + angularVelocity * duration) - + Math.cos(parameters.m_robotDirection)); + if (!Double.isFinite(newY)) { + newY = parameters.m_robotPositionY + velocity * duration * Math.sin(parameters.m_robotDirection); + } + double newDirection = asNormalizedRadians(parameters.m_robotDirection + angularVelocity * duration); + parameters.updateRobot(newX, newY, 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 double applyLimits(double value, double min, double max) { + if (value < min) + return min; + if (value > max) + return max; + return value; + } + + +} diff --git a/robots/src/gui/RobotsProgram.java b/robots/src/gui/RobotsProgram.java index ae0930a8b..3051d62f4 100644 --- a/robots/src/gui/RobotsProgram.java +++ b/robots/src/gui/RobotsProgram.java @@ -5,21 +5,18 @@ 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); - }); - }} +public class RobotsProgram { + public static void main(String[] args) { + try { + UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); + } catch (Exception e) { + e.printStackTrace(); + } + SwingUtilities.invokeLater(() -> { + MainApplicationFrame frame = new MainApplicationFrame(); + frame.pack(); + frame.setVisible(true); + frame.setExtendedState(Frame.MAXIMIZED_BOTH); + }); + } +} diff --git a/text.txt b/text.txt new file mode 100644 index 000000000..e2469fecb --- /dev/null +++ b/text.txt @@ -0,0 +1,12 @@ +Текущие координаты робота +1076 525 +300 150 +T +Игровое поле +913 58 +400 400 +T +Протокол работы +10 10 +212 524 +T From d792346ca39901b63bfb98342f8b5ca4c1e5639f Mon Sep 17 00:00:00 2001 From: massshasch Date: Wed, 24 May 2023 16:15:09 +0500 Subject: [PATCH 2/3] robot moving --- robots/src/gui/RobotModel.java | 54 +++++++++------------------------- 1 file changed, 14 insertions(+), 40 deletions(-) diff --git a/robots/src/gui/RobotModel.java b/robots/src/gui/RobotModel.java index b454f1276..b84e27684 100644 --- a/robots/src/gui/RobotModel.java +++ b/robots/src/gui/RobotModel.java @@ -43,19 +43,20 @@ protected void onModelUpdateEvent() { if (distance < 0.5) { return; } - parameters.m_robotDirection = asNormalizedRadians(parameters.m_robotDirection); - double velocity = maxVelocity; - double angleToTarget = angleTo(parameters.m_robotPositionX, parameters.m_robotPositionY, parameters.m_targetPositionX, parameters.m_targetPositionY); - double angularVelocity = 0; - if (angleToTarget > parameters.m_robotDirection) { - angularVelocity = maxAngularVelocity; - } - if (angleToTarget < parameters.m_robotDirection) { - angularVelocity = -maxAngularVelocity; - } - - - moveRobot(velocity, angularVelocity, 10); + var newX = parameters.m_robotPositionX; + var newY = parameters.m_robotPositionY; + var koef = 0.4; + + if (parameters.m_robotPositionX < parameters.m_targetPositionX) + newX += koef; + if (parameters.m_robotPositionY < parameters.m_targetPositionY) + newY += koef; + if (parameters.m_robotPositionX > parameters.m_targetPositionX) + newX -= koef; + if (parameters.m_robotPositionY > parameters.m_targetPositionY) + newY -= koef; + var dir = angleTo(newX, newY, parameters.m_targetPositionX, parameters.m_targetPositionY); + parameters.updateRobot(newX, newY, dir); } private static double angleTo(double fromX, double fromY, double toX, double toY) { @@ -64,25 +65,6 @@ private static double angleTo(double fromX, double fromY, double toX, double toY return asNormalizedRadians(Math.atan2(diffY, diffX)); } - private void moveRobot(double velocity, double angularVelocity, double duration) { - velocity = applyLimits(velocity, 0, maxVelocity); - angularVelocity = applyLimits(angularVelocity, -maxAngularVelocity, maxAngularVelocity); - double newX = parameters.m_robotPositionX + velocity / angularVelocity * - (Math.sin(parameters.m_robotDirection + angularVelocity * duration) - - Math.sin(parameters.m_robotDirection)); - if (!Double.isFinite(newX)) { - newX = parameters.m_robotPositionX + velocity * duration * Math.cos(parameters.m_robotDirection); - } - double newY = parameters.m_robotPositionY - velocity / angularVelocity * - (Math.cos(parameters.m_robotDirection + angularVelocity * duration) - - Math.cos(parameters.m_robotDirection)); - if (!Double.isFinite(newY)) { - newY = parameters.m_robotPositionY + velocity * duration * Math.sin(parameters.m_robotDirection); - } - double newDirection = asNormalizedRadians(parameters.m_robotDirection + angularVelocity * duration); - parameters.updateRobot(newX, newY, newDirection); - } - private static double asNormalizedRadians(double angle) { while (angle < 0) { angle += 2 * Math.PI; @@ -93,13 +75,5 @@ private static double asNormalizedRadians(double angle) { return angle; } - private static double applyLimits(double value, double min, double max) { - if (value < min) - return min; - if (value > max) - return max; - return value; - } - } From 73fdc9faf5b166ebbc2fe112bc4c8d63900f98f0 Mon Sep 17 00:00:00 2001 From: massshasch Date: Fri, 2 Jun 2023 14:13:50 +0500 Subject: [PATCH 3/3] added optional task --- robots/src/gui/CoordinatesDrawer.java | 2 + robots/src/gui/GameWindow.java | 3 + robots/src/gui/LogWindow.java | 2 +- robots/src/gui/MainApplicationFrame.java | 1 - robots/src/gui/Parameters.java | 4 + robots/src/gui/RobotModel.java | 2 + robots/src/log/List.java | 123 +++++++++++++++++++++++ robots/src/log/LogWindowSource.java | 100 +++++++----------- 8 files changed, 173 insertions(+), 64 deletions(-) create mode 100644 robots/src/log/List.java diff --git a/robots/src/gui/CoordinatesDrawer.java b/robots/src/gui/CoordinatesDrawer.java index dea259afb..b4ff55b1f 100644 --- a/robots/src/gui/CoordinatesDrawer.java +++ b/robots/src/gui/CoordinatesDrawer.java @@ -1,5 +1,7 @@ package gui; +import log.Logger; + import javax.swing.*; import java.awt.*; import java.util.Timer; diff --git a/robots/src/gui/GameWindow.java b/robots/src/gui/GameWindow.java index 617b0aafb..0c16319e6 100644 --- a/robots/src/gui/GameWindow.java +++ b/robots/src/gui/GameWindow.java @@ -1,5 +1,7 @@ package gui; +import log.Logger; + import java.awt.BorderLayout; import java.util.Observable; @@ -12,6 +14,7 @@ public class GameWindow extends JInternalFrame { public GameWindow(Parameters parameters) { super("Игровое поле", true, true, true, true); + Logger.debug("Создано игровое поле"); m_robot = new RobotModel(parameters); m_drawer = new GameDrawer(parameters); parameters.addObserver(m_drawer); diff --git a/robots/src/gui/LogWindow.java b/robots/src/gui/LogWindow.java index 54884b614..58a1958da 100644 --- a/robots/src/gui/LogWindow.java +++ b/robots/src/gui/LogWindow.java @@ -35,7 +35,7 @@ private void updateLogContent() { content.append(entry.getMessage()).append("\n"); } m_logContent.setText(content.toString()); - m_logContent.invalidate(); + // m_logContent.invalidate(); } @Override diff --git a/robots/src/gui/MainApplicationFrame.java b/robots/src/gui/MainApplicationFrame.java index 9fc25c900..da9cd59d6 100644 --- a/robots/src/gui/MainApplicationFrame.java +++ b/robots/src/gui/MainApplicationFrame.java @@ -32,7 +32,6 @@ public MainApplicationFrame() { setContentPane(desktopPane); CreateInternalWindows(); - setJMenuBar(generateMenuBar()); setDefaultCloseOperation(EXIT_ON_CLOSE); ReadPreviousSettings(); diff --git a/robots/src/gui/Parameters.java b/robots/src/gui/Parameters.java index 8dd0d4682..66bcd2b3f 100644 --- a/robots/src/gui/Parameters.java +++ b/robots/src/gui/Parameters.java @@ -1,5 +1,7 @@ package gui; +import log.Logger; + import java.awt.*; import java.util.Observable; @@ -18,6 +20,7 @@ public class Parameters extends Observable { public void updateTarget(Point point) { m_targetPositionX = point.x; m_targetPositionY = point.y; + Logger.debug("Переместили цель"); setChanged(); notifyObservers(); } @@ -26,6 +29,7 @@ public void updateRobot(double pX, double pY, double dir) { m_robotPositionX = pX; m_robotPositionY = pY; m_robotDirection = dir; + //Logger.debug("Новые координаты: "+ pX + " " + pY); setChanged(); notifyObservers(); } diff --git a/robots/src/gui/RobotModel.java b/robots/src/gui/RobotModel.java index b84e27684..1d96e7b6b 100644 --- a/robots/src/gui/RobotModel.java +++ b/robots/src/gui/RobotModel.java @@ -1,5 +1,7 @@ package gui; +import log.Logger; + import javax.swing.*; import java.awt.*; import java.util.Timer; diff --git a/robots/src/log/List.java b/robots/src/log/List.java new file mode 100644 index 000000000..4eb3c4c34 --- /dev/null +++ b/robots/src/log/List.java @@ -0,0 +1,123 @@ +package log; + +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicReference; + +import static java.lang.System.*; + +/** + * Что починить: + * 1. Этот класс порождает утечку ресурсов (связанные слушатели оказываются + * удерживаемыми в памяти) + * 2. Этот класс хранит активные сообщения лога, но в такой реализации он + * их лишь накапливает. Надо же, чтобы количество сообщений в логе было ограничено + * величиной m_iQueueLength (т.е. реально нужна очередь сообщений + * ограниченного размера) + */ +public class List { + private final int size; + public int curSize; + + public List(int size) { + this.size = size; + curSize = 0; + } + + private static class Node { + final LogEntry item; + final AtomicReference next; + + Node(LogEntry item, Node next) { + this.item = item; + this.next = new AtomicReference(next); + } + } + + private AtomicReference tail = new AtomicReference<>(); + private AtomicReference head + = new AtomicReference(new Node(null, null)); + + public void put(LogEntry item) { + Node newNode = new Node(item, null); + var curHead = head.get(); + if (curHead.item == null || size == 1) { + if (!head.compareAndSet(curHead, newNode)) { + put(item); + return; + } + curSize++; + return; + } + if (tail.get() == null) { + if (!tail.compareAndSet(null, newNode)) { + put(item); + return; + } + if (!head.get().next.compareAndSet(null, tail.get())) { + put(item); + return; + } + curSize++; + return; + } + if (!tail.get().next.compareAndSet(null, newNode)) { + put(item); + return; + } + var previous = tail.get(); + if (!tail.compareAndSet(previous, previous.next.get())) { + put(item); + return; + } + curSize++; + if (size < curSize) { + var cur = head.get(); + if (!head.compareAndSet(cur, cur.next.get())) { + put(item); + return; + } + curSize--; + } + + } + + public int size() { + return curSize; + } + + public Node[] getCurNodes() { + var result = new Node[size]; + var curIndex = 0; + var start = this.head; + while (start.get() != null && start.get().item != null) { + synchronized (start.get()) { + var prev = start.get(); + result[curIndex] = prev; + start = prev.next; + curIndex++; + } + } + + return result; + } + + public Iterable range(int startFrom, int count) { + var nodeList = Arrays.copyOfRange(getCurNodes(), startFrom, count); + var result = new LogEntry[nodeList.length]; + var cur = 0; + for (Node node : nodeList) { + result[cur] = node.item; + cur++; + } + return java.util.List.of(result); + } + + public void print(Node[] arr) { + for (Node node : arr) { + if (node != null) + out.println(node.item.getMessage()); + } + System.out.println("*****"); + } + +} diff --git a/robots/src/log/LogWindowSource.java b/robots/src/log/LogWindowSource.java index ca0ce4426..56c39f142 100644 --- a/robots/src/log/LogWindowSource.java +++ b/robots/src/log/LogWindowSource.java @@ -3,87 +3,63 @@ import java.util.ArrayList; import java.util.Collections; -/** - * Что починить: - * 1. Этот класс порождает утечку ресурсов (связанные слушатели оказываются - * удерживаемыми в памяти) - * 2. Этот класс хранит активные сообщения лога, но в такой реализации он - * их лишь накапливает. Надо же, чтобы количество сообщений в логе было ограничено - * величиной m_iQueueLength (т.е. реально нужна очередь сообщений - * ограниченного размера) - */ -public class LogWindowSource -{ +public class LogWindowSource { + /** + * Что починить: + * 1. Этот класс порождает утечку ресурсов (связанные слушатели оказываются + * удерживаемыми в памяти) + * 2. Этот класс хранит активные сообщения лога, но в такой реализации он + * их лишь накапливает. Надо же, чтобы количество сообщений в логе было ограничено + * величиной m_iQueueLength (т.е. реально нужна очередь сообщений + * ограниченного размера) + */ private int m_iQueueLength; - - private ArrayList m_messages; + + private List m_msgs; private final ArrayList m_listeners; - private volatile LogChangeListener[] m_activeListeners; - - public LogWindowSource(int iQueueLength) - { + + public LogWindowSource(int iQueueLength) { m_iQueueLength = iQueueLength; - m_messages = new ArrayList(iQueueLength); - m_listeners = new ArrayList(); + m_msgs = new List(30); + m_listeners = new ArrayList<>(); } - - public void registerListener(LogChangeListener listener) - { - synchronized(m_listeners) - { + + public void registerListener(LogChangeListener listener) { + synchronized (m_listeners) { m_listeners.add(listener); - m_activeListeners = null; } } - - public void unregisterListener(LogChangeListener listener) - { - synchronized(m_listeners) - { + + public void unregisterListener(LogChangeListener listener) { + synchronized (m_listeners) { m_listeners.remove(listener); - m_activeListeners = null; } } - - public void append(LogLevel logLevel, String strMessage) - { + + 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; - } + m_msgs.put(entry); + + synchronized (m_listeners) { + for (LogChangeListener listener : m_listeners) { + listener.onLogChanged(); } } - for (LogChangeListener listener : activeListeners) - { - listener.onLogChanged(); - } } - - public int size() - { - return m_messages.size(); + + public int size() { + return m_msgs.size(); } - public Iterable range(int startFrom, int count) - { - if (startFrom < 0 || startFrom >= m_messages.size()) - { + public Iterable range(int startFrom, int count) { + if (startFrom < 0 || startFrom >= m_msgs.size()) { return Collections.emptyList(); } - int indexTo = Math.min(startFrom + count, m_messages.size()); - return m_messages.subList(startFrom, indexTo); + int indexTo = Math.min(startFrom + count, m_msgs.size()); + return m_msgs.range(startFrom, indexTo); } - public Iterable all() - { - return m_messages; + public Iterable all() { + return m_msgs.range(0, size()); } }