Java - Picross Game

Picross Game - Java


This is an application written in Java to implement the puzzle game of “Picross”. The user is able to play the game through an implemented graphical user interface.

Picross, is a visual game where the objective is to identify a picture on a cross board using a specific logic. The graphical user interface is implemented using Java Swing. The application utilizes a Model-View-Controller architecture. A server and client configuration was additionally implemented to allow user data and game configurations to be sent and stored at the server or received. Each row and column of the board has a sequence of numbers that indicate the number of blocks (squares) that should appear consecutively. The initial board is empty, and the player needs to use logic to determine the correct distribution of squares. For example, a sequence like (5,1) means there should be a group of 5 squares followed by some empty spaces and then another single square. The challenge lies in figuring out the correct arrangement of squares since no initial distribution information is provided.

A video demonstrating the application and the code is shown below:


Alternate Link

View the Source Code below, or view the full codebase on GitHub

Game
Client
Server
Splash
Model
View
Controller
Exported from Notepad++
1 /* 2 * File name: Game.java 3 * Author: Mostapha A 4 * Purpose: This contains the main method and uses the other classes 5 * Class list: Game.java, GameView.java, GameModel.java, GameController.java 6 */ 7 8 package piccross; 9 10 import java.awt.EventQueue; 11 12 /** 13 * Piccross class that contains the main method for the program, displays the 14 * splash screen then game 15 * 16 * @author Mostapha Abdelaziz 17 * @version 2.0 18 * @see piccross package 19 * @since Java 16 20 */ 21 public class Game { 22 23 /** 24 * The main method that combines the other classes, displays a splash screen then the game 25 * @param args default arguments 26 */ 27 public static void main(String[] args) { 28 GameView gameView = new GameView(); 29 GameModel gameModel = new GameModel(); 30 GameController gameController = new GameController(gameView, gameModel); 31 32 // create the splash screen 33 GameView.GameSplash splashScreen = new GameView.GameSplash(); 34 35 // call method to display 36 splashScreen.showSplashWindow(); 37 38 // display the game after the splash screen 39 EventQueue.invokeLater(new Runnable() { 40 @Override 41 public void run() { 42 gameController.startGame(""); 43 } 44 }); 45 46 } 47 } 48 49
Exported from Notepad++
1 /* 2 * File name: GameServer.java 3 * Author: Mostapha A 4 * Purpose: Creates and Manages a game client 5 * Class list: gameView.java, gameModel.java, gameController.java, DrawGame, ButtonHandler 6 */ 7 8 package piccross; 9 10 import java.awt.BorderLayout; 11 import java.awt.Color; 12 import java.awt.Dimension; 13 import java.awt.GridLayout; 14 import java.awt.event.ActionEvent; 15 import java.awt.event.ActionListener; 16 import java.io.BufferedReader; 17 import java.io.IOException; 18 import java.io.InputStreamReader; 19 import java.io.PrintStream; 20 import java.net.Socket; 21 import java.net.UnknownHostException; 22 23 import javax.swing.BorderFactory; 24 import javax.swing.JButton; 25 import javax.swing.JComboBox; 26 import javax.swing.JFrame; 27 import javax.swing.JLabel; 28 import javax.swing.JPanel; 29 import javax.swing.JScrollPane; 30 import javax.swing.JTextArea; 31 import javax.swing.JTextField; 32 33 /** 34 * GameClient class that sets up a piccross client 35 * 36 * @author Mostapha Abdelaziz 37 * @version 1.0 38 * @see piccross package, Game.java, GameModel.java, GameView.java 39 * @since Java 16 40 */ 41 public class GameClient { 42 /** The console to write information to */ 43 private static JTextArea console; 44 /** The button to initiate connection */ 45 private static JButton connect; 46 /** The text box for port number input */ 47 private static JTextField portInput; 48 /** The text box for user name input */ 49 private static JTextField userInput; 50 /** The text box for server name input */ 51 private static JTextField serverNameInput; 52 /** The port number */ 53 private static int portNum; 54 /** The GameView object */ 55 private static GameView gameView; 56 /** The GameModel object */ 57 private static GameModel gameModel; 58 /** The game controller object */ 59 private static GameController gameController; 60 /** The server name */ 61 private static String serverName; 62 /** The socket for connections */ 63 private static Socket socket; 64 /** buffered reader for information from server */ 65 private static BufferedReader serverInput; 66 /** print stream to send information to server */ 67 private static PrintStream serverOutput; 68 /** get the client id from server */ 69 private static String clientId; 70 /** a counter for the play button for logic purposes */ 71 private static int game = 0; 72 /** To keep track whether we are connected */ 73 private static boolean connected = false; 74 75 /** 76 * Main function that calls function to create GUI elements 77 * @param args 78 */ 79 public static void main(String[] args) { 80 create(); 81 } // end main 82 83 /** 84 * Creates the GUI elements 85 */ 86 private static void create() { 87 // create action listener 88 ButtonHandler buttonHandler = new ButtonHandler(); 89 90 // create the window 91 JFrame window = new JFrame("Piccross client - Mostapha"); 92 window.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); 93 94 // print a message if they try to close from the window button 95 window.addWindowListener(new java.awt.event.WindowAdapter() { 96 @Override 97 public void windowClosing(java.awt.event.WindowEvent windowEvent) { 98 write("Must close the client with the \"End\" button"); 99 } 100 }); 101 102 // create the text area and scrollpane 103 console = new JTextArea(); 104 JScrollPane consoleScroll = new JScrollPane(console); 105 console.setEditable(false); 106 console.setText(""); 107 108 // create the buttons and text options 109 JLabel userLabel = new JLabel("User:"); 110 userInput = new JTextField("user", 10); 111 JLabel serverLabel = new JLabel("Server:"); 112 serverNameInput = new JTextField("localhost", 10); 113 JLabel portLabel = new JLabel("Port:"); 114 portInput = new JTextField("1234", 6); 115 connect = new JButton("Connect"); 116 JButton end = new JButton("End"); 117 118 JButton newGame = new JButton("New Game"); 119 JButton drawGame = new JButton("Draw Game"); 120 JButton sendGame = new JButton("Send Game"); 121 JButton receiveGame = new JButton("Receive Game"); 122 JButton sendData = new JButton("Send Data"); 123 JButton play = new JButton("Play"); 124 125 // add listeners 126 connect.addActionListener(buttonHandler); 127 end.addActionListener(buttonHandler); 128 newGame.addActionListener(buttonHandler); 129 drawGame.addActionListener(buttonHandler); 130 sendGame.addActionListener(buttonHandler); 131 receiveGame.addActionListener(buttonHandler); 132 sendData.addActionListener(buttonHandler); 133 play.addActionListener(buttonHandler); 134 135 // add option elements to 2 panels and a main panel 136 JPanel info = new JPanel(); 137 JPanel buttons = new JPanel(); 138 info.add(userLabel); 139 info.add(userInput); 140 info.add(serverLabel); 141 info.add(serverNameInput); 142 info.add(portLabel); 143 info.add(portInput); 144 info.add(connect); 145 info.add(end); 146 147 buttons.add(newGame); 148 buttons.add(drawGame); 149 buttons.add(sendGame); 150 buttons.add(receiveGame); 151 buttons.add(sendData); 152 buttons.add(play); 153 154 JPanel options = new JPanel(); 155 options.setLayout(new BorderLayout()); 156 options.add(info, BorderLayout.NORTH); 157 options.add(buttons, BorderLayout.CENTER); 158 159 // set window layout and add elements 160 window.setLayout(new BorderLayout()); 161 window.add(options, BorderLayout.NORTH); 162 window.add(consoleScroll, BorderLayout.CENTER); 163 164 // set size and show 165 window.setSize(630, 350); 166 window.setResizable(false); 167 window.setVisible(true); 168 window.setLocationRelativeTo(null); 169 // window.pack(); 170 171 // create game elements 172 gameView = new GameView(); 173 gameModel = new GameModel(); 174 gameController = new GameController(gameView, gameModel); 175 } 176 177 /** 178 * Writes a message to system and GUI console 179 * @param message The message to write 180 */ 181 private static void write(String message) { 182 // write the message to console 183 console.append(message + "\n"); 184 System.out.println(message); 185 } 186 187 /** 188 * Attempts to connect to the server 189 * @return Return a boolean for connection status 190 */ 191 private static boolean connect() { 192 // create a socket with port number and server name 193 serverName = serverNameInput.getText(); 194 195 try { 196 // socket for connection 197 socket = new Socket(serverName, portNum); 198 // buffered reader for information from server 199 serverInput = new BufferedReader(new InputStreamReader(socket.getInputStream())); 200 // print stream to send information to server 201 serverOutput = new PrintStream(socket.getOutputStream()); 202 // get the client id from server 203 clientId = serverInput.readLine(); 204 // write we are connected 205 write("We are client " + clientId + " connected in server"); 206 connected = true; 207 return true; 208 } catch (UnknownHostException e) { 209 // TODO Auto-generated catch block 210 e.printStackTrace(); 211 write("Host name is invalid"); 212 } catch (IOException e) { 213 // TODO Auto-generated catch block 214 e.printStackTrace(); 215 write("Port Number is invalid"); 216 } catch (Exception e) { 217 e.printStackTrace(); 218 write("Unknown error"); 219 } 220 connected = false; 221 return false; 222 } 223 224 /** 225 * Attempts to send data to the server 226 * @param protocol Protocol number for communication purposes 227 * @param data The data being sent 228 * @throws IOException Disconnection exception 229 */ 230 private static void sendData(int protocol, String data) throws IOException { 231 // set output to data taken in 232 String output = data; 233 String input; 234 try { 235 write("Sending " + output); 236 // add necessary format 237 output = clientId + "#P" + protocol + "#" + output; 238 // send to server 239 serverOutput.println(output); 240 serverOutput.flush(); 241 // receive information from server 242 input = serverInput.readLine(); 243 String[] splitInput = input.split("#"); 244 // write("Server sent: " + input); 245 246 // case structure depending on protocol 247 switch (protocol) { 248 // cases 0 - 4 not receiving anything 249 case 0: 250 // end game protocol 251 write("Closing connection..."); 252 break; 253 case 1: 254 case 2: 255 case 3: 256 write(data + " sent"); 257 break; 258 case 4: 259 // receiving game configuration 260 if (splitInput[1].equals("0")) { 261 write("Server has no saved game"); 262 } else { 263 gameModel.generateBoard(splitInput[1]); 264 write("Received game " + gameModel.getString()); 265 } 266 break; 267 case 5: 268 break; 269 } 270 271 /* 272 * write("Client[" + clientId + "]: "); 273 * 274 * output = clientId + "#" + output; serverOutput.println(output); 275 */ 276 277 serverOutput.flush(); 278 // socket.close(); 279 280 } catch (Exception e) { 281 System.out.println(e); 282 // set connected to false and tell user we are disconnected 283 write("Connection to server lost"); 284 connected = false; 285 connect.setEnabled(true); 286 } 287 } 288 289 /** 290 * Creates the window to draw a game configuration 291 * @author moabd 292 * 293 */ 294 private static class DrawGame implements ActionListener { 295 /** The dimension of the drawing grid */ 296 private static int dimension = 5; 297 /** The array of buttons */ 298 private static JButton[][] playButtons; 299 /** The panel for the buttons */ 300 private static JPanel buttonGrid; 301 /** The combo box for grid options */ 302 private static JComboBox options; 303 /** The array for configuration string */ 304 private static int[][] configuration; 305 /** The frame for the draw window */ 306 private static JFrame drawGame; 307 308 /** 309 * creates the GUI elements of the draw window 310 */ 311 private void drawGame() { 312 // create a frame 313 drawGame = new JFrame(); 314 // create a combo box for options 315 JPanel sizeSelection = new JPanel(); 316 JLabel enterSize = new JLabel("Choose board size:"); 317 String[] sizes = { "2", "3", "4", "5", "6", "7", "8", "9", "10" }; 318 options = new JComboBox(sizes); 319 options.setSelectedIndex(3); 320 options.addActionListener(this); 321 sizeSelection.add(enterSize); 322 sizeSelection.add(options); 323 // create array for game configuration 324 configuration = new int[dimension][dimension]; 325 // create a button to save 326 JButton save = new JButton("save"); 327 save.addActionListener(this); 328 329 // create a panel to add the buttons to 330 buttonGrid = new JPanel(); 331 332 // create the grid 333 makeGrid(); 334 335 // add components 336 drawGame.add(sizeSelection, BorderLayout.NORTH); 337 drawGame.add(save, BorderLayout.SOUTH); 338 drawGame.add(buttonGrid, BorderLayout.CENTER); 339 340 drawGame.setResizable(false); 341 drawGame.setVisible(true); 342 drawGame.setLocationRelativeTo(null); 343 drawGame.pack(); 344 } 345 346 /** 347 * Creates a button and sets it up for actions 348 * 349 * @param name The name of the button, or the position 350 * @return Returns the created button 351 */ 352 public JButton createButton(String name) { 353 // create button 354 JButton button = new JButton(); 355 356 // set attributes 357 button.setPreferredSize(new Dimension((500 / dimension), (500 / dimension))); 358 button.setFocusable(false); 359 button.setBackground(Color.white); 360 button.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, new Color(70, 70, 70))); 361 // button.setText(name); 362 363 // set action 364 button.addActionListener(this); 365 button.setActionCommand(name); 366 // return the created button 367 return button; 368 } 369 370 /** 371 * Creates the button grid depending on the selected dimension 372 */ 373 private void makeGrid() { 374 // create an array for all the buttons, size of grid 375 playButtons = new JButton[dimension][dimension]; 376 buttonGrid.setLayout(new GridLayout(dimension, dimension)); 377 378 // set amount of names 379 String[] buttonNames = new String[dimension * dimension]; 380 // loop for grid size and create buttons 381 int i = 0; 382 int row = 0; 383 int column = 0; 384 for (i = 0; i < (dimension * dimension); i++) { 385 // reset column after reaches gridSize 386 if (column >= dimension) { 387 column = 0; 388 row++; 389 } 390 391 // create button name/action 392 buttonNames[i] = (column + 1) + "," + (row + 1); 393 394 // create and add button to array list 395 playButtons[column][row] = createButton(buttonNames[i]); 396 397 // thicker border for outside edge 398 if (column == 0 && row == 0) { 399 // top left corner 400 playButtons[column][row] 401 .setBorder(BorderFactory.createMatteBorder(4, 4, 2, 2, new Color(70, 70, 70))); 402 } else if (column == dimension - 1 && row == 0) { 403 // top right corner 404 playButtons[column][row] 405 .setBorder(BorderFactory.createMatteBorder(4, 2, 2, 4, new Color(70, 70, 70))); 406 } else if (column == 0 && row == dimension - 1) { 407 // bottom left corner 408 playButtons[column][row] 409 .setBorder(BorderFactory.createMatteBorder(2, 4, 4, 2, new Color(70, 70, 70))); 410 } else if (column == dimension - 1 && row == dimension - 1) { 411 // bottom right corner 412 playButtons[column][row] 413 .setBorder(BorderFactory.createMatteBorder(2, 2, 4, 4, new Color(70, 70, 70))); 414 } else if (column == 0) { 415 // left edge 416 playButtons[column][row] 417 .setBorder(BorderFactory.createMatteBorder(2, 4, 2, 2, new Color(70, 70, 70))); 418 } else if (row == 0) { 419 // top edge 420 playButtons[column][row] 421 .setBorder(BorderFactory.createMatteBorder(4, 2, 2, 2, new Color(70, 70, 70))); 422 } else if (column == dimension - 1) { 423 // right edge 424 playButtons[column][row] 425 .setBorder(BorderFactory.createMatteBorder(2, 2, 2, 4, new Color(70, 70, 70))); 426 } else if (row == dimension - 1) { 427 // bottom edge 428 playButtons[column][row] 429 .setBorder(BorderFactory.createMatteBorder(2, 2, 4, 2, new Color(70, 70, 70))); 430 } 431 432 // add to panel 433 buttonGrid.add(playButtons[column][row]); 434 435 column++; 436 } 437 438 } 439 440 /** 441 * Creates the configuration string based on the selected buttons 442 */ 443 private void createString() { 444 String config = ""; 445 // loop through config array and create configuration string 446 int x = 0; 447 int y = 0; 448 for (y = 0; y < dimension; y++) { 449 for (x = 0; x < dimension; x++) { 450 // create the string depending on which buttons are selected 451 if (configuration[x][y] == 0) { 452 config += "0"; 453 } else { 454 config += "1"; 455 } 456 } 457 // add comma unless it is the last row 458 if (y < dimension - 1) { 459 config += ","; 460 } 461 } 462 // change the game config string 463 gameModel.generateBoard(config); 464 } 465 466 /** 467 * Listens to actions on the items and performs functions depending on item selected 468 */ 469 @Override 470 public void actionPerformed(ActionEvent e) { 471 // if they choose a new dimension re-draw the grid 472 if (e.getActionCommand().equals("comboBoxChanged")) { 473 // set new dimension and redraw 474 dimension = Integer.parseInt(options.getSelectedItem().toString()); 475 buttonGrid.removeAll(); 476 makeGrid(); 477 buttonGrid.revalidate(); 478 buttonGrid.repaint(); 479 drawGame.pack(); 480 configuration = new int[dimension][dimension]; 481 } else if (e.getActionCommand().equals("save")) { 482 // if they click save set the game string, print and close 483 createString(); 484 drawGame.setVisible(false); 485 drawGame.dispose(); 486 write("New game " + gameModel.getString()); 487 } else { 488 // otherwise change the game configuration string 489 String[] coordinate = e.getActionCommand().split(","); 490 int x = Integer.parseInt(coordinate[0]) - 1; 491 int y = Integer.parseInt(coordinate[1]) - 1; 492 // check if button is unselected 493 if (configuration[x][y] == 0) { 494 // change color and set to selected 495 configuration[x][y] = 1; 496 playButtons[x][y].setBackground(new Color(97, 197, 255)); 497 } else { 498 // change color and set to unselected 499 configuration[x][y] = 0; 500 playButtons[x][y].setBackground(Color.WHITE); 501 } 502 } 503 } 504 } 505 506 /** 507 * Inner action listener class for managing the buttons 508 * 509 * @author Mostapha Abdelaziz 510 * @version 1.0 511 * @since Java 16 512 * @see GameServer 513 */ 514 private static class ButtonHandler implements ActionListener { 515 /** 516 * This is called when one of the buttons is clicked, it will execute a function 517 * depending on the button used 518 * 519 * @param e The event object with the event information 520 */ 521 @Override 522 public void actionPerformed(ActionEvent e) { 523 // store which button was pressed 524 String button = e.getActionCommand(); 525 // case structure to do different things depending on the button 526 switch (button) { 527 // check connection first with each case 528 case "Connect": 529 // get the port value 530 String input = portInput.getText(); 531 write("Connecting to server..."); 532 // validate input 533 if (input.length() > 5 || input.isBlank() || !input.matches("[0-9]+")) { 534 write("Port must be an integer number from 0 to 66535, try again"); 535 } else if (Integer.parseInt(input) < 0 || Integer.parseInt(input) > 66535) { 536 write("Port must be an integer number from 0 to 66535, try again"); 537 } else if (userInput.getText().equals("")){ 538 write("Enter a username, try again"); 539 }else { 540 // if it is valid establish server on port 541 portNum = Integer.parseInt(input); 542 try { 543 connected = connect(); 544 // if we are connected act accordingly 545 if (connected == true) { 546 // send our name 547 sendData(2, userInput.getText()); 548 // set connect button to not be enabled 549 connect.setEnabled(false); 550 } else { 551 write("We are not connected to a server"); 552 } 553 } catch (IOException e1) { 554 // TODO Auto-generated catch block 555 e1.printStackTrace(); 556 } 557 } 558 break; 559 case "End": 560 try { 561 // send end protocol 562 if (connected == true) { 563 sendData(0, "0"); 564 System.exit(0); 565 } else { 566 System.exit(0); 567 } 568 } catch (IOException e1) { 569 // TODO Auto-generated catch block 570 e1.printStackTrace(); 571 System.exit(0); 572 } 573 break; 574 case "New Game": 575 gameModel.generateString(); 576 577 write("New game " + gameModel.getString()); 578 break; 579 case "Draw Game": 580 // create a new game based on their selections 581 DrawGame draw = new DrawGame(); 582 draw.drawGame(); 583 break; 584 case "Send Game": 585 // send the config string if it is not empty 586 if (gameModel.getString().equals("0")) { 587 write("No game stored, create a new game or receive one first"); 588 } else { 589 // send the configuration 590 try { 591 if (connected == true) { 592 sendData(1, gameModel.getString()); 593 } else { 594 write("We are not connected to a server"); 595 } 596 } catch (IOException e1) { 597 // TODO Auto-generated catch block 598 e1.printStackTrace(); 599 } 600 } 601 break; 602 case "Receive Game": 603 // send a request for a configuration 604 try { 605 if (connected == true) { 606 sendData(4, "0"); 607 write("Current game is " + gameModel.getString()); 608 } else { 609 write("We are not connected to a server"); 610 } 611 } catch (IOException e2) { 612 // TODO Auto-generated catch block 613 e2.printStackTrace(); 614 } 615 break; 616 case "Send Data": 617 try { 618 if (connected == true) { 619 sendData(3, gameController.returnInfo()); 620 } else { 621 write("We are not connected to a server"); 622 } 623 } catch (IOException e1) { 624 // TODO Auto-generated catch block 625 e1.printStackTrace(); 626 } 627 break; 628 case "Play": 629 // start the game if we have a configuration 630 if (gameModel.getString().equals("0")) { 631 write("No game stored, create a new game or receive one first"); 632 } else { 633 if (game > 0) { 634 int dimension = gameModel.getDimension(); 635 String tempGameConfig = gameModel.getString(); 636 637 // reset view and model 638 gameView.reset(); 639 gameModel.reset(); 640 gameController.resetController(); 641 642 // set dimensions 643 gameView.setDimension(dimension); 644 gameModel.setDimension(dimension); 645 gameController.setDimension(dimension); 646 647 // reset play area 648 gameController.createNewGame(); 649 650 // create data for game logic 651 gameModel.generateBoard(tempGameConfig); 652 653 // setup hints 654 gameController.setupHints(); 655 gameView.setVisible(); 656 657 } else { 658 gameController.startGame(gameModel.getString()); 659 } 660 write("Starting game " + gameModel.getString()); 661 game++; 662 } 663 break; 664 } 665 } 666 667 } // end button handler class 668 669 } 670
Exported from Notepad++
1 /* 2 * File name: GameServer.java 3 * Author: Mostapha A 4 * Purpose: Creates and Manages a game server 5 * Class list: ButtonHandler, CheckBoxHandler, Connection 6 */ 7 8 package piccross; 9 10 import java.awt.BorderLayout; 11 import java.awt.event.ActionEvent; 12 import java.awt.event.ActionListener; 13 import java.awt.event.ItemEvent; 14 import java.awt.event.ItemListener; 15 import java.io.BufferedReader; 16 import java.io.IOException; 17 import java.io.InputStreamReader; 18 import java.io.PrintStream; 19 import java.net.InetAddress; 20 import java.net.ServerSocket; 21 import java.net.Socket; 22 import java.util.ArrayList; 23 24 import javax.swing.JButton; 25 import javax.swing.JCheckBox; 26 import javax.swing.JFrame; 27 import javax.swing.JLabel; 28 import javax.swing.JPanel; 29 import javax.swing.JScrollPane; 30 import javax.swing.JTextArea; 31 import javax.swing.JTextField; 32 33 /** 34 * GameServer class that sets up a piccross server 35 * 36 * @author Mostapha Abdelaziz 37 * @version 1.0 38 * @see piccross package 39 * @since Java 16 40 */ 41 public class GameServer implements Runnable { 42 /** The input box for port number */ 43 private static JTextField portInput; 44 /** The button to execute */ 45 private static JButton execute; 46 /** The text area for all the information to be printed */ 47 private static JTextArea console; 48 /** The port number */ 49 private static int portNum; 50 /** The socket for the connection */ 51 private static Socket sock; 52 /** The current client and total clients */ 53 static int nclient = 0, nclients = 0; 54 /** The server socket for the connections */ 55 static ServerSocket servsock; 56 /** The finalize checkbox */ 57 private static JCheckBox finalize; 58 /** The button to print results */ 59 private static JButton results; 60 /** The current game configuration */ 61 static String gameConfig = "0"; 62 /** The array of all client information */ 63 private static ArrayList<String[]> allInfo = new ArrayList<String[]>(); 64 65 /** 66 * Main function that calls function to create the GUI 67 * @param args 68 */ 69 public static void main(String[] args) { 70 // call the function that creates the gui 71 create(); 72 } 73 74 /** 75 * Creates GUI elements 76 */ 77 private static void create() { 78 // create action listener 79 ButtonHandler buttonHandler = new ButtonHandler(); 80 81 // create the window 82 JFrame window = new JFrame("Piccross server - Mostapha"); 83 window.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); 84 85 // print a message if they try to close from the window button 86 window.addWindowListener(new java.awt.event.WindowAdapter() { 87 @Override 88 public void windowClosing(java.awt.event.WindowEvent windowEvent) { 89 write("Must close the server with the \"End\" button"); 90 } 91 }); 92 93 // create the text area and scrollpane 94 console = new JTextArea(); 95 JScrollPane consoleScroll = new JScrollPane(console); 96 console.setEditable(false); 97 console.setText(""); 98 99 // create the buttons and text options 100 JLabel portLabel = new JLabel("Port:"); 101 portInput = new JTextField("1234", 6); 102 execute = new JButton("Execute"); 103 results = new JButton("Results"); 104 results.setEnabled(false); 105 JButton end = new JButton("End"); 106 finalize = new JCheckBox("Finalize"); 107 108 execute.addActionListener(buttonHandler); 109 results.addActionListener(buttonHandler); 110 end.addActionListener(buttonHandler); 111 finalize.addItemListener(new CheckBoxHandler()); 112 113 // add option elements to a panel 114 JPanel options = new JPanel(); 115 options.add(portLabel); 116 options.add(portInput); 117 options.add(execute); 118 options.add(results); 119 options.add(finalize); 120 options.add(end); 121 122 // set window layout and add elements 123 window.setLayout(new BorderLayout()); 124 window.add(options, BorderLayout.NORTH); 125 window.add(consoleScroll, BorderLayout.CENTER); 126 127 // set size and show 128 window.setSize(630, 350); 129 window.setResizable(false); 130 window.setVisible(true); 131 window.setLocationRelativeTo(null); 132 // window.pack(); 133 } 134 135 /** 136 * Writes a message to the system console and GUI console 137 * @param message The message to write 138 */ 139 private static void write(String message) { 140 // write the message to console 141 console.append(message + "\n"); 142 System.out.println(message); 143 } 144 145 /** Attempts to connect with a new thread */ 146 public static void connect() throws IOException { 147 try { 148 servsock = new ServerSocket(portNum); 149 Thread newThread = new Thread(new GameServer()); 150 newThread.start(); 151 write("Server on " + InetAddress.getLocalHost() + " port " + portNum); 152 // grey out execute button 153 execute.setEnabled(false); 154 results.setEnabled(true); 155 } catch (Exception e) { 156 System.out.println(e); 157 write("Port Number in use try again"); 158 } 159 160 } 161 162 /** 163 * Inner action listener class for managing the buttons 164 * 165 * @author Mostapha Abdelaziz 166 * @version 1.0 167 * @since Java 16 168 * @see GameServer 169 */ 170 private static class ButtonHandler implements ActionListener { 171 /** 172 * This is called when one of the buttons is clicked, it will execute a function 173 * depending on the button used 174 * 175 * @param e The event object with the event information 176 */ 177 @Override 178 public void actionPerformed(ActionEvent e) { 179 // store which button was pressed 180 String button = e.getActionCommand(); 181 // case structure to do different things depending on the button 182 switch (button) { 183 case "Execute": 184 // get the port value 185 String input = portInput.getText(); 186 187 // validate input 188 if (input.length() > 5 || input.isBlank() || !input.matches("[0-9]+")) { 189 write("Port must be an integer number from 0 to 66535, try again"); 190 } else if (Integer.parseInt(input) < 0 || Integer.parseInt(input) > 66535) { 191 write("Port must be an integer number from 0 to 66535, try again"); 192 } else { 193 // if it is valid establish server on port 194 portNum = Integer.parseInt(input); 195 try { 196 connect(); 197 198 } catch (IOException e1) { 199 // TODO Auto-generated catch block 200 e1.printStackTrace(); 201 } 202 } 203 204 break; 205 case "Results": 206 // print info 207 printInfo(); 208 break; 209 case "End": 210 // close server 211 try { 212 if (nclients > 0) 213 sock.close(); 214 } catch (IOException e1) { 215 // TODO Auto-generated catch block 216 e1.printStackTrace(); 217 } 218 System.exit(0); 219 break; 220 } 221 } 222 223 } // end button handler class 224 225 /** 226 * Inner item listener class for managing the finalize check box 227 * 228 * @author Mostapha Abdelaziz 229 * @version 1.0 230 * @since Java 16 231 * @see GameServer 232 */ 233 private static class CheckBoxHandler implements ItemListener { 234 /** 235 * This is called when the finalize check box is changed 236 * 237 * @param e The event object with the event information 238 */ 239 @Override 240 public void itemStateChanged(ItemEvent e) { 241 // print message depending on status 242 if (finalize.isSelected() == true) { 243 write("Server will close when there are no more connections"); 244 if (nclients == 0) { 245 System.exit(0); 246 } 247 } else { 248 write("Server will remain open when there are no more connections"); 249 } 250 251 } 252 }// end check box handler class 253 254 /** 255 * Prints the information in the array of client information 256 */ 257 public static void printInfo() { 258 // loop through our clients and print information 259 String scoreTime; 260 // if we have no clients write so 261 if (allInfo.size() == 0) { 262 write("No clients connected"); 263 } 264 for (String[] client : allInfo) { 265 // if they have no score and time print info accordingly 266 if (Integer.parseInt(client[1]) == 0) { 267 scoreTime = "has not finished a game"; 268 } else { 269 scoreTime = "last played game took " + client[1] + " seconds and scored " + client[2] + " points"; 270 } 271 // write each clients information 272 write("Client " + client[3] + " (" + client[0] + ") " + scoreTime); 273 } 274 } 275 276 /** 277 * The method that will run with a new thread, attempts to connect to a client 278 */ 279 public void run() { 280 // loop indefinitely 281 for (;;) { 282 // try to establish a connection 283 try { 284 // new client 285 sock = servsock.accept(); 286 nclient += 1; 287 nclients += 1; 288 write("Connecting " + sock.getInetAddress() + " in port " + sock.getPort()); 289 } catch (IOException ioe) { 290 System.out.println(ioe); 291 } 292 // new object that recieves info from client 293 Connection clientConnection = new Connection(sock, nclient); 294 clientConnection.start(); 295 } 296 } 297 298 /** 299 * The class that will take in all input and handle communications 300 * @author moabd 301 * 302 */ 303 class Connection extends Thread { 304 /** Socket for connection */ 305 Socket sock; 306 /** The unique client number */ 307 Integer clientid; 308 /** The clients name */ 309 String clientName; 310 /** A descriptor of the information received */ 311 String infoType; 312 /** An array for the clients information */ 313 String[] clientInfo = new String[4]; 314 315 /** 316 * The constructor of the class 317 * @param socket Previously established socket 318 * @param nclient The unique client number 319 */ 320 public Connection(Socket socket, int nclient) { 321 // receive the socket previously established a connection with 322 sock = socket; 323 clientid = nclient; 324 } 325 326 /** 327 * Handles all communications 328 */ 329 public void run() { 330 String clientData; 331 String returnInfo; 332 PrintStream clientOutput = null; 333 try { 334 // set the stream we will be printing to 335 clientOutput = new PrintStream(sock.getOutputStream()); 336 // set the reader we will be receiving from 337 BufferedReader clientInput = new BufferedReader(new InputStreamReader(sock.getInputStream())); 338 // send the client their client number 339 clientOutput.println(clientid); 340 // receive first info back 341 clientData = clientInput.readLine(); 342 343 // initialize our client info array 344 clientInfo[0] = "No name recorded"; 345 clientInfo[1] = "0"; 346 clientInfo[2] = "0"; 347 clientInfo[3] = clientid.toString(); 348 // store our client in all information array 349 allInfo.add(clientInfo); 350 351 // loop until end protocol 352 while (!clientData.equals(clientid + "#P0#0")) { 353 // default return value 354 returnInfo = "0"; 355 // case structure depending on input 356 String[] input = clientData.split("#"); 357 switch (input[1]) { 358 case "P1": 359 // receiving game configuration 360 gameConfig = input[2]; 361 infoType = "a game configuration (" + gameConfig + ")"; 362 break; 363 case "P2": 364 // receiving user name 365 clientInfo[0] = input[2]; 366 clientName = input[2]; 367 infoType = "their name"; 368 break; 369 case "P3": 370 // receiving time and score 371 clientInfo[1] = input[2]; 372 clientInfo[2] = input[3]; 373 infoType = "their time (" + clientInfo[1] + ") and score (" + clientInfo[2] + ")"; 374 break; 375 case "P4": 376 // receiving a request for a game configuration 377 returnInfo = gameConfig; 378 default: 379 380 break; 381 } 382 // write to console what was received 383 write("Client " + clientid + " (" + clientName + ") sent " + infoType); 384 // send something back 385 clientOutput.println(clientid + "#" + returnInfo); 386 387 // update info array 388 int i = 0; 389 for(i = 0; i < allInfo.size(); i++) { 390 if (allInfo.get(i)[3].equals(clientid.toString())) { 391 allInfo.set(i, clientInfo); 392 break; 393 } 394 } 395 396 // flush and receive next input 397 clientOutput.flush(); 398 clientData = clientInput.readLine(); 399 } 400 // if they sent end protocol 401 write("Disconnecting client " + clientid + " (" + clientName + ") at " + sock.getInetAddress()); 402 clientOutput.println(clientid + "#Closing Connection"); 403 // close socket 404 sock.close(); 405 406 // decrease client number 407 nclients -= 1; 408 write("There are " + nclients + " clients connected"); 409 410 // if finalize is checked and there are no clients automatically close the 411 // server 412 if (finalize.isSelected() && nclients == 0) { 413 write("Closing server..."); 414 System.exit(0); 415 } 416 } catch (IOException ioe) { 417 System.out.println(ioe); 418 } 419 } 420 } 421 } 422
Exported from Notepad++
1 /* 2 * File name: GameSplash.java 3 * Author: Mostapha A 4 * Purpose: This sets up the splash screen 5 * Class list: Piccross.java, GameSplash.java, GameController.java 6 */ 7 8 package piccross; 9 10 import java.awt.BorderLayout; 11 import java.awt.Dimension; 12 import java.awt.Toolkit; 13 import javax.swing.ImageIcon; 14 import javax.swing.JLabel; 15 import javax.swing.JPanel; 16 import javax.swing.JWindow; 17 18 /** 19 * GameSplash class that sets up the splash screen 20 * 21 * @author Mostapha Abdelaziz 22 * @version 1.0 23 * @see piccross package, Piccross.java 24 * @since Java 16 25 */ 26 public class GameSplash extends JWindow { 27 /** Required long value */ 28 private static final long serialVersionUID = 1L; 29 30 /** 31 * Displays a splash screen for 5 seconds 32 */ 33 public void showSplashWindow() { 34 // create panel that will hold image 35 JPanel splashPanel = new JPanel(new BorderLayout()); 36 37 // create a label to place splash screen image 38 JLabel label; 39 try { 40 label = new JLabel(new ImageIcon("images/loadingscreen.gif")); 41 } catch (Exception e) { 42 // print error and no image will be displayed instead of selected image 43 e.printStackTrace(); 44 label = new JLabel("No image"); 45 } 46 47 // add the image to our panel 48 splashPanel.add(label, BorderLayout.CENTER); 49 50 // get the size of the screen 51 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); 52 53 // calculate the position to place window in center of screens 54 int x = (screen.width - (600)) / 2; 55 int y = (screen.height - (300)) / 2; 56 57 // set the window size and put in the center of the screen 58 setBounds(x, y, (600), (300)); 59 60 // replace the window content with our image in the panel 61 setContentPane(splashPanel); 62 63 // ensure splash window is visible 64 setVisible(true); 65 66 // keep the screen up for 5 seconds 67 try { 68 // splash screen displays for 5000 milliseconds 69 Thread.sleep(5000); 70 } catch (InterruptedException e) { 71 // print error if one is caught 72 e.printStackTrace(); 73 System.out.println("Interrupted Exception " + e); 74 } 75 76 // release resources 77 dispose(); 78 } 79 }
Exported from Notepad++
1 /* 2 * File name: GameModel.java 3 * Author: Mostapha A 4 * Purpose: This maintains data and values 5 * Class list: Game.java, GameView.java, GameModel.java, GameController.java 6 */ 7 8 package piccross; 9 10 import java.util.Random; 11 import java.util.Timer; 12 import java.util.TimerTask; 13 14 /** 15 * GameModel class contains game data 16 * 17 * @author Mostapha Abdelaziz 18 * @version 1.0 19 * @see piccross package, Game.java, GameController.java 20 * @since Java 16 21 */ 22 public class GameModel { 23 /** The board dimension */ 24 private int dimension = 5; 25 /** The board array representation */ 26 private Integer[][] board; 27 /** The board selection array representation */ 28 private Integer[][] selectedBoard; 29 /** The string with the solution */ 30 private String configString = "0"; 31 32 /** The starting seconds for timer */ 33 private int seconds = 0; 34 /** Timer initialization */ 35 private Timer timer = new Timer(); 36 /** The timer task initialization */ 37 private TimerTask timerTask; 38 39 /** 40 * Default game model constructor 41 */ 42 GameModel() { 43 44 } 45 46 /** 47 * Generates a solution string based on dimensions 48 */ 49 public void generateString() { 50 int column = 0; 51 int row = 0; 52 // create a random object to randomize game solution 53 Random rd = new Random(); 54 // reset current string 55 configString = ""; 56 // temporary array and booleans for validation 57 int[][] stringArray = new int[dimension][dimension]; 58 boolean rowCheck = false; 59 boolean colCheck = false; 60 61 // loop through dimension, generating a string for solution 62 for (row = 0; row < dimension; row++) { 63 // reset boolean checks 64 rowCheck = false; 65 for (column = 0; column < dimension; column++) { 66 colCheck = false; 67 // check that each column has at least one 1, otherwise generate randoms 68 if (row == dimension - 1) { 69 // loop through the row 70 for (int i = 0; i < dimension - 1; i++) { 71 // check if there is a 1 in the row 72 if (stringArray[column][i] == 1) { 73 colCheck = true; 74 } 75 } 76 // if row check is false make last column in row a 1, otherwise randomise 77 if (colCheck == false) { 78 // set string and checks 79 colCheck = true; 80 configString = configString + "1"; 81 stringArray[column][row] = 1; 82 } else { 83 if (rd.nextBoolean() == true) { 84 // set string and checks 85 rowCheck = true; 86 configString = configString + "1"; 87 stringArray[column][row] = 1; 88 } else if (column == dimension - 1 && rowCheck == false) { 89 // if there isn't at least one 1 in row, make last column in row a 1 90 rowCheck = true; 91 configString = configString + "1"; 92 stringArray[column][row] = 1; 93 } else { 94 // set string and checks 95 configString = configString + "0"; 96 stringArray[column][row] = 0; 97 } 98 } 99 } else { 100 // generate a random boolean, true is 1 101 if (rd.nextBoolean() == true) { 102 // set string and checks 103 rowCheck = true; 104 configString = configString + "1"; 105 stringArray[column][row] = 1; 106 } else if (column == dimension - 1 && rowCheck == false) { 107 // if there isn't at least one 1 in row, make last column in row a 1 108 rowCheck = true; 109 configString = configString + "1"; 110 stringArray[column][row] = 1; 111 } else { 112 // set string and checks 113 configString = configString + "0"; 114 stringArray[column][row] = 0; 115 } 116 } 117 } 118 // add a comma to the string 119 if (row != dimension - 1) { 120 configString = configString + ","; 121 } 122 } 123 System.out.println(configString); 124 } 125 126 /** 127 * Generates a 2d array representing the board solution based on the configuration string 128 * @param string The configuration string to generate board out of 129 */ 130 public void generateBoard(String string) { 131 configString = string; 132 // split the config string based on commas 133 String[] rows = string.split(","); 134 dimension = rows[0].length(); 135 // reset / make a new board representation 136 board = new Integer[dimension][dimension]; 137 selectedBoard = new Integer[dimension][dimension]; 138 139 int column = 0; 140 int row = 0; 141 142 // loop through strings and create board 143 for(row = 0; row < dimension; row++) { 144 for(column = 0; column < dimension; column++) { 145 // loop through each column string and put corresponding value in the board 146 board[column][row] = Integer.parseInt(Character.toString(rows[row].charAt(column))); 147 // set selection to -1 for unselected 148 selectedBoard[column][row] = -1; 149 } 150 } 151 } 152 153 /** 154 * Returns the current configuration string 155 * @return The configuration string 156 */ 157 public String getString() { 158 return configString; 159 } 160 161 /** 162 * Resets the time to 0 163 */ 164 public void resetTime() { 165 seconds = 0; 166 } 167 168 /** 169 * Returns the current time 170 * @return The time in seconds 171 */ 172 public int returnTime() { 173 return seconds; 174 } 175 176 /** 177 * Changes the selection board 2d array representation based on a selection 178 * @param column The button's column dimension to change 179 * @param row The button's row dimension to change 180 * @param markOn Whether the mark checkbox is in use 181 * @return Whether the button was a correct selection 182 */ 183 public int selectButton(int column, int row, boolean markOn) { 184 // -1 = unselected 185 // 0 = correct mark (false/0) 186 // 1 = correct selection (true/1) 187 // 2 = incorrect mark(false/0) or selection(true/1) 188 189 // select the chosen button accordingly, return associated number 190 if ((board[column][row] == 1) && (markOn == false)) { 191 // if mark is unselected, and button is true set to 1 (correct selection/true) 192 selectedBoard[column][row] = 1; 193 return 1; 194 } else if ((board[column][row] == 0) && (markOn == true)) { 195 // if mark is selected, and button is false set to 0 (correct mark/false) 196 selectedBoard[column][row] = 0; 197 return 0; 198 } else { 199 // otherwise set to 2 (incorrect) 200 selectedBoard[column][row] = 2; 201 return 2; 202 } 203 } 204 205 /** 206 * Changes the boards dimension 207 * @param newDimension The new dimension for the board 208 */ 209 public void setDimension(int newDimension) { 210 dimension = newDimension; 211 } 212 213 /** 214 * Gets the dimension of the model 215 * @return the dimension size 216 */ 217 public int getDimension() { 218 return dimension; 219 } 220 221 /** 222 * Checks if a specific button is selected or not 223 * @param column The button's column dimension to check 224 * @param row The button's column dimension to check 225 * @return Whether the button is selected and if it is correct 226 */ 227 public int checkButtonSelected(int column, int row) { 228 // return the provided buttons status 229 return (selectedBoard[column][row]); 230 } 231 232 /** 233 * Checks the solution for a specific button 234 * @param column The button's column dimension to check 235 * @param row The button's column dimension to check 236 * @return The button's solution 237 */ 238 public int checkSolution(int column, int row) { 239 // return the provided buttons solution 240 return (board[column][row]); 241 } 242 243 /** 244 * Resets the selection boards 2d array representation to all unselected and timer to 0 245 */ 246 public void reset() { 247 // set each button to unselected 248 int column = 0; 249 int row = 0; 250 for (row = 0; row < dimension; row++) { 251 for (column = 0; column < dimension; column++) { 252 selectedBoard[column][row] = -1; 253 } 254 } 255 seconds = 0; 256 } 257 258 /** 259 * Starts and keeps track of the timer on the GUI 260 * @param gameView The GameView that will update the timer for 261 */ 262 public void startTimer(GameView gameView) { 263 // Timer task 264 timerTask = new TimerTask() { 265 public void run() { 266 seconds++; 267 // Update your interface 268 gameView.updateTimer(seconds); 269 } 270 }; 271 try { 272 timer.scheduleAtFixedRate(timerTask, 0, 1000); 273 } catch (Exception e) { 274 // Eventual treatment 275 276 } 277 } 278 } 279
Exported from Notepad++
1 /* 2 * File name: GameView.java 3 * Author: Mostapha A 4 * Purpose: This makes the splash screen and creates/maintains visual components 5 * Class list: Game.java, GameView.java, GameModel.java, GameController.java 6 */ 7 8 package piccross; 9 10 import java.awt.BorderLayout; 11 import java.awt.Color; 12 import java.awt.Component; 13 import java.awt.Dimension; 14 import java.awt.GridBagConstraints; 15 import java.awt.GridBagLayout; 16 import java.awt.GridLayout; 17 import java.awt.Toolkit; 18 19 import javax.swing.BorderFactory; 20 import javax.swing.BoxLayout; 21 import javax.swing.ImageIcon; 22 import javax.swing.JButton; 23 import javax.swing.JCheckBox; 24 import javax.swing.JFrame; 25 import javax.swing.JLabel; 26 import javax.swing.JMenu; 27 import javax.swing.JMenuBar; 28 import javax.swing.JMenuItem; 29 import javax.swing.JOptionPane; 30 import javax.swing.JPanel; 31 import javax.swing.JScrollPane; 32 import javax.swing.JTextArea; 33 import javax.swing.JTextField; 34 import javax.swing.JTextPane; 35 import javax.swing.JWindow; 36 import javax.swing.ScrollPaneConstants; 37 import javax.swing.border.Border; 38 import javax.swing.text.SimpleAttributeSet; 39 import javax.swing.text.StyleConstants; 40 import javax.swing.text.StyledDocument; 41 42 import java.awt.event.ActionListener; 43 import java.awt.event.ItemListener; 44 45 /** 46 * GameView class that sets up the splash screen and visual game components 47 * 48 * @author Mostapha Abdelaziz 49 * @version 1.1 50 * @see piccross package, Piccross.java, GameController.java 51 * @since Java 16 52 */ 53 public class GameView extends JFrame { 54 /** Required long value */ 55 private static final long serialVersionUID = 1L; 56 /** A grey border for use on different elements */ 57 private static Border greyBorder = BorderFactory.createMatteBorder(2, 2, 2, 2, new Color(70, 70, 70)); 58 /** A blue border for use on different elements */ 59 private static Border blueBorder = BorderFactory.createMatteBorder(3, 3, 3, 3, new Color(97, 197, 255)); 60 /** A grey background color for use on different elements */ 61 private static Color greyBG = new Color(84, 91, 102); 62 /** A light grey background color for use on different elements */ 63 private static Color lightGreyBG = new Color(107, 112, 122); 64 /** This is the check box for marking */ 65 private JCheckBox mark = new JCheckBox(); 66 /** This is the history area, the text box in the control panel */ 67 private JTextArea historyArea = new JTextArea(); 68 /** The panel that will contain the play area, hint area and mark check box */ 69 private static JPanel playArea; 70 /** 71 * The panel that will contain the logo and control panel elements score, time, 72 * history area and reset button 73 */ 74 private static JPanel controlPanel = new JPanel(); 75 /** The text box for the score */ 76 private JTextField score; 77 /** The text box for the time */ 78 private JTextField time; 79 /** The array that holds all the play buttons */ 80 private JButton[][] playButtons; 81 /** The array that holds all the hint areas */ 82 private JPanel[] hintAreas; 83 /** The array that holds the hint texts for the top hints */ 84 private JTextPane[] hintTextTop; 85 /** The array that holds the hint texts/labels for the side hints */ 86 private JLabel[] hintTextSide; 87 /** Keeps track of the board dimension */ 88 private int dimension = 5; 89 90 /** 91 * Default constructor, set the name 92 */ 93 GameView() { 94 // set window name 95 super("piccross - mostapha"); 96 } 97 98 /** 99 * Sets up all visual components of the piccross game 100 * 101 * @param menuHandler Tha handler for the menu 102 * @param playButtonHandler The handler for the playing buttons 103 * @param resetButtonHandler The handler for the reset button 104 * @param checkBoxHandler The handler for the mark check box 105 */ 106 public void startGame(ActionListener menuHandler, ActionListener playButtonHandler, 107 ActionListener resetButtonHandler, ItemListener checkBoxHandler) { 108 // set attributes for main window 109 setSize(987, 710); 110 getContentPane().setBackground(greyBG); 111 setResizable(false); 112 113 // hides window if they close from the window button 114 addWindowListener(new java.awt.event.WindowAdapter() { 115 @Override 116 public void windowClosing(java.awt.event.WindowEvent windowEvent) { 117 setVisible(false); 118 } 119 }); 120 121 // set the layout for our main window 122 setLayout(new BorderLayout()); 123 124 // set the image for application 125 ImageIcon miniLogo; 126 try { 127 miniLogo = new ImageIcon("images/logomini.png"); 128 setIconImage(miniLogo.getImage()); 129 } catch (Exception e) { 130 // print error and default image will be displayed 131 e.printStackTrace(); 132 } 133 134 // set up menu 135 setUpMenu(menuHandler); 136 137 // call methods that setup the separate panels 138 mark.addItemListener(checkBoxHandler); 139 setUpControlPanel(resetButtonHandler); 140 playArea = new JPanel(); 141 setUpPlayingArea(playButtonHandler, checkBoxHandler); 142 143 // add components 144 add(controlPanel, BorderLayout.WEST); 145 add(playArea, BorderLayout.CENTER); 146 147 // set visible as true and center in the screen 148 setVisible(true); 149 setLocationRelativeTo(null); 150 pack(); 151 } 152 153 /** 154 * sets the window as visible 155 */ 156 public void setVisible() { 157 setVisible(true); 158 } 159 160 /** 161 * Returns whether the mark check box is selected 162 * @return Selected status of mark check box 163 */ 164 public boolean checkMark() { 165 return mark.isSelected(); 166 } 167 168 /** 169 * Resets a games playing area visual components 170 * 171 * @param playButtonHandler The handler for play buttons 172 * @param checkBoxHandler The handler for the check box 173 */ 174 public void newGame(ActionListener playButtonHandler, ItemListener checkBoxHandler) { 175 // remove components to update 176 remove(playArea); 177 playArea.removeAll(); 178 // set up playing are again 179 setUpPlayingArea(playButtonHandler, checkBoxHandler); 180 revalidate(); 181 repaint(); 182 // re add and validate 183 add(playArea, BorderLayout.CENTER); 184 revalidate(); 185 repaint(); 186 } 187 188 /** 189 * Sets up the menu bar and all it's items 190 * 191 * @param menuHandler The handler for the menu items 192 */ 193 public void setUpMenu(ActionListener menuHandler) { 194 // create all the image icons 195 // ImageIcon newGameIcon; 196 ImageIcon solutionIcon; 197 ImageIcon exitIcon; 198 ImageIcon coloursIcon; 199 ImageIcon aboutIcon; 200 /* 201 * new game will be sub menu for different dimensions, no icon try { newGameIcon 202 * = new ImageIcon("images/newgame.gif"); } catch (Exception e) { // print error 203 * and no image will be displayed instead of selected image e.printStackTrace(); 204 * newGameIcon = new ImageIcon(); } 205 */ 206 try { 207 solutionIcon = new ImageIcon("images/solution.gif"); 208 } catch (Exception e) { // print error and no image will be displayed instead of selected image 209 e.printStackTrace(); 210 solutionIcon = new ImageIcon(); 211 } 212 try { 213 exitIcon = new ImageIcon("images/exit.gif"); 214 } catch (Exception e) { // print error and no image will be displayed instead of selected image 215 e.printStackTrace(); 216 exitIcon = new ImageIcon(); 217 } 218 try { 219 coloursIcon = new ImageIcon("images/colours.gif"); 220 } catch (Exception e) { // print error and no image will be displayed instead of selected image 221 e.printStackTrace(); 222 coloursIcon = new ImageIcon(); 223 } 224 try { 225 aboutIcon = new ImageIcon("images/about.gif"); 226 } catch (Exception e) { // print error and no image will be displayed instead of selected image 227 e.printStackTrace(); 228 aboutIcon = new ImageIcon(); 229 } 230 // Action commands 231 // 13 = 3x3 grid 232 // 15 = 5x5 grid 233 // 110 = 10x10 grid 234 // 2 = solution 235 // 3 = exit 236 // 4 = colours 237 // 5 = about 238 239 // Game menu 240 JMenu gameMenu = new JMenu("Game"); 241 242 // create submenu for new game 243 JMenu newGameMenu = new JMenu("New"); 244 245 // create new game menu options 246 JMenuItem newGame3 = new JMenuItem("3x3 Game"); 247 newGameMenu.add(newGame3); 248 newGame3.setActionCommand("13"); 249 newGame3.addActionListener(menuHandler); 250 JMenuItem newGame5 = new JMenuItem("5x5 Game"); 251 newGameMenu.add(newGame5); 252 newGame5.setActionCommand("15"); 253 newGame5.addActionListener(menuHandler); 254 JMenuItem newGame10 = new JMenuItem("10x10 Game"); 255 newGameMenu.add(newGame10); 256 newGame10.setActionCommand("110"); 257 newGame10.addActionListener(menuHandler); 258 259 // add new game to game menu 260 gameMenu.add(newGameMenu); 261 262 // create solution menu item - add in Game menu 263 JMenuItem solutionItem = new JMenuItem("Solution", solutionIcon); 264 gameMenu.add(solutionItem); 265 solutionItem.setActionCommand("2"); 266 solutionItem.addActionListener(menuHandler); 267 268 // create exit menu item - add in Game menu 269 JMenuItem exitItem = new JMenuItem("Exit", exitIcon); 270 gameMenu.add(exitItem); 271 exitItem.setActionCommand("3"); 272 exitItem.addActionListener(menuHandler); 273 274 // create menu bar, add game menu 275 JMenuBar menuBar = new JMenuBar(); 276 setJMenuBar(menuBar); 277 menuBar.add(gameMenu); 278 279 // create help menu 280 JMenu helpMenu = new JMenu("Help"); 281 282 // create colours menu item - add in Help menu 283 JMenuItem coloursItem = new JMenuItem("Colours", coloursIcon); 284 helpMenu.add(coloursItem); 285 coloursItem.setActionCommand("4"); 286 coloursItem.addActionListener(menuHandler); 287 288 // create about menu item - add in Help menu 289 JMenuItem aboutItem = new JMenuItem("About", aboutIcon); 290 helpMenu.add(aboutItem); 291 aboutItem.setActionCommand("5"); 292 aboutItem.addActionListener(menuHandler); 293 294 // add help menu to menu bar 295 menuBar.add(helpMenu); 296 297 } 298 299 /** 300 * Adds to the history area a passed through message 301 * 302 * @param message The string to be added to the history area 303 */ 304 public void historyAreaMessage(String message) { 305 historyArea.append(message); 306 historyArea.setCaretPosition(historyArea.getDocument().getLength()); 307 } 308 309 /** 310 * Changes a buttons colour 311 * 312 * @param column The button's column dimension 313 * @param row The button's row dimension 314 * @param colour The colour to change to 315 */ 316 public void changeButton(int column, int row, Color colour) { 317 // change the indicated button to the indicated colour 318 playButtons[column][row].setBackground(colour); 319 } 320 321 /** 322 * Writes the hints in the hint areas 323 * 324 * @param hintsTop The hints to be written in the top hint areas 325 * @param hintsSide The hints to be written in the side hint areas 326 */ 327 public void writeHints(Integer[][] hintsTop, Integer[][] hintsSide) { 328 int i = 0; 329 int j = 0; 330 String hint; 331 332 // loop to write hints in the top hint areas 333 for (i = 0; i < dimension; i++) { 334 // reset hint 335 hint = ""; 336 for (j = 0; j < 6; j++) { 337 // if the hint is not 0, store at end of string 338 if (hintsTop[i][j] != 0) { 339 hint = hint + hintsTop[i][j].toString() + "\n"; 340 } else { 341 // otherwise, hint is 0, put an empty space at the beginning of string 342 hint = " \n" + hint; 343 } 344 } 345 // store all the hints in the corresponding hint label for hint area 346 hintTextTop[i].setText(hint); 347 hintTextTop[i].setBackground(lightGreyBG); 348 hintTextTop[i].setHighlighter(null); 349 hintTextTop[i].setEditable(false); 350 // center the hints 351 StyledDocument doc = hintTextTop[i].getStyledDocument(); 352 SimpleAttributeSet center = new SimpleAttributeSet(); 353 StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER); 354 doc.setParagraphAttributes(0, doc.getLength(), center, false); 355 } 356 357 // loop to write hints in the side hint areas 358 for (i = 0; i < dimension; i++) { 359 // reset hint 360 hint = ""; 361 for (j = 0; j < 6; j++) { 362 // if the hint is not 0, store at end of string 363 if (hintsSide[i][j] != 0) { 364 hint = hint + " " + hintsSide[i][j].toString(); 365 } else { 366 // otherwise, hint is 0, put an empty space at the beginning of string 367 hint = " " + hint; 368 } 369 } 370 // store all the hints in the corresponding hint label for hint area 371 hint = hint + " "; 372 hintTextSide[i].setText(hint); 373 hintTextSide[i].setBackground(lightGreyBG); 374 } 375 } 376 377 /** 378 * Resets the history area and score 379 */ 380 public void reset() { 381 // set each button colour to white 382 int row = dimension; 383 int column = dimension; 384 for (row = 0; row < dimension; row++) { 385 for (column = 0; column < dimension; column++) { 386 playButtons[column][row].setBackground(Color.WHITE); 387 } 388 } 389 mark.setSelected(false); 390 historyArea.setText(""); 391 392 updateScore(0); 393 } 394 395 /** 396 * Updates the score 397 * 398 * @param scoreNum The new score 399 */ 400 public void updateScore(Integer scoreNum) { 401 score.setText(scoreNum.toString()); 402 } 403 404 /** 405 * Updates the timer 406 * 407 * @param seconds The new time 408 */ 409 public void updateTimer(Integer seconds) { 410 time.setText(seconds.toString()); 411 } 412 413 /** 414 * Creates and sets up the logo and control panel elements, including score, 415 * time, history text area and reset button 416 */ 417 public void setUpControlPanel(ActionListener resetButtonHandler) { 418 // set up the panels and layouts 419 controlPanel.setLayout(new BorderLayout()); 420 controlPanel.setBackground(greyBG); 421 controlPanel.setPreferredSize(new Dimension(300, 650)); 422 // panel for scrolling history area 423 JPanel historyAreaPanel = new JPanel(); 424 historyAreaPanel.setBackground(greyBG); 425 historyAreaPanel.setLayout(new BorderLayout()); 426 // panel that will contain logo, and panel that contains the score and time 427 JPanel topArea = new JPanel(); 428 topArea.setLayout(new BorderLayout()); 429 topArea.setBackground(greyBG); 430 // panel that will contain the score and time 431 JPanel scoreAndTime = new JPanel(); 432 scoreAndTime.setLayout(new BorderLayout()); 433 scoreAndTime.setBackground(greyBG); 434 // panel that contains the score label and text box 435 JPanel scorePanel = new JPanel(); 436 scorePanel.setLayout(new BorderLayout()); 437 scorePanel.setBackground(greyBG); 438 scorePanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 439 // panel that contains the time label and text box 440 JPanel timePanel = new JPanel(); 441 timePanel.setLayout(new BorderLayout()); 442 timePanel.setBackground(greyBG); 443 timePanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 444 // panel that will contain the reset button 445 JPanel resetPanel = new JPanel(); 446 resetPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 447 resetPanel.setBackground(greyBG); 448 449 // configure the elements that will be placed in the panels 450 // configure the label for score 451 JLabel labelScore = new JLabel("score "); 452 labelScore.setForeground(Color.white); 453 labelScore.setFont(controlPanel.getFont().deriveFont(25f)); 454 455 // configure the score text box 456 score = new JTextField(); 457 score.setEditable(false); 458 score.setText("0"); 459 score.setBorder(blueBorder); 460 score.setBackground(lightGreyBG); 461 score.setForeground(Color.white); 462 score.setFont(controlPanel.getFont().deriveFont(18f)); 463 score.setHorizontalAlignment(JTextField.CENTER); 464 465 // configure the label for the time 466 JLabel labelTime = new JLabel("time "); 467 labelTime.setForeground(Color.white); 468 labelTime.setFont(controlPanel.getFont().deriveFont(25f)); 469 470 // configure the text box for the time 471 time = new JTextField(); 472 time.setEditable(false); 473 time.setText("time"); 474 time.setBorder(blueBorder); 475 time.setBackground(lightGreyBG); 476 time.setForeground(Color.white); 477 time.setFont(controlPanel.getFont().deriveFont(18f)); 478 time.setHorizontalAlignment(JTextField.CENTER); 479 480 // configure history area text box 481 historyArea.setEditable(false); 482 historyArea.setFont(controlPanel.getFont().deriveFont(18f)); 483 historyArea.setText(""); 484 // historyArea.setBorder(blueBorder); 485 historyArea.setBackground(lightGreyBG); 486 historyArea.setForeground(Color.white); 487 // historyArea.setPreferredSize(new Dimension(280, 370)); 488 489 // create scrolling pane for history area 490 JScrollPane scrollingHistory = new JScrollPane(historyArea); 491 scrollingHistory.setBackground(greyBG); 492 scrollingHistory.setBorder(blueBorder); 493 // scrollingHistory.setPreferredSize(new Dimension(280, 370)); 494 scrollingHistory.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); 495 496 // add history area elements 497 historyAreaPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 498 historyAreaPanel.add(scrollingHistory, BorderLayout.CENTER); 499 500 // configure the reset button 501 JButton reset = new JButton(); 502 reset.addActionListener(resetButtonHandler); 503 reset.setPreferredSize(new Dimension(100, 40)); 504 reset.setAlignmentX(Component.CENTER_ALIGNMENT); 505 reset.setBackground(new Color(84, 91, 102)); 506 reset.setForeground(Color.white); 507 reset.setBorder(blueBorder); 508 reset.setText("reset"); 509 reset.setFont(controlPanel.getFont().deriveFont(25f)); 510 511 // Create and configure a label for the logo image 512 JLabel logo = new JLabel(); 513 ImageIcon logoImg; 514 try { 515 logoImg = new ImageIcon("images/logocpl.png"); 516 logo.setIcon(logoImg); 517 logo.setPreferredSize(new Dimension(300, 100)); 518 } catch (Exception e) { 519 // print error and display no image 520 e.printStackTrace(); 521 } 522 523 // add all elements to their respective panels 524 // the score 525 scorePanel.add(labelScore, BorderLayout.WEST); 526 scorePanel.add(score, BorderLayout.CENTER); 527 // the time 528 timePanel.add(labelTime, BorderLayout.WEST); 529 timePanel.add(time, BorderLayout.CENTER); 530 // reset button 531 resetPanel.add(reset); 532 533 // add our element panels to organizational panels 534 scoreAndTime.add(scorePanel, BorderLayout.NORTH); 535 scoreAndTime.add(timePanel, BorderLayout.SOUTH); 536 topArea.add(logo, BorderLayout.NORTH); 537 topArea.add(scoreAndTime, BorderLayout.CENTER); 538 539 // add all the panels to the control panel that will be placed west on main 540 // window 541 controlPanel.add(topArea, BorderLayout.NORTH); 542 controlPanel.add(historyAreaPanel, BorderLayout.CENTER); 543 controlPanel.add(resetPanel, BorderLayout.SOUTH); 544 } 545 546 /** 547 * Changes the boards dimension 548 * 549 * @param newDimension The new dimension 550 */ 551 public void setDimension(int newDimension) { 552 dimension = newDimension; 553 } 554 555 /** 556 * Displays a dialog at the end of the game 557 * 558 * @param score The user's score 559 */ 560 public void endGame(int score) { 561 // get end game images 562 ImageIcon victory; 563 ImageIcon failure; 564 565 // if perfect score show victory else defeat 566 if (score == dimension * dimension) { 567 try { 568 victory = new ImageIcon("images/gamepicwinner.png"); 569 JOptionPane.showMessageDialog(null, null, "Victory!", JOptionPane.INFORMATION_MESSAGE, victory); 570 } catch (Exception e) { // print error and no image will be displayed instead of selected image 571 e.printStackTrace(); 572 JOptionPane.showMessageDialog(null, "You won!", "Victory!", JOptionPane.INFORMATION_MESSAGE, null); 573 } 574 } else { 575 try { 576 failure = new ImageIcon("images/gamepicend.png"); 577 JOptionPane.showMessageDialog(null, null, "Defeat!", JOptionPane.INFORMATION_MESSAGE, failure); 578 } catch (Exception e) { // print error and no image will be displayed instead of selected image 579 e.printStackTrace(); 580 JOptionPane.showMessageDialog(null, "You lost the game!", "Defeat!", JOptionPane.INFORMATION_MESSAGE, 581 null); 582 } 583 } 584 } 585 586 /** 587 * Displays a dialog for about menu item 588 */ 589 public void aboutDialog() { 590 // get end game images 591 ImageIcon about; 592 593 try { 594 about = new ImageIcon("images/piccross.png"); 595 JOptionPane.showMessageDialog(null, null, "About", JOptionPane.INFORMATION_MESSAGE, about); 596 } catch (Exception e) { // print error and no image will be displayed instead of selected image 597 e.printStackTrace(); 598 JOptionPane.showMessageDialog(null, "About", "About", JOptionPane.INFORMATION_MESSAGE, null); 599 } 600 } 601 602 /** 603 * Creates and sets up the mark check box and playing area elements, including 604 * the buttons and hint area 605 */ 606 public void setUpPlayingArea(ActionListener playButtonHandler, ItemListener checkBoxHandler) { 607 // array for all the button names/action codes 608 String[] buttonNames; 609 // create an array for all the buttons, size of grid 610 playButtons = new JButton[dimension][dimension]; 611 // create a panel to add the buttons to 612 JPanel buttonGrid = new JPanel(); 613 buttonGrid.setLayout(new GridLayout(dimension, dimension)); 614 // create arrays for the hint areas 615 hintAreas = new JPanel[dimension + dimension]; 616 hintTextTop = new JTextPane[dimension]; 617 hintTextSide = new JLabel[dimension]; 618 // variables for grid size, and looping 619 int i = 0; 620 int row = 0; 621 int column = 0; 622 623 // set the JPanel for the play area attributes 624 playArea.setLayout(new GridBagLayout()); 625 playArea.setBackground(greyBG); 626 playArea.setBorder(BorderFactory.createEmptyBorder()); 627 // gridbaglayout constraints 628 GridBagConstraints c = new GridBagConstraints(); 629 630 // set amount of names 631 buttonNames = new String[dimension * dimension]; 632 633 // set up the panel for the mark box 634 JPanel markPanel = new JPanel(); 635 // create check box and mark label 636 JLabel markLabel = new JLabel("mark"); 637 markLabel.setForeground(Color.white); 638 markLabel.setFont(controlPanel.getFont().deriveFont(25f)); 639 // set the item listener and add 640 mark.setBackground(greyBG); 641 642 // add the mark elements to the mark panel 643 markPanel.add(markLabel); 644 markPanel.add(mark); 645 markPanel.setBackground(greyBG); 646 647 // add mark panel to playing area 648 c.gridx = 1; 649 c.gridy = 1; 650 playArea.add(markPanel, c); 651 652 // loop to set the hint area 653 for (i = 0; i < (dimension * 2); i++) { 654 // create a panel 655 JPanel hintArea = new JPanel(); 656 657 // set attributes 658 hintArea.setBackground(lightGreyBG); 659 660 // set positioning in play area 661 // if top row 662 if (i < dimension) { 663 hintArea.setBorder(BorderFactory.createMatteBorder(2, 2, 0, 2, greyBG)); 664 hintArea.setPreferredSize(new Dimension((500 / dimension), 150)); 665 hintArea.setLayout(new BoxLayout(hintArea, BoxLayout.PAGE_AXIS)); 666 667 c.gridy = 0; // doesnt change 668 c.gridx = i + 2; // moves over one 669 670 // size 671 c.gridheight = 2; 672 c.gridwidth = 1; 673 } else { 674 // if vertical/side hint area 675 hintArea.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 0, greyBG)); 676 hintArea.setPreferredSize(new Dimension(150, (500 / dimension))); 677 hintArea.setLayout(new BorderLayout()); 678 679 c.gridx = 0; // doesnt change 680 c.gridy = i + 2 - dimension; // moves down one 681 682 // size 683 c.gridheight = 1; 684 c.gridwidth = 2; 685 } 686 c.fill = GridBagConstraints.BOTH; 687 688 // add text and change postioning depending on top or side 689 if (i < dimension) { 690 // top hints 691 // create and add a text panel to top areas area 692 JTextPane hintLabel = new JTextPane(); 693 hintLabel.setFont(controlPanel.getFont().deriveFont(18f)); 694 hintLabel.setForeground(Color.WHITE); 695 696 hintLabel.setAlignmentX(Component.CENTER_ALIGNMENT); 697 hintLabel.setAlignmentY(Component.BOTTOM_ALIGNMENT); 698 699 // add to array 700 hintTextTop[i] = hintLabel; 701 // add to JPanel hintArea 702 hintArea.add(hintTextTop[i]); 703 } else { 704 // side hints 705 // create and add a text panel to top areas area 706 JLabel hintLabel = new JLabel("", JLabel.RIGHT); 707 hintLabel.setFont(controlPanel.getFont().deriveFont(18f)); 708 hintLabel.setForeground(Color.WHITE); 709 710 hintLabel.setAlignmentX(Component.RIGHT_ALIGNMENT); 711 hintLabel.setAlignmentY(Component.CENTER_ALIGNMENT); 712 713 // add to array 714 hintTextSide[i - dimension] = hintLabel; 715 // add to JPanel hintArea 716 hintArea.add(hintTextSide[i - dimension], BorderLayout.EAST); 717 } 718 719 // add to array list 720 hintAreas[i] = hintArea; 721 722 // add to play area 723 playArea.add(hintAreas[i], c); 724 } 725 726 // loop for grid size and create buttons 727 for (i = 0; i < (dimension * dimension); i++) { 728 // reset column after reaches gridSize 729 if (column >= dimension) { 730 column = 0; 731 row++; 732 } 733 734 // create button name/action 735 buttonNames[i] = (column + 1) + "," + (row + 1); 736 737 // create and add button to array list 738 playButtons[column][row] = createButton(buttonNames[i], playButtonHandler); 739 740 // thicker border for outside edge 741 if (column == 0 && row == 0) { 742 // top left corner 743 playButtons[column][row].setBorder(BorderFactory.createMatteBorder(4, 4, 2, 2, new Color(70, 70, 70))); 744 } else if (column == dimension - 1 && row == 0) { 745 // top right corner 746 playButtons[column][row].setBorder(BorderFactory.createMatteBorder(4, 2, 2, 4, new Color(70, 70, 70))); 747 } else if (column == 0 && row == dimension - 1) { 748 // bottom left corner 749 playButtons[column][row].setBorder(BorderFactory.createMatteBorder(2, 4, 4, 2, new Color(70, 70, 70))); 750 } else if (column == dimension - 1 && row == dimension - 1) { 751 // bottom right corner 752 playButtons[column][row].setBorder(BorderFactory.createMatteBorder(2, 2, 4, 4, new Color(70, 70, 70))); 753 } else if (column == 0) { 754 // left edge 755 playButtons[column][row].setBorder(BorderFactory.createMatteBorder(2, 4, 2, 2, new Color(70, 70, 70))); 756 } else if (row == 0) { 757 // top edge 758 playButtons[column][row].setBorder(BorderFactory.createMatteBorder(4, 2, 2, 2, new Color(70, 70, 70))); 759 } else if (column == dimension - 1) { 760 // right edge 761 playButtons[column][row].setBorder(BorderFactory.createMatteBorder(2, 2, 2, 4, new Color(70, 70, 70))); 762 } else if (row == dimension - 1) { 763 // bottom edge 764 playButtons[column][row].setBorder(BorderFactory.createMatteBorder(2, 2, 4, 2, new Color(70, 70, 70))); 765 } 766 767 // add to panel 768 buttonGrid.add(playButtons[column][row]); 769 770 column++; 771 } 772 773 // add button grid to play area layout 774 // set positions 775 c.gridx = 2; 776 c.gridy = 2; 777 778 // size 779 c.gridheight = dimension; 780 c.gridwidth = dimension; 781 c.fill = GridBagConstraints.BOTH; 782 783 // add to play area 784 playArea.add(buttonGrid, c); 785 } 786 787 /** 788 * Creates a button and sets it up for actions 789 * 790 * @param name The name of the button, or the position 791 * @param buttonHandler The action listener/event handler for the button 792 * @return Returns the created button 793 */ 794 public JButton createButton(String name, ActionListener buttonHandler) { 795 // create button 796 JButton button = new JButton(); 797 798 // set attributes 799 button.setPreferredSize(new Dimension((500 / dimension), (500 / dimension))); 800 button.setFocusable(false); 801 button.setBackground(Color.white); 802 button.setBorder(greyBorder); 803 // button.setText(name); 804 805 // set the action 806 button.setActionCommand(name); 807 button.addActionListener(buttonHandler); 808 809 // return the created button 810 return button; 811 } 812 813 /** 814 * GameSplash class that sets up the splash screen 815 * 816 * @author Mostapha Abdelaziz 817 * @version 1.0 818 * @see piccross package, Piccross.java 819 * @since Java 16 820 */ 821 public static class GameSplash extends JWindow { 822 /** Required long value */ 823 private static final long serialVersionUID = 1L; 824 825 /** 826 * Displays a splash screen for 5 seconds 827 */ 828 public void showSplashWindow() { 829 // create panel that will hold image 830 JPanel splashPanel = new JPanel(new BorderLayout()); 831 832 // create a label to place splash screen image 833 JLabel label; 834 try { 835 label = new JLabel(new ImageIcon("images/loadingscreen.gif")); 836 } catch (Exception e) { 837 // print error and no image will be displayed instead of selected image 838 e.printStackTrace(); 839 label = new JLabel("No image"); 840 } 841 842 // add the image to our panel 843 splashPanel.add(label, BorderLayout.CENTER); 844 845 // get the size of the screen 846 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); 847 848 // calculate the position to place window in center of screens 849 int x = (screen.width - (600)) / 2; 850 int y = (screen.height - (300)) / 2; 851 852 // set the window size and put in the center of the screen 853 setBounds(x, y, (600), (300)); 854 855 // replace the window content with our image in the panel 856 setContentPane(splashPanel); 857 858 // ensure splash window is visible 859 setVisible(true); 860 861 // keep the screen up for 5 seconds 862 try { 863 // splash screen displays for 5000 milliseconds 864 Thread.sleep(5000); 865 } catch (InterruptedException e) { 866 // print error if one is caught 867 e.printStackTrace(); 868 System.out.println("Interrupted Exception " + e); 869 } 870 871 // release resources 872 dispose(); 873 } 874 } 875 }
Exported from Notepad++
1 /* 2 * File name: GameController.java 3 * Author: Mostapha A 4 * Purpose: Manages the timer and deals with actions 5 * Class list: Game.java, GameView.java, GameModel.java, GameController.java 6 */ 7 8 package piccross; 9 10 import java.awt.BorderLayout; 11 import java.awt.Color; 12 import java.awt.Dimension; 13 import java.awt.event.ActionEvent; 14 import java.awt.event.ActionListener; 15 import java.awt.event.ItemEvent; 16 import java.awt.event.ItemListener; 17 18 import javax.swing.JButton; 19 import javax.swing.JColorChooser; 20 import javax.swing.JFrame; 21 import javax.swing.JLabel; 22 import javax.swing.JPanel; 23 24 /** 25 * GameController class that sets up the pic cross game 26 * 27 * @author Mostapha Abdelaziz 28 * @version 2.1 29 * @see piccross package, Game.java, GameModel.java, GameView.java 30 * @since Java 16 31 */ 32 public class GameController extends JFrame { 33 /** 34 * Default variable 35 */ 36 private static final long serialVersionUID = 1L; 37 /** 38 * The view portion of the game, will be set to what is passed through from the 39 * main 40 */ 41 private GameView gameView; 42 /** 43 * The model portion of the game, will be set to what is passed through from the 44 * main 45 */ 46 private GameModel gameModel; 47 /** Keeps track of current dimension/grid size */ 48 private int dimension = 5; 49 /** Keeps track of the score */ 50 private int score = 0; 51 /** Keeps track of how many buttons selected for checking end game */ 52 private int selections = 0; 53 /** Stores the colour for correct selections */ 54 private static Color correctColour = new Color(97, 197, 255); 55 /** Stores the colour for correct marked selections */ 56 private static Color markedColour = new Color(195, 180, 165); 57 /** Stores the colour for incorrect selections */ 58 private static Color errorColour = new Color(200, 86, 70); 59 /** The handler for the mark check box */ 60 CheckBoxHandler checkBoxHandler = new CheckBoxHandler(); 61 /** This is the time and score, it is set to 0 until the game is finished */ 62 private static String gameInfo = "0#0"; 63 64 /** 65 * Constructor for controller, takes in GameView and GameModel objects 66 * 67 * @param view The view portion of the game 68 * @param model The model portion of the game 69 */ 70 public GameController(GameView view, GameModel model) { 71 // set to class variables 72 gameView = view; 73 gameModel = model; 74 } 75 76 /** 77 * Starts the game, creates visual components and data needed 78 */ 79 public void startGame(String gameConfig) { 80 // create data for game logic 81 if (gameConfig == "") { 82 gameModel.generateString(); 83 gameModel.generateBoard(gameModel.getString()); 84 } else { 85 gameModel.generateBoard(gameConfig); 86 dimension = gameModel.getDimension(); 87 gameView.setDimension(dimension); 88 } 89 90 score = 0; 91 // create all the visual components 92 gameView.startGame(new MenuHandler(), new PlayButtonHandler(), new ResetHandler(), checkBoxHandler); 93 /* 94 gameView.reset(); 95 gameModel.reset(); 96 gameView.newGame(new PlayButtonHandler(), checkBoxHandler); 97 */ 98 99 // setup hints 100 setupHints(); 101 // start time 102 int time = gameModel.returnTime(); 103 if (time == 0) { 104 gameModel.startTimer(gameView); 105 } else { 106 gameModel.resetTime(); 107 } 108 109 } 110 111 /** 112 * Sets the dimension for controller 113 * @param newDimension The new dimension value 114 */ 115 public void setDimension(int newDimension) { 116 dimension = newDimension; 117 } 118 119 /** 120 * Return the current time and score 121 * 122 * @return The time and score in a string 123 */ 124 public String returnInfo() { 125 return gameInfo; 126 } 127 128 /** 129 * Calculates the hints and sends them to the View to write 130 */ 131 public void setupHints() { 132 // create hint arrays, and write in hint areas 133 int hintDimension = 6; 134 Integer[][] hintsTop = new Integer[dimension][hintDimension]; 135 Integer[][] hintsSide = new Integer[dimension][hintDimension]; 136 // variables for loops 137 int j; 138 int i; 139 int hintCounterSide; 140 int hintCounterTop; 141 int rowHint; 142 int colHint; 143 int rowHintPrev; 144 int colHintPrev; 145 146 // set hints to 0 by default 147 for (i = 0; i < dimension; i++) { 148 for (j = 0; j < hintDimension; j++) { 149 hintsTop[i][j] = 0; 150 hintsSide[i][j] = 0; 151 } 152 } 153 154 // loop to check solution for hints 155 for (i = 0; i < dimension; i++) { 156 // hints and related variables start/reset at 0 157 rowHint = 0; 158 colHint = 0; 159 rowHintPrev = 0; 160 colHintPrev = 0; 161 hintCounterSide = 0; 162 hintCounterTop = 0; 163 for (j = 0; j < dimension; j++) { 164 // check how many trues are in a row for the hintsSide (row) 165 if (gameModel.checkSolution(j, i) == 1) { 166 // increment current hint if the solution is true 167 rowHint++; 168 } else { 169 // otherwise set to 0 170 rowHint = 0; 171 } 172 173 // check if the current hint is 0, and previous was not we are storing hint, or 174 // if it is the last loop 175 if ((rowHint == 0) && (rowHintPrev > 0)) { 176 // store previous hint 177 hintsSide[i][hintCounterSide] = rowHintPrev; 178 hintCounterSide++; 179 } else if (j == dimension - 1) { 180 // if its last loop store the current row hint 181 hintsSide[i][hintCounterSide] = rowHint; 182 hintCounterSide++; 183 } 184 185 // set the previous row hint to current 186 rowHintPrev = rowHint; 187 188 // check how many trues are in a row for the hintsTop (column) 189 if (gameModel.checkSolution(i, j) == 1) { 190 // increment current hint if the solution is true 191 colHint++; 192 } else { 193 // otherwise set to 0 194 colHint = 0; 195 } 196 197 // check if the current hint is 0, and previous was not we are storing hint, or 198 // if it is the last loop 199 if ((colHint == 0) && (colHintPrev > 0)) { 200 // store previous hint 201 hintsTop[i][hintCounterTop] = colHintPrev; 202 hintCounterTop++; 203 } else if (j == dimension - 1) { 204 // if its last loop store the current column hint 205 hintsTop[i][hintCounterTop] = colHint; 206 hintCounterTop++; 207 } 208 209 // set the previous column hint to current 210 colHintPrev = colHint; 211 } 212 213 } 214 215 // call function to write to hint areas 216 gameView.writeHints(hintsTop, hintsSide); 217 } 218 219 /** 220 * Works with the view to change the colours of the buttons 221 * 222 * @param whichColour indicates which colour (selection/marked/error) to change 223 */ 224 private void changeColours(int whichColour) { 225 int column = 0; 226 int row = 0; 227 Color colour; 228 229 // set colour based on whats selected 230 if (whichColour == 0) { 231 colour = markedColour; 232 } else if (whichColour == 1) { 233 colour = correctColour; 234 } else { 235 colour = errorColour; 236 } 237 238 // loop through the grid of buttons, changing corresponding colour 239 for (row = 0; row < dimension; row++) { 240 for (column = 0; column < dimension; column++) { 241 // check the button selection status and update it's colour if it matches 242 if (gameModel.checkButtonSelected(column, row) == whichColour) { 243 gameView.changeButton(column, row, colour); 244 } 245 } 246 } 247 } 248 249 /** 250 * Shows the solution on the buttons 251 */ 252 private void showSolution() { 253 int column = 0; 254 int row = 0; 255 256 // loop through the grid of buttons, changing corresponding colour 257 for (row = 0; row < dimension; row++) { 258 for (column = 0; column < dimension; column++) { 259 // check the button solution and change button 260 if (gameModel.checkSolution(column, row) == 0) { 261 gameModel.selectButton(column, row, true); 262 gameView.changeButton(column, row, markedColour); 263 } else { 264 gameModel.selectButton(column, row, false); 265 gameView.changeButton(column, row, correctColour); 266 } 267 } 268 } 269 } 270 271 /** 272 * Creates a new game 273 */ 274 public void createNewGame() { 275 gameView.newGame(new PlayButtonHandler(), checkBoxHandler); 276 } 277 278 /** 279 * Resets the controller variables keeping track of the game 280 */ 281 public void resetController() { 282 selections = 0; 283 score = 0; 284 } 285 286 /** 287 * Inner action listener class for managing the playing buttons 288 * 289 * @author Mostapha Abdelaziz 290 * @version 1.0 291 * @since Java 16 292 * @see GameController 293 */ 294 private class PlayButtonHandler implements ActionListener { 295 /** 296 * This is called when a playing area button is clicked, it will print the 297 * position in the history area 298 * 299 * @param e The event object with the event information 300 */ 301 @Override 302 public void actionPerformed(ActionEvent e) { 303 String actionCommand = e.getActionCommand(); 304 // split the action command into integers for column and row 305 String[] dimensions = actionCommand.split(","); 306 int column = Integer.parseInt(dimensions[0]) - 1; 307 int row = Integer.parseInt(dimensions[1]) - 1; 308 309 // print action to history area (text area in control panel) and console 310 gameView.historyAreaMessage("Pos " + actionCommand + " clicked;\n"); 311 System.out.println(actionCommand); 312 313 // check if the button is selected 314 if (gameModel.checkButtonSelected(column, row) == -1) { 315 // call the model to keep track of selections, and set button color 316 int selection = gameModel.selectButton(column, row, gameView.checkMark()); 317 // 0 = correct mark (false/0) 318 // 1 = correct selection (true/1) 319 // 2 = incorrect mark(false/0) or selection(true/1) 320 if (selection == 0) { 321 score++; 322 gameView.changeButton(column, row, markedColour); 323 } else if (selection == 1) { 324 score++; 325 gameView.changeButton(column, row, correctColour); 326 } else { 327 score--; 328 gameView.changeButton(column, row, errorColour); 329 } 330 // increment selections 331 selections++; 332 // if we reached end of the game, show dialog 333 if (selections == dimension * dimension) { 334 gameView.endGame(score); 335 int time = gameModel.returnTime(); 336 gameInfo = time + "#" + score; 337 } 338 } 339 340 // update the score 341 gameView.updateScore(score); 342 343 } 344 345 } 346 347 /** 348 * Inner action listener class for managing the reset button 349 * 350 * @author Mostapha Abdelaziz 351 * @version 1.0 352 * @since Java 16 353 * @see GameController 354 */ 355 private class ResetHandler implements ActionListener { 356 /** 357 * This is called when the reset button is clicked, it will clear the history 358 * area 359 * 360 * @param e The event object with the event information 361 */ 362 @Override 363 public void actionPerformed(ActionEvent e) { 364 // clear the history area text 365 gameView.historyAreaMessage(""); 366 System.out.println("History area cleared"); 367 368 // reset buttons 369 gameView.reset(); 370 gameModel.reset(); 371 372 // reset score 373 score = 0; 374 selections = 0; 375 } 376 } 377 378 /** 379 * Inner item listener class for managing the mark check box 380 * 381 * @author Mostapha Abdelaziz 382 * @version 1.0 383 * @since Java 16 384 * @see GameController 385 */ 386 private class CheckBoxHandler implements ItemListener { 387 /** 388 * This is called when the mark check box is changed 389 * 390 * @param e The event object with the event information 391 */ 392 @Override 393 public void itemStateChanged(ItemEvent e) { 394 // if the check box is selected or unselected print info and toggle our variable 395 if (gameView.checkMark() == true) { 396 gameView.historyAreaMessage("Mark set;" + "\n"); 397 System.out.println("Mark set;"); 398 } else { 399 gameView.historyAreaMessage("Mark reset;" + "\n"); 400 System.out.println("Mark reset;"); 401 } 402 } 403 } 404 405 /** 406 * Inner action listener class for managing the menus 407 * 408 * @author Mostapha Abdelaziz 409 * @version 1.0 410 * @since Java 16 411 * @see GameController 412 */ 413 private class MenuHandler implements ActionListener { 414 /** 415 * This is called when any menu item is selected 416 * 417 * @param e The event object with the event information 418 */ 419 @Override 420 public void actionPerformed(ActionEvent e) { 421 // 13 = 3x3 grid 422 // 15 = 5x5 grid 423 // 110 = 10x10 grid 424 // 2 = solution 425 // 3 = exit 426 // 4 = colours 427 // 5 = about 428 429 String menuChoice = e.getActionCommand(); 430 431 // depending on menu choice do something 432 if (menuChoice == "13") { 433 // make a new game with a 3x3 grid 434 System.out.println("menu choice 3x3 grid selected"); 435 436 // reset view and model 437 gameView.reset(); 438 gameModel.reset(); 439 resetController(); 440 441 // set new dimension 442 dimension = 3; 443 gameView.setDimension(dimension); 444 gameModel.setDimension(dimension); 445 446 // reset play area 447 gameView.newGame(new PlayButtonHandler(), checkBoxHandler); 448 449 // create data for game logic 450 gameModel.generateString(); 451 gameModel.generateBoard(gameModel.getString()); 452 453 // setup hints 454 setupHints(); 455 456 } else if (menuChoice == "15") { 457 // make a new game with a 5x5 grid 458 System.out.println("menu choice 5x5 grid selected"); 459 // reset view and model 460 gameView.reset(); 461 gameModel.reset(); 462 resetController(); 463 464 // set new dimension 465 dimension = 5; 466 gameView.setDimension(dimension); 467 gameModel.setDimension(dimension); 468 469 // reset play area 470 gameView.newGame(new PlayButtonHandler(), checkBoxHandler); 471 472 // create data for game logic 473 gameModel.generateString(); 474 gameModel.generateBoard(gameModel.getString()); 475 476 // setup hints 477 setupHints(); 478 } else if (menuChoice == "110") { 479 // make a new game with a 10x10 grid 480 System.out.println("menu choice 10x10 grid selected"); 481 // reset view and model 482 gameView.reset(); 483 gameModel.reset(); 484 resetController(); 485 486 // set new dimension 487 dimension = 10; 488 gameView.setDimension(dimension); 489 gameModel.setDimension(dimension); 490 491 // reset play area 492 gameView.newGame(new PlayButtonHandler(), checkBoxHandler); 493 494 // create data for game logic 495 gameModel.generateString(); 496 gameModel.generateBoard(gameModel.getString()); 497 498 // setup hints 499 setupHints(); 500 } else if (menuChoice == "2") { 501 // display the solution, set score to 0 502 System.out.println("menu choice solution selected"); 503 gameModel.reset(); 504 gameView.reset(); 505 showSolution(); 506 score = 0; 507 508 // get solution string 509 String solution = gameModel.getString(); 510 String[] rows = solution.split(","); 511 // print to history area 512 for (String row : rows) { 513 gameView.historyAreaMessage(row + "\n"); 514 System.out.println(row); 515 } 516 } else if (menuChoice == "3") { 517 // exit the game 518 System.out.println("menu choice exit selected"); 519 System.exit(0); 520 } else if (menuChoice == "4") { 521 // display colour chooser 522 System.out.println("menu choice colour selected"); 523 new ColourChooser(); 524 } else if (menuChoice == "5") { 525 // display about dialog 526 System.out.println("menu choice about selected"); 527 gameView.aboutDialog(); 528 } 529 } 530 531 } 532 533 /** 534 * Inner colour chooser class deals with changing the colours in the menu 535 * 536 * @author Mostapha Abdelaziz 537 * @version 1.0 538 * @see piccross package, GameController.java, GameModel.java 539 * @since Java 16 540 */ 541 private class ColourChooser extends JFrame implements ActionListener { 542 /** Default variable */ 543 private static final long serialVersionUID = 1L; 544 /** The label that will display the correct selection colour */ 545 private JLabel correctLabel; 546 /** The label that will display the marked selection colour */ 547 private JLabel markedLabel; 548 /** The label that will display the incorrect selection colour */ 549 private JLabel errorLabel; 550 551 /** 552 * Constructor for the menu option to change colour, creates a new frame with 553 * selections 554 */ 555 ColourChooser() { 556 // new frame for choosing colours 557 JFrame coloursFrame = new JFrame("Choose Colours"); 558 coloursFrame.setLayout(new BorderLayout()); 559 560 // Three panels for each Colour 561 JPanel correctPanel = new JPanel(); 562 correctPanel.setLayout(new BorderLayout()); 563 JPanel markedPanel = new JPanel(); 564 markedPanel.setLayout(new BorderLayout()); 565 JPanel errorPanel = new JPanel(); 566 errorPanel.setLayout(new BorderLayout()); 567 568 // create labels and buttons for each colour 569 correctLabel = new JLabel(); 570 correctLabel.setBackground(correctColour); 571 correctLabel.setPreferredSize(new Dimension(150, 80)); 572 correctLabel.setOpaque(true); 573 markedLabel = new JLabel(); 574 markedLabel.setBackground(markedColour); 575 markedLabel.setPreferredSize(new Dimension(150, 80)); 576 markedLabel.setOpaque(true); 577 errorLabel = new JLabel(); 578 errorLabel.setPreferredSize(new Dimension(150, 80)); 579 errorLabel.setBackground(errorColour); 580 errorLabel.setOpaque(true); 581 582 // buttons 583 JButton correctButton = new JButton("Colour 1: Correct"); 584 correctButton.setPreferredSize(new Dimension(150, 30)); 585 correctButton.setActionCommand("correct"); 586 correctButton.addActionListener(this); 587 JButton markedButton = new JButton("Colour 2: Marked"); 588 markedButton.setPreferredSize(new Dimension(150, 30)); 589 markedButton.setActionCommand("marked"); 590 markedButton.addActionListener(this); 591 JButton errorButton = new JButton("Colour 3: Error"); 592 errorButton.setPreferredSize(new Dimension(150, 30)); 593 errorButton.setActionCommand("error"); 594 errorButton.addActionListener(this); 595 596 // add labels and buttons to their respective panels 597 correctPanel.add(correctLabel, BorderLayout.NORTH); 598 correctPanel.add(correctButton, BorderLayout.SOUTH); 599 markedPanel.add(markedLabel, BorderLayout.NORTH); 600 markedPanel.add(markedButton, BorderLayout.SOUTH); 601 errorPanel.add(errorLabel, BorderLayout.NORTH); 602 errorPanel.add(errorButton, BorderLayout.SOUTH); 603 604 // add panels to frame 605 coloursFrame.add(correctPanel, BorderLayout.WEST); 606 coloursFrame.add(markedPanel, BorderLayout.CENTER); 607 coloursFrame.add(errorPanel, BorderLayout.EAST); 608 609 // set dialog size and visibility 610 coloursFrame.setSize(470, 150); 611 coloursFrame.setVisible(true); 612 } 613 614 /** 615 * Action listener for keeping track of which colours are being changed 616 */ 617 public void actionPerformed(ActionEvent e) { 618 // store action command 619 String colourButton = e.getActionCommand(); 620 621 // change colours with a colour chooser depending on button 622 if (colourButton == "correct") { 623 // change the correct colour, and corresponding colour in the chooser and 624 // buttons 625 Color c = JColorChooser.showDialog(this, "Correct Colour", correctColour); 626 if (c != null) { 627 correctColour = c; 628 correctLabel.setBackground(c); 629 changeColours(1); 630 } 631 } else if (colourButton == "marked") { 632 // change the marked colour, and corresponding colour in the chooser and buttons 633 Color c = JColorChooser.showDialog(this, "Marked Colour", markedColour); 634 if (c != null) { 635 markedColour = c; 636 markedLabel.setBackground(c); 637 changeColours(0); 638 } 639 } else if (colourButton == "error") { 640 // change the error colour, and corresponding colour in the chooser and buttons 641 Color c = JColorChooser.showDialog(this, "Error Colour", errorColour); 642 if (c != null) { 643 errorColour = c; 644 errorLabel.setBackground(c); 645 changeColours(2); 646 } 647 } 648 } 649 } 650 651 }