// Alex Huddleston and Brandon Jackson // Breakthrough Client in Java import java.io.IOException; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.Scanner; import java.io.DataInputStream; import java.util.Arrays; import javax.swing.*; import javax.*; import java.awt.*; import java.awt.geom.*; import java.awt.event.*; import java.awt.image.BufferedImage; import javax.swing.border.*; import java.net.URL; import javax.imageio.ImageIO; import java.awt.image.*; import java.io.File; import java.io.InputStream; //import javax.swing.text.html.parser.ParserDelegator; public class Client { private final JPanel gui = new JPanel(new BorderLayout(3, 3)); private JButton[][] boardSquares = new JButton[8][8]; private Image[] pieceImages = new Image[2]; private JPanel boardPanel; private static final String Columns = "ABCDEFGH"; public static final int BLACK = 0, WHITE = 1; public static String boardoutput = ""; public String oldBoard = ""; public static String undoString = ""; public static char myTurn = 'O'; public Client() { initializeGui(); } public final void initializeGui() { createImages(); gui.setBorder(new EmptyBorder(5,5,5,5)); boardPanel = new JPanel(new GridLayout(0, 9)) { /** * Override the preferred size to return the largest it can, in * a square shape. Must (must, must) be added to a GridBagLayout * as the only component (it uses the parent as a guide to size) * with no GridBagConstaint (so it is centered). */ @Override public final Dimension getPreferredSize() { Dimension d = super.getPreferredSize(); Dimension prefSize = null; Component c = getParent(); if (c == null) { prefSize = new Dimension( (int)d.getWidth(),(int)d.getHeight()); } else if (c!=null && c.getWidth()>d.getWidth() && c.getHeight()>d.getHeight()) { prefSize = c.getSize(); } else { prefSize = d; } int w = (int) prefSize.getWidth(); int h = (int) prefSize.getHeight(); // the smaller of the two sizes int s = (w>h ? h : w); return new Dimension(s,s); } }; boardPanel.setBorder(new CompoundBorder( new EmptyBorder(8,8,8,8), new LineBorder(Color.BLACK) )); // Set BG. Color background = new Color(100,100,100); Color boardbg = new Color(250, 200, 100); boardPanel.setBackground(background); JPanel boardConstrain = new JPanel(new GridBagLayout()); boardConstrain.setBackground(background); boardConstrain.add(boardPanel); gui.add(boardConstrain); Insets buttonMargin = new Insets(0,0,0,0); for(int r = 0; r < boardSquares.length; ++r) { for(int c = 0; c < boardSquares.length; ++c) { final int selectrow = r; final int selectcol = c; Action selectPiece = new AbstractAction("") { @Override public void actionPerformed(ActionEvent e) { sendLocation(selectrow, selectcol); } }; JButton b = new JButton(); b.setMargin(buttonMargin); b.setAction(selectPiece); ImageIcon icon = new ImageIcon( new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB)); b.setIcon(icon); b.setBackground(boardbg); boardSquares[r][c] = b; } } // fill the board. Action undoMove = new AbstractAction("") { @Override public void actionPerformed(ActionEvent e) { undoMoveSend(); } }; ImageIcon icon = new ImageIcon( new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB)); JButton undo = new JButton("UNDO", icon); undo.setMargin(buttonMargin); undo.setAction(undoMove); undo.setBackground(new Color(150, 150, 150)); boardPanel.add(undo); // fill the top row for(int c = 0; c < 8; c++) { boardPanel.add(new JLabel(Columns.substring(c, c + 1), SwingConstants.CENTER)); } // fill everything else for(int r = 0; r < 8; ++r) { for(int c = 0; c < 8; c++) { switch(c) { case 0: boardPanel.add(new JLabel("" + (9 - (r + 1)), SwingConstants.CENTER)); default: boardPanel.add(boardSquares[r][c]); } } } } public final JComponent getGui() { return gui; } private final void createImages() { try { //URL url1 = new URL("http://www.iconsdb.com/icons/preview/black/circle-xxl.png"); BufferedImage bi = ImageIO.read(new File("Resources/black_circle.png")); Image img = bi.getScaledInstance(64, 64, BufferedImage.SCALE_FAST); pieceImages[0] = img; //URL url2 = new URL("http://www.iconsdb.com/icons/preview/white/circle-xxl.png"); bi = ImageIO.read(new File("Resources/white_circle.png")); img = bi.getScaledInstance(64, 64, BufferedImage.SCALE_FAST); pieceImages[1] = img; } catch (Exception e) { e.printStackTrace(); System.exit(1); } } public String TrimBoard(String board) { String output = ""; for(int i = 0; i < board.length(); ++i) { if((output.length() != 64) && board.charAt(i) == 'X') { output += board.charAt(i); } else if((output.length() != 64) && board.charAt(i) == '_') { output += board.charAt(i); } else if((output.length() != 64) && board.charAt(i) == 'O') { output += board.charAt(i); } } return output; } public final void updateBoard(String board) { board = TrimBoard(board); System.out.println(board); int count = 0; ImageIcon icon = new ImageIcon( new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB)); if(oldBoard.equals("")) { for(int r = 0; r < 8; ++r) { for(int c = 0; c < 8; c++) { if(board.charAt(count) == 'X') { boardSquares[r][c].setIcon(new ImageIcon(pieceImages[0])); } else if(board.charAt(count) == 'O') { boardSquares[r][c].setIcon(new ImageIcon(pieceImages[1])); } else { boardSquares[r][c].setIcon(icon); } count++; } } count = 0; } else { for(int r = 0; r < 8; ++r) { for(int c = 0; c < 8; c++) { if(board.charAt(count) == 'X' && oldBoard.charAt(count) != 'X') { boardSquares[r][c].setIcon(new ImageIcon(pieceImages[0])); } else if(board.charAt(count) == 'O' && oldBoard.charAt(count) != 'O') { boardSquares[r][c].setIcon(new ImageIcon(pieceImages[1])); } else if(board.charAt(count) == '_' && oldBoard.charAt(count) != '_') { boardSquares[r][c].setIcon(icon); } count++; } } } oldBoard = board; } public final void undoMoveSend() { undoString = "UNDO"; } public void sendLocation(int r, int c) { //debugging. System.out.println("row: " + r + " col: " + c); boardoutput += "" + r + "" + c; } public static String parseOutput(String move) { String output = ""; int tempa = move.charAt(0) - '0'; int tempb = move.charAt(1) - '0'; int tempc = move.charAt(2) - '0'; int tempd = move.charAt(3) - '0'; if((myTurn == 'O') && (tempa == (tempc + 1))) { //cout << "\nTest\n"; if(tempb == tempd) { output = ((char)('A' + tempb)) + "" + (8 - tempa) + " FWD"; } else if(tempb == (tempd + 1)) { output = ((char)('A' + tempb)) + "" + (8 - tempa) + " LEFT"; } else if(tempb == (tempd - 1)) { output = ((char)('A' + tempb)) + "" + (8 - tempa) + " RIGHT"; } } else if((myTurn == 'X') && (tempa == (tempc - 1))){ //cout << "\nTest\n"; if(tempb == tempd) { output = ((char)('A' + tempb)) + "" + (8 - tempa) + " FWD"; } else if(tempb == (tempd + 1)) { output = ((char)('A' + tempb)) + "" + (8 - tempa) + " LEFT"; } else if(tempb == (tempd - 1)) { output = ((char)('A' + tempb)) + "" + (8 - tempa) + " RIGHT"; } } else { return "Invalid"; } //Debugging System.out.println("Output: " + output); return output; } public static void main (String[] args) throws InterruptedException { Scanner keyboard = new Scanner(System.in); String hostname = args[0]; int portnum = Integer.parseInt(args[1]); try { Socket echoSocket = new Socket(hostname, portnum); PrintWriter output = new PrintWriter(echoSocket.getOutputStream(), true); BufferedReader in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream())); BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in)); String userInput = "test"; char[] b = new char[256]; in.read(b, 0, 256); String temp = String.valueOf(b).trim(); String g = "GAME OVER"; char[] go = new char[9]; for(int x = 0; x < go.length; ++x) { go[x] = g.charAt(x); } boolean end = false; int c = 0; Client window = new Client(); JFrame frame = new JFrame("Breakthrough"); frame.add(window.getGui()); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setLocationByPlatform(true); frame.pack(); frame.setMinimumSize(frame.getSize()); frame.setVisible(true); //userInput = stdIn.readLine(); int gameMode = 0; String diff = "?"; if(!temp.equals("skip")) { userInput = JOptionPane.showInputDialog(frame, temp); //gameMode = Integer.parseInt(userInput); while(!userInput.equals("1") && !userInput.equals("2") && !userInput.equals("3")) { userInput = JOptionPane.showInputDialog(frame, temp); output.println(userInput); } gameMode = Integer.parseInt(userInput); output.println(userInput); if(gameMode != 3) { in.read(b, 0, 256); temp = String.valueOf(b).trim(); while(!diff.equals("1") && !diff.equals("2") && !diff.equals("3")) { diff = JOptionPane.showInputDialog(frame, temp);//diff = stdIn.readLine(); //diff = diff.toUpperCase(); if(!diff.equals("1") && !diff.equals("2") && !diff.equals("3")) { JOptionPane.showMessageDialog(null, diff + "\nInvalid difficulty.\n" + temp); } } if(diff.equals("1")) { userInput = "EASY"; } else if(diff.equals("2")) { userInput = "MEDIUM"; } else if(diff.equals("3")) { userInput = "HARD"; } output.println(userInput); } } else { gameMode = 3; myTurn = 'X'; } String out = ""; if(gameMode == 3) { in.read(b, 0, 256); temp = String.valueOf(b).trim(); userInput = JOptionPane.showInputDialog(frame, temp); //gameMode = Integer.parseInt(userInput); while(!userInput.equals("1") && !userInput.equals("2")) { userInput = JOptionPane.showInputDialog(frame, temp); output.println(userInput); } gameMode = Integer.parseInt(userInput); output.println(userInput); if(gameMode == 2) { in.read(b, 0, 256); temp = String.valueOf(b).trim(); userInput = JOptionPane.showInputDialog(frame, temp); diff = userInput; while(!diff.equals("1") && !diff.equals("2") && !diff.equals("3")) { diff = JOptionPane.showInputDialog(frame, temp);//diff = stdIn.readLine(); //diff = diff.toUpperCase(); if(!diff.equals("1") && !diff.equals("2") && !diff.equals("3")) { JOptionPane.showMessageDialog(null, diff + "\nInvalid difficulty.\n" + temp); } } if(diff.equals("1")) { userInput = "EASY"; } else if(diff.equals("2")) { userInput = "MEDIUM"; } else if(diff.equals("3")) { userInput = "HARD"; } output.println(userInput); } while(!end) { char[] buffer = new char[256]; if(gameMode == 1) { in.read(buffer, 0, 256); for(int i = 0; i < buffer.length; ++i) { if(Arrays.equals(Arrays.copyOfRange(buffer, i, i+9), go)) { frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING)); JOptionPane.showMessageDialog(null, "\nGAME OVER\n"); end = true; } } System.out.println(String.valueOf(buffer).trim()); window.updateBoard(String.valueOf(buffer).trim()); while(!end && boardoutput.length() < 4) { if(in.ready()) { in.read(buffer, 0, 256); for(int i = 0; i < buffer.length; ++i) { if(Arrays.equals(Arrays.copyOfRange(buffer, i, i+9), go)) { frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING)); JOptionPane.showMessageDialog(null, "\nGAME OVER\n"); end = true; } } System.out.println(String.valueOf(buffer).trim()); window.updateBoard(String.valueOf(buffer).trim()); } String tempstring; Thread.sleep(1); if(!undoString.equals("")) { System.out.println(undoString); output.println(undoString); output.flush(); undoString = ""; } if(boardoutput.length() == 4) { out = parseOutput(boardoutput); if(out == "Invalid") { out = ""; boardoutput = ""; System.out.println("Invalid move."); } } } //System.out.println(String.valueOf(buffer).trim()); System.out.println(out); output.println(out); output.flush(); boardoutput = ""; } else { if(in.ready()) { in.read(buffer, 0, 256); for(int i = 0; i < buffer.length; ++i) { if(Arrays.equals(Arrays.copyOfRange(buffer, i, i+9), go)) { frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING)); JOptionPane.showMessageDialog(null, "\nGAME OVER\n"); end = true; } } System.out.println(String.valueOf(buffer).trim()); window.updateBoard(String.valueOf(buffer).trim()); } } } output.close(); in.close(); stdIn.close(); echoSocket.close(); } else if(gameMode == 1) { while(!end) { char[] buffer = new char[256]; in.read(buffer, 0, 256); for(int i = 0; i < buffer.length; ++i) { if(Arrays.equals(Arrays.copyOfRange(buffer, i, i+9), go)) { frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING)); JOptionPane.showMessageDialog(null, "\nGAME OVER\n"); end = true; } } System.out.println(String.valueOf(buffer).trim()); window.updateBoard(String.valueOf(buffer).trim()); while(!end && boardoutput.length() < 4) { String tempstring; Thread.sleep(100); if(!undoString.equals("")) { System.out.println(undoString); output.println(undoString); output.flush(); undoString = ""; } if(boardoutput.length() == 4) { out = parseOutput(boardoutput); if(out == "Invalid") { out = ""; boardoutput = ""; System.out.println("Invalid move."); } } } System.out.println(String.valueOf(buffer).trim()); System.out.println(out); output.println(out); output.flush(); boardoutput = ""; } output.close(); in.close(); stdIn.close(); echoSocket.close(); } else if(gameMode == 2) { while(!end) { char[] buffer = new char[256]; in.read(buffer, 0, 256); for(int i = 0; i < buffer.length; ++i) { if(Arrays.equals(Arrays.copyOfRange(buffer, i, i+9), go)) { frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING)); JOptionPane.showMessageDialog(null, "\nGAME OVER\n"); end = true; } } System.out.println(String.valueOf(buffer).trim()); window.updateBoard(String.valueOf(buffer).trim()); /* while(!end && boardoutput.length() < 4) { Thread.sleep(100); if(!undoString.equals("")) { System.out.println(undoString); //output.println(undoString); //output.flush(); undoString = ""; } if(boardoutput.length() == 4) { out = parseOutput(boardoutput); if(out == "Invalid") { out = ""; boardoutput = ""; System.out.println("Invalid move."); } } } */ System.out.println(out); //output.println(out); //output.flush(); boardoutput = ""; } output.close(); in.close(); stdIn.close(); echoSocket.close(); } } catch (IOException e){ System.err.println("IOException: " + e.getMessage()); } } }