// // = FILENAME // Minesweep.java // // = FUNCTION // // This is the main control for the mine sweep process. You can run it in // three different modes: // 1. Manual mode: user clicks on the mines // 2. Auto mode : agent plays // 3. Server mode: agent can connect via sockets and play // // = AUTHOR(S) // Patric Jensfelt // // = COPYRIGHT // Copyright (c) 2005 Patric Jensfelt // /*----------------------------------------------------------------------*/ import java.awt.*; import javax.swing.*; import java.awt.event.*; import java.io.*; import java.net.*; import java.util.Timer; import java.util.TimerTask; import java.util.Random; public class Minesweep extends JFrame implements ItemListener, ActionListener, Runnable { ///////////////////////////////////////////////////////// ///////////////////////////////////////////////////////// protected class NewConnListener extends Thread implements Runnable { Minesweep m_Parent = null; int m_Port; public NewConnListener(Minesweep parent, int port) { m_Parent = parent; m_Port = port; } public void run() { try { ServerSocket ss = new ServerSocket(m_Port); System.out.println("Minesweep Server listening on port " + m_Port); while ( true ) { Socket s = ss.accept(); System.out.println("NewConnListener::Got client"); m_Parent.addClient(s); } } catch (Exception exc) { System.out.println("Coud not open ServerSocket on port " + m_Port); } } }; protected class AgentClient { public Socket m_Socket; public InputStream m_InRaw; public BufferedReader m_In; public PrintWriter m_Out; public int m_Id; public String m_Name; public boolean m_Peeked; public boolean m_Active; public int m_Score; public long m_UsedTime; public double m_TimeFraction; }; ///////////////////////////////////////////////////////// ///////////////////////////////////////////////////////// private static int MANUAL_MODE = 0; private static int AUTO_MODE = 1; private static int SERVER_MODE = 2; private Thread m_SecondThread = null; private MineField m_Field = null; private String m_MineFile = null; private FileReader m_BatchFile = null; private BufferedReader m_BatchReader = null; private FileWriter m_BatchResFile = null; private BufferedWriter m_BatchResWriter = null; JCheckBoxMenuItem m_UseRandom; private int m_PlayMode; private boolean m_StartPlay; private boolean m_Playing; private int m_GameNumber; private int m_GameId = 0; private int m_AutoScore; private JTextField m_TextXSize; private JTextField m_TextYSize; private JTextField m_TextDens; private JTextField m_TextDeadCost; private JTextField m_TextPeekCost; private JTextField m_TextNumOpen; private JCheckBoxMenuItem m_SlowSpeedAuto = null; private JCheckBoxMenuItem m_TwoPlayerGame = null; private JCheckBoxMenuItem m_SaveGameBoards = null; private JCheckBoxMenuItem m_AutoRestart = null; private JCheckBoxMenuItem m_OnlySave = null; private JCheckBoxMenuItem m_ShowStats = null; private JCheckBoxMenuItem m_RandomPeekCost = null; private JCheckBoxMenuItem m_RandomDeadCost = null; private JCheckBoxMenuItem m_RandomDensity = null; private JCheckBoxMenuItem m_RandomBoardSize = null; private MineAgent m_Agent = null; private Thread m_TimerThread = null; private boolean m_StoppedGame = false; private boolean m_GameStopPressed = false; private long m_StartTime = -1; private StatWindow m_StatWin = null; private NewConnListener m_ConnListener = null; private AgentClient m_Clients[] = null; int m_NumClients = 0; // Parameters private long m_MaxGameTimeSec = 300; private double m_Density; private int m_DeadCost = 10; private int m_PeekCost = 15; private int m_ServerPort; public Minesweep(int port, int xsize, int ysize, double density, int deadCost, int peekCost) { setTitle("Mine sweep"); m_ServerPort = port; m_Density = density; m_DeadCost = deadCost; m_PeekCost = peekCost; //Create the menu bar. JMenuBar menuBar = new JMenuBar(); JMenu fmenu = new JMenu("File"); JMenuItem loadItem = new JMenuItem("Load mine file"); loadItem.addActionListener(this); fmenu.add(loadItem); JMenuItem saveItem = new JMenuItem("Save mine file"); saveItem.addActionListener(this); fmenu.add(saveItem); m_UseRandom = new JCheckBoxMenuItem("Randomize"); m_UseRandom.setSelected(true); m_UseRandom.addActionListener(this); fmenu.add(m_UseRandom); JMenuItem batchItem = new JMenuItem("Run batch file test"); batchItem.addActionListener(this); fmenu.add(batchItem); JMenuItem quitItem = new JMenuItem("Quit"); quitItem.addActionListener(this); fmenu.add(quitItem); menuBar.add(fmenu); JMenu mmenu = new JMenu("Mode"); ButtonGroup group = new ButtonGroup(); JRadioButtonMenuItem rbMenuItem = new JRadioButtonMenuItem("Manual mode"); rbMenuItem.setSelected(false); rbMenuItem.addItemListener(this); mmenu.add(rbMenuItem); group.add(rbMenuItem); rbMenuItem = new JRadioButtonMenuItem("Auto mode"); rbMenuItem.setSelected(false); rbMenuItem.addItemListener(this); mmenu.add(rbMenuItem); group.add(rbMenuItem); rbMenuItem = new JRadioButtonMenuItem("Server mode"); rbMenuItem.setSelected(true); rbMenuItem.addItemListener(this); mmenu.add(rbMenuItem); group.add(rbMenuItem); m_PlayMode = SERVER_MODE; menuBar.add(mmenu); JMenu smenu = new JMenu("Settings"); m_SlowSpeedAuto = new JCheckBoxMenuItem("Slow auto"); m_SlowSpeedAuto.setSelected(false); smenu.add(m_SlowSpeedAuto); m_TwoPlayerGame = new JCheckBoxMenuItem("Two player game"); m_TwoPlayerGame.setSelected(false); smenu.add(m_TwoPlayerGame); m_SaveGameBoards = new JCheckBoxMenuItem("Save game boards"); m_SaveGameBoards.setSelected(false); smenu.add(m_SaveGameBoards); m_AutoRestart = new JCheckBoxMenuItem("Auto restart"); m_AutoRestart.setSelected(true); smenu.add(m_AutoRestart); m_OnlySave = new JCheckBoxMenuItem("Only save files"); m_OnlySave.setSelected(false); m_OnlySave.addActionListener(this); smenu.add(m_OnlySave); menuBar.add(smenu); smenu = new JMenu("Statistics"); m_ShowStats = new JCheckBoxMenuItem("Show Statistics"); m_ShowStats.setSelected(true); m_ShowStats.addActionListener(this); smenu.add(m_ShowStats); JMenuItem mi = new JMenuItem("Clear statistics"); mi.addActionListener(this); smenu.add(mi); menuBar.add(smenu); JMenu rmenu = new JMenu("Random"); m_RandomDensity = new JCheckBoxMenuItem("Random density"); m_RandomDensity.setSelected(true); rmenu.add(m_RandomDensity); m_RandomDeadCost = new JCheckBoxMenuItem("Random deadCost"); m_RandomDeadCost.setSelected(true); rmenu.add(m_RandomDeadCost); m_RandomPeekCost = new JCheckBoxMenuItem("Random peekCost"); m_RandomPeekCost.setSelected(true); rmenu.add(m_RandomPeekCost); m_RandomBoardSize = new JCheckBoxMenuItem("Random board size"); m_RandomBoardSize.setSelected(true); rmenu.add(m_RandomBoardSize); menuBar.add(rmenu); menuBar.add(Box.createHorizontalGlue()); JMenu hmenu = new JMenu("Help"); JMenuItem helpItem = new JMenuItem("Help"); helpItem.addActionListener(this); hmenu.add(helpItem); JMenuItem aboutItem = new JMenuItem("About"); aboutItem.addActionListener(this); hmenu.add(aboutItem); menuBar.add(hmenu); setJMenuBar(menuBar); getContentPane().setLayout(new BorderLayout()); JPanel buttons = new JPanel(); JButton newGame = new JButton("New Game"); newGame.addActionListener(this); buttons.add(newGame); JButton stopGame = new JButton("Stop Game"); stopGame.addActionListener(this); buttons.add(stopGame); JButton openAll = new JButton("Open all"); openAll.addActionListener(this); buttons.add(openAll); JPanel ctrl = new JPanel(); ctrl.setLayout(new GridLayout(3,2)); ctrl.add(new JLabel("x-size")); m_TextXSize = new JTextField(Integer.toString(xsize)); m_TextXSize.addActionListener(this); ctrl.add(m_TextXSize); ctrl.add(new JLabel("density")); m_TextDens = new JTextField(Double.toString(m_Density)); m_TextDens.addActionListener(this); ctrl.add(m_TextDens); ctrl.add(new JLabel("y-size")); m_TextYSize = new JTextField(Integer.toString(ysize)); m_TextYSize.addActionListener(this); ctrl.add(m_TextYSize); makeTextEditable(m_UseRandom.isSelected()); ctrl.add(new JLabel("dead cost")); m_TextDeadCost = new JTextField(Integer.toString(m_DeadCost)); m_TextDeadCost.addActionListener(this); ctrl.add(m_TextDeadCost); ctrl.add(new JLabel("#open")); m_TextNumOpen = new JTextField("0"); m_TextNumOpen.setEditable(false); ctrl.add(m_TextNumOpen); ctrl.add(new JLabel("peek cost")); m_TextPeekCost = new JTextField(Integer.toString(m_PeekCost)); m_TextPeekCost.addActionListener(this); ctrl.add(m_TextPeekCost); buttons.add(ctrl, BorderLayout.EAST); getContentPane().add(buttons, BorderLayout.SOUTH); m_Field = new MineField(this, xsize, ysize); getContentPane().add( m_Field, BorderLayout.CENTER); newGame(); Dimension d = m_Field.getSize(); setSize((int)d.getWidth(), (int)(d.getHeight() + 100)); pack(); m_StatWin = new StatWindow(this); m_StatWin.setVisible(m_ShowStats.isSelected()); m_StartPlay = false; m_Playing = false; m_SecondThread = new Thread(this, "Extra thread"); m_SecondThread.start(); m_TimerThread = new Thread(this, "Timer thread"); m_TimerThread.start(); m_ConnListener = new NewConnListener(this, m_ServerPort); m_ConnListener.start(); m_NumClients = 0; } public void stopGame() { m_GameStopPressed = true; if (m_PlayMode == SERVER_MODE) { System.out.println("Stopped the game"); m_StoppedGame = true; clientGameOver(false); } else if (m_PlayMode == MANUAL_MODE) { gameOver(true); } else { gameOver(false); } if (m_BatchReader != null) { m_BatchReader = null; } } public void setTwoPlayerGame(boolean v) { m_TwoPlayerGame.setSelected(v); } public void updateNumOpened(int n) { m_TextNumOpen.setText(Integer.toString(n)); } public void setSettings(int deadCost, int peekCost, double density) { m_DeadCost = deadCost; m_PeekCost = peekCost; m_Density = density; m_TextDens.setText("" + m_Density); m_TextDeadCost.setText("" + m_DeadCost); m_TextPeekCost.setText("" + m_PeekCost); } public void makeTextEditable(boolean e) { m_TextXSize.setEditable(e); m_TextYSize.setEditable(e); m_TextDens.setEditable(e); } public void rejectClient(Socket s, String msg) { try { PrintWriter pw = new PrintWriter(s.getOutputStream(), true); pw.println(msg); pw.close(); s.close(); } catch (Exception exc) {} } public void sendToClient(PrintWriter pw, String msg) { try { pw.println(msg); } catch (Exception exc) {} } public void sendToAllClients(String msg) { for (int i = 0; i < m_NumClients; i++) { try { m_Clients[i].m_Out.println(msg); } catch (Exception exc) {} } } public void sendGameStart() { for (int i = 0; i < m_NumClients; i++) { m_Clients[i].m_Active = true; String msg = "START " + m_NumClients + " " + m_Clients[i].m_Id + " " + m_Field.getFieldXSize() + " " + m_Field.getFieldYSize() + " " + m_DeadCost + " " + m_PeekCost; sendToClient(m_Clients[i].m_Out, msg); } } public int getNumActiveClient() { int n = 0; for (int i = 0; i < m_NumClients; i++) { if (m_Clients[i].m_Active) n++; } return n; } /// This function should be called when there is a new client public boolean addClient(Socket s) { if (m_PlayMode != SERVER_MODE) { rejectClient(s, "ERROR Not in server mode"); return false; } if ((!m_TwoPlayerGame.isSelected() && m_NumClients == 1) || (m_TwoPlayerGame.isSelected() && m_NumClients > 1)) { rejectClient(s, "ERROR No more slots to connect to"); } AgentClient newClient = new AgentClient(); newClient.m_Socket = s; newClient.m_Id = 0; newClient.m_Peeked = false; newClient.m_Score = 0; newClient.m_UsedTime = 0; try { newClient.m_InRaw = s.getInputStream(); InputStreamReader isr = new InputStreamReader(s.getInputStream()); newClient.m_In = new BufferedReader(isr); newClient.m_Out = new PrintWriter(s.getOutputStream(), true); } catch(Exception exc) { System.out.println("Could not create I/O for client"); return false; } sendToClient(newClient.m_Out, "WELCOME to the Minesweep server"); System.out.println("Waiting for team name..."); // The client should now send the name of the team String name = null; try { name = newClient.m_In.readLine(); } catch (Exception exc) { System.out.println("Could not get agent name"); return false; } if (name != null) { newClient.m_Name = name; System.out.println("Client with name \"" + name + "\" just joined"); } else { System.out.println("Client name is null string"); return false; } m_NumClients++; System.out.println("addClient: Now got " + m_NumClients + " clients"); m_GameNumber = 0; m_GameId++; if (m_NumClients == 0) { m_Clients = new AgentClient[1]; m_NumClients = 1; m_Clients[0] = newClient; } else { AgentClient ac[] = new AgentClient[m_NumClients]; // We insert the new client based on the name so that the // list of client is sorted based on name. This way it i // smore likely that the clients will be in the same order // in case they have to reconnect due to broken // connection, timeout, etc int j = 0; boolean addedNew = false; for (int i = 0; i < (m_NumClients-1); i++) { if (newClient.m_Name.compareTo(m_Clients[i].m_Name) < 0) { ac[j] = newClient; ac[j].m_Id = j; j++; addedNew = true; } ac[j] = m_Clients[i]; ac[j].m_Id = j; j++; } if (!addedNew) { ac[m_NumClients-1] = newClient; ac[m_NumClients-1].m_Id = m_NumClients - 1; } m_Clients = ac; } return true; } public void closeAllClients() { int n = m_NumClients; for (int i = 0; i < n; i++) { delClient(i); } } public boolean delClient(int i) { AgentClient oldClient = m_Clients[i]; System.out.println("Removing client with name \"" + m_Clients[i].m_Name + "\""); if (m_NumClients-1 > 0) { AgentClient ac[] = new AgentClient[m_NumClients - 1]; int n = 0; for (int j = 0; j < m_NumClients; j++) { if (j != i) { ac[n] = m_Clients[j]; ac[n].m_Id = 0; n++; } } m_Clients = ac; } else { m_Clients = null; } m_NumClients--; try { oldClient.m_InRaw.close(); oldClient.m_In.close(); oldClient.m_Socket.close(); } catch(Exception e) {} return true; } /// In this function we check for data from client(s) public void clientPlay() { m_StartTime = System.nanoTime(); int nSquares = m_Field.getFieldXSize() * m_Field.getFieldYSize(); boolean run = true; boolean firstRound = true; System.out.println("Game number " + (m_GameNumber + 1)); m_StoppedGame = false; if (m_OnlySave.isSelected()) { clientGameOver(false); m_Playing = false; return; } if (m_NumClients == 1) { m_StatWin.setTeamName(m_Clients[0].m_Name, "-"); } else if (m_NumClients == 2) { m_StatWin.setTeamName(m_Clients[0].m_Name, m_Clients[1].m_Name); } while (run) { for (int i = 0; run && i < m_NumClients; i++) { if (m_StoppedGame) { System.out.println("Game stopped/timeout"); run = false; break; } double splitTime = System.nanoTime(); // In the first round we skip players in such as way // that the pllayers take turn to start if (firstRound) { if (i < (m_GameNumber % m_NumClients)) { System.out.println("Skipping client " + i + " for game #" + m_GameNumber); continue; } firstRound = false; } if (!m_Clients[i].m_Active) continue; System.out.println("Sending MOVE to client " + i); String msg = "MOVE"; sendToClient(m_Clients[i].m_Out, msg); String move = ""; try { move = m_Clients[i].m_In.readLine(); } catch (Exception exc) { System.out.println("Got exception"); delClient(i); run = false; break; } System.out.println("Got response from client " + i); if (move == null) { System.out.println("Null string read for move"); delClient(i); run = false; break; } if (m_StoppedGame) { System.out.println("Game stopped/timeout"); run = false; break; } m_Clients[i].m_UsedTime += (System.nanoTime() - splitTime); //System.out.println(move); String cmd[] = move.split(" "); if (cmd[0].equals("OPEN")) { int x = Integer.parseInt(cmd[1]); int y = Integer.parseInt(cmd[2]); int ret = m_Field.openSquare(x,y); if (ret == -10) { String repl = new String("ILLEGAL_MOVE " + m_Clients[i].m_Id + " " + x + " " + y); sendToClient(m_Clients[i].m_Out, repl); // Let this player play again, sicne we do not // want clients using this as a strategy not // to have to say STOP i--; } else if (ret == -20) { System.out.println("Square already open, stop or open a !!"); String repl = new String("ALREADY_OPEN " + m_Clients[i].m_Id + " " + x + " " + y); sendToClient(m_Clients[i].m_Out, repl); // Let this player play again, sicne we do not // want clients using this as a strategy not // to have to say STOP i--; } else { if (ret == -1) { m_Clients[i].m_Active = false; m_Clients[i].m_Score -= m_DeadCost; if (getNumActiveClient() <= 1) { clientGameOver(false); run = false; break; } } else if (ret == -2) { } else { // A safe square was open and we should // increment the score for the active // clients for (int j = 0; j < m_NumClients; j++) { if (m_Clients[j].m_Active) { m_Clients[j].m_Score ++; } } } String repl = new String("SQUARE_INFO " + m_Clients[i].m_Id + " " + x + " " + y + " " + ret); sendToAllClients(repl); } } else if (cmd[0].equals("STOP")) { String repl = new String("PLAYER_STOPPED " + m_Clients[i].m_Id); sendToAllClients(repl); m_Clients[i].m_Active = false; if (getNumActiveClient() == 0) { clientGameOver(false); run = false; break; } } else if (cmd[0].equals("PEEK")) { if (m_Clients[i].m_Peeked) { String repl = new String("ALREADY_PEEKED " + m_Clients[i].m_Id); sendToClient(m_Clients[i].m_Out, repl); } else { int x = Integer.parseInt(cmd[1]); int y = Integer.parseInt(cmd[2]); int ret = m_Field.peekSquare(x,y); System.out.println("Client " + i + " peeking at " + x + " " + y); String repl = new String("SQUARE_INFO " + m_Clients[i].m_Id + " " + x + " " + y + " " + ret); sendToClient(m_Clients[i].m_Out, repl); m_Clients[i].m_Peeked = true; } // This client should move again i--; } else { System.out.println("Unkown command \"" + move + "\""); String repl = new String("UNKNOWN_CMD " + move); sendToClient(m_Clients[i].m_Out, repl); // This player has to go again i--; } // Check if all squares are open if (nSquares - m_Field.getNumOpened() == 0) { clientGameOver(false); run = false; break; } if (m_SlowSpeedAuto.isSelected()) { try { Thread.sleep(50); } catch (Exception exc) {} } } } System.out.println("Game finished"); m_GameNumber++; m_Playing = false; } public void run() { Thread myThread = Thread.currentThread(); System.out.println("Started thread"); while (m_SecondThread == myThread) { /* System.out.println("m_PlayMode=" + m_PlayMode + " " + " m_StartPlay=" + " " + m_StartPlay + " " + " m_Playing=" + " " + m_Playing); */ if (m_PlayMode == AUTO_MODE && m_StartPlay) { m_StartPlay = false; m_Playing = true; autoPlay(); } if (m_PlayMode == SERVER_MODE) { if (m_StartPlay) { sendGameStart(); m_StartPlay = false; m_StoppedGame = false; m_Playing = true; System.out.println("Starting new game"); clientPlay(); } } try { Thread.sleep(100); } catch (Exception exc) {} } while (m_TimerThread == myThread) { if (m_PlayMode == SERVER_MODE) { if (m_StartTime > 0) { long dt = (long)(1e-9*(System.nanoTime() - m_StartTime)); m_StatWin.setTime(dt, m_MaxGameTimeSec); if (dt > m_MaxGameTimeSec) { if (!m_StoppedGame) { System.out.println("Game timeout"); m_StoppedGame = true; // Give clients 10s to close m_StartTime += 10000000000L; JOptionPane.showMessageDialog(this, "Timeout"); clientGameOver(true); } else { System.out.println("No response from clients, " + "closing them"); JOptionPane.showMessageDialog(this, "Timeout: closing all"); closeAllClients(); } } } else { m_StatWin.setTime(0, m_MaxGameTimeSec); } } else { if (m_StartTime > 0) { long dt = (long)(1e-9*(System.nanoTime() - m_StartTime)); m_StatWin.setTime(dt, m_MaxGameTimeSec); } else { m_StatWin.setTime(0, m_MaxGameTimeSec); } } try { Thread.sleep(1000); } catch (Exception exc) {} } System.out.println("Done with thread"); } public void paint(Graphics g) { super.paint(g); // m_Field.paint(g); } public void autoPlay() { m_StartTime = System.nanoTime(); System.out.println("Starting autoplay"); int playerID = 0; if (m_Agent.startNewGame(1, playerID, m_Field.getFieldXSize(), m_Field.getFieldYSize(), m_DeadCost, m_PeekCost) == false) { showMessage("Could not start agent"); return; } MineMove mm; m_AutoScore = 0; int nSquares = m_Field.getFieldXSize() * m_Field.getFieldYSize(); boolean peeked = false; if (m_OnlySave.isSelected()) { gameOver(false); return; } while (true) { mm = m_Agent.getNextMove(); if (mm == null || mm.m_Move == MineMove.STOP || (nSquares - m_Field.getNumOpened() == 0)) { gameOver(false); return; } if (mm.m_Move == MineMove.OPEN_SQUARE) { int ret = m_Field.openSquare(mm.m_X, mm.m_Y); MineInfo mi = new MineInfo(); mi.m_PlayerID = playerID; mi.m_X = mm.m_X; mi.m_Y = mm.m_Y; if (ret == -10) { mi.m_InfoType = MineInfo.ILLEGAL_MOVE; } else { if (ret == -1) { m_AutoScore -= m_DeadCost; gameOver(false); return; } else if (ret == -2) { showMessage("You should be dead, but you're not"); } else { m_AutoScore++; } mi.m_Value = ret; mi.m_InfoType = MineInfo.SQUARE_INFO; } m_Agent.handleInfo(mi); } else if (mm.m_Move == MineMove.PEEK_SQUARE) { MineInfo mi = new MineInfo(); mi.m_PlayerID = playerID; if (peeked) { mi.m_InfoType = MineInfo.ALREADY_PEEKED; } else { mi.m_X = mm.m_X; mi.m_Y = mm.m_Y; mi.m_Value = m_Field.peekSquare(mm.m_X, mm.m_Y); mi.m_InfoType = MineInfo.SQUARE_INFO; peeked = true; } m_Agent.handleInfo(mi); } if (m_SlowSpeedAuto.isSelected()) { try { Thread.sleep(50); } catch (Exception exc) {} } } } public void showMessage(String msg) { // Do not show messages in batch mode if (m_BatchReader != null) return; if (m_AutoRestart.isSelected()) return; JOptionPane.showMessageDialog(this, msg); } public void runBatchFileTest(String batchfile) { try { m_BatchFile = new FileReader(batchfile); m_BatchReader = new BufferedReader(m_BatchFile); String filename = "batchresults-" + System.nanoTime() + ".txt"; m_BatchResFile = new FileWriter(filename); m_BatchResWriter = new BufferedWriter(m_BatchResFile); m_UseRandom.setSelected(false); makeTextEditable(false); newGame(); m_StartPlay = true; } catch (Exception exc) { showMessage("Failed to open batch file \"" + batchfile + "\""); } } public void actionPerformed(ActionEvent e) { if (e.getSource() == m_TextXSize) { System.out.println("X changed"); try { int s = Integer.parseInt(m_TextXSize.getText()); if (s < 0 || s > 50) { System.out.println("xsize in [0,50]"); JOptionPane.showMessageDialog(this, "xsize in [0,50]"); m_TextXSize.setText(Integer.toString(m_Field.getFieldXSize())); } else { m_Field.setFieldXSize(s); newGame(); } } catch (Exception ne) { JOptionPane.showMessageDialog(this, "xsize must be integer"); m_TextXSize.setText(Integer.toString(m_Field.getFieldXSize())); } } else if (e.getSource() == m_TextYSize) { System.out.println("Y changed"); try { int s = Integer.parseInt(m_TextYSize.getText()); if (s < 0 || s > 50) { System.out.println("ysize in [0,50]"); JOptionPane.showMessageDialog(this, "ysize in [0,50]"); m_TextYSize.setText(Integer.toString(m_Field.getFieldYSize())); } else { m_Field.setFieldYSize(s); newGame(); } } catch (Exception ne) { JOptionPane.showMessageDialog(this, "ysize must be integer"); m_TextYSize.setText(Integer.toString(m_Field.getFieldYSize())); } } else if (e.getSource() == m_TextDens) { System.out.println("Density changed"); try { double d = Double.parseDouble(m_TextDens.getText()); if (d < 0) { System.out.println("density < 0"); JOptionPane.showMessageDialog(this, "0.0 1) { if (m_Clients[0].m_TimeFraction > 2.0 / 3) { System.out.println("Punished agent \"" + m_Clients[0].m_Name + "\" for using too much time"); m_Clients[0].m_Score -= m_PeekCost; } else if (m_Clients[1].m_TimeFraction > 2.0 / 3) { System.out.println("Punished agent \"" + m_Clients[1].m_Name + "\" for using too much time"); m_Clients[1].m_Score -= m_PeekCost; } } if (m_NumClients == 1) writeResult(m_Clients[0].m_Score); else writeResult(-1); if (!m_GameStopPressed) { if (m_NumClients == 1) { m_StatWin.addStats(1.0 * m_Clients[0].m_Score / maxScore, false, 0, false); } else if (m_NumClients == 2) { boolean win1 = (m_Clients[0].m_Score > m_Clients[1].m_Score); boolean win2 = (m_Clients[1].m_Score > m_Clients[0].m_Score); m_StatWin.addStats(1.0 * m_Clients[0].m_Score / maxScore, win1, 1.0 * m_Clients[1].m_Score / maxScore, win2); } } for (int i = 0; i < m_NumClients; i++) { if (m_NumClients == 1) { m += "\nClient" + i + " (\"" + m_Clients[i].m_Name + "\") got score=" + m_Clients[i].m_Score + " time=" + (long)(1e-6 * m_Clients[i].m_UsedTime) + "ms"; } else { m += "\nClient" + i + " (\"" + m_Clients[i].m_Name + "\") got score=" + m_Clients[i].m_Score + " time=" + (long)(1e-6 * m_Clients[i].m_UsedTime) + "ms (" + (long)(100.0 * m_Clients[i].m_TimeFraction) + "%)"; } String msg = "DONE " + m_Clients[i].m_Score; sendToClient(m_Clients[i].m_Out, msg); m_Clients[i].m_Score = 0; m_Clients[i].m_Active = true; m_Clients[i].m_Peeked = false; m_Clients[i].m_UsedTime = 0; } showMessage(m); System.out.println(m); if (!m_GameStopPressed) { if (m_BatchReader != null) { newGame(); m_StartPlay = true; } else if (m_AutoRestart.isSelected() && !m_GameStopPressed) { if (m_PlayMode == SERVER_MODE) { newGame(); m_StartPlay = true; } } } } public void gameOver(boolean calcScore) { m_GameId++; m_StartTime = -1; m_Playing = false; int score = m_AutoScore; if (calcScore) { score = m_Field.getNumOpened() - m_Field.getNumInitialMines(); if (m_Field.isDead()) { score -= m_DeadCost; } } m_StatWin.addStats(1.0 * score / m_Field.getMaxScore(), false, 0, false); showMessage("Game finished\n" + "You got score " + score); if (m_BatchReader != null) { writeResult(score); newGame(); m_StartPlay = true; } else if (m_AutoRestart.isSelected() && !m_GameStopPressed) { if (m_PlayMode == AUTO_MODE) { newGame(); m_StartPlay = true; } } } private void writeResult(int score) { if (m_BatchReader == null) return; String line = new String(""); if (m_TwoPlayerGame.isSelected() && m_PlayMode == SERVER_MODE) { line += m_MineFile + " " + m_Field.getFieldXSize() + " " + m_Field.getFieldYSize() + " " + m_Field.getMaxScore() + " " + m_Field.getNumOpened() + " " + m_Field.getNumInitialMines() + " " + m_Clients[0].m_Name + " " + m_Clients[1].m_Name + " " + m_Clients[0].m_Score + " " + m_Clients[1].m_Score + " " + (long)(1e-6*m_Clients[0].m_UsedTime) + " " + (long)(1e-6*m_Clients[1].m_UsedTime) + " " + m_Clients[0].m_TimeFraction + " " + m_Clients[1].m_TimeFraction; } else { line += m_MineFile + " " + m_Field.getFieldXSize() + " " + m_Field.getFieldYSize() + " " + m_Field.getMaxScore() + " " + m_Field.getNumOpened() + " " + m_Field.getNumInitialMines() + " " + score + " " + score / m_Field.getMaxScore(); } try { m_BatchResWriter.write(line, 0, line.length()); m_BatchResWriter.newLine(); m_BatchResWriter.flush(); } catch (Exception exc) { System.out.println("Failed to write result to file"); } } private boolean readNextBatchFile() { try { m_MineFile = m_BatchReader.readLine(); } catch (Exception e) {} return (m_MineFile != null); } public void newGame() { System.out.println("newGame called"); if (m_UseRandom.isSelected() == false) { if (m_BatchReader != null) { System.out.println("In batch mode"); if (!readNextBatchFile()) { m_BatchReader = null; m_StartPlay = false; m_GameStopPressed = true; m_Playing = false; m_StoppedGame = true; m_AutoRestart.setSelected(false); System.out.println("Out of batch files"); try { m_BatchResWriter.close(); } catch (Exception exc) {} showMessage("Batch test done"); return; } else { System.out.println("Found batch file \"" + m_MineFile + "\""); } } if (m_MineFile == null) { showMessage("You must specify mine file"); } else { if (m_Field.readMinesFromFile(m_MineFile)) { System.out.println("Loaded mine file \"" + m_MineFile + "\""); m_TextXSize.setText(Integer.toString(m_Field.getFieldXSize())); m_TextYSize.setText(Integer.toString(m_Field.getFieldYSize())); m_TextDens.setText("?"); } else { System.out.println("Could not load mine file"); } } } else { Random r = new Random(); if (m_RandomDensity.isSelected()) { m_Density = 1e-3 * (long)(1e3 * (0.02 + 0.23*r.nextDouble())); m_TextDens.setText("" + m_Density); } if (m_RandomPeekCost.isSelected()) { if (r.nextInt(10) > 8) { m_PeekCost = 10 + r.nextInt(10); } else { m_PeekCost = r.nextInt(10); } m_TextPeekCost.setText("" + m_PeekCost); } if (m_RandomDeadCost.isSelected()) { m_DeadCost = 5 + r.nextInt(15); m_TextDeadCost.setText("" + m_DeadCost); } if (m_RandomBoardSize.isSelected()) { int xSize = 10 + r.nextInt(40); int ySize = 10 + r.nextInt(40); m_TextXSize.setText("" + xSize); m_TextYSize.setText("" + ySize); m_Field.setFieldXSize(xSize); m_Field.setFieldYSize(ySize); } m_Field.createRandomMines(m_Density); if (m_SaveGameBoards.isSelected()) { String filename = "minefile-" + m_GameId + ".msf"; m_Field.saveMinesToFile(filename); // Add the settings to the minefile try { FileWriter fw = new FileWriter(filename, true); fw.write("S " + m_DeadCost + " " + m_PeekCost + " " + m_Density + " " + "\n"); fw.close(); } catch (Exception e) {} } } m_Field.buildField(); } public static void main(String[] args) { int port = 5555; if (args.length >= 1) { try { port = Integer.parseInt(args[0]); } catch (Exception e) { System.out.println("Could not get port number for server\n" + "args: "); System.exit(0); } } int numplayers = 1; if (args.length >= 2) { try { numplayers = Integer.parseInt(args[1]); if (numplayers < 1 || numplayers > 2) { System.out.println("Only allowing 1 or 2 player\n" + "args: "); System.exit(0); } } catch (Exception e) { System.out.println("Could not get number of players\n" + "args: "); System.exit(0); } } Minesweep frame = new Minesweep(port, 40, 20, 0.04, 10, 10); frame.setTwoPlayerGame((numplayers==2)); Dimension d = frame.getSize(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); frame.setLocation((int)(screenSize.width/2 - d.getWidth()/2), (int)(screenSize.height/2 - d.getHeight()/2)); frame.setVisible(true); } };