Online-TicTacToe

Log | Files | Refs | README | LICENSE

commit 757c774d92592390ecf64a87e3c6e58ec85c28a8
parent a6639bde4e1e2d5cc32b20d8983e5cb8239d5e10
Author: William Lindholm <william_lindholm@outlook.com>
Date:   Thu,  5 Dec 2024 19:44:50 +0000

Minor refactoring

Diffstat:
MTicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/CustomPanel.java | 2+-
MTicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/MainContentPanel.java | 108+++++++++++++++++++++++++++++++++++++------------------------------------------
MTicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/StartPanel.java | 21++++++++++-----------
MTicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/TicTacToeGrid.java | 33++++++++++++++++-----------------
MTicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/allscore.java | 6+++++-
MTicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/login.java | 54+++++++++++++++++++++++++++---------------------------
MTicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/register.java | 6+-----
MTicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/score.java | 10++++++++--
MTicTacToeClient/src/main/java/com/groupproject/tictactoeclient/HelperMethods.java | 61++++++++++++++++++++++++++++++-------------------------------
MTicTacToeClient/src/main/java/com/groupproject/tictactoeclient/PollingThread.java | 9++++++---
MTicTacToeClient/src/main/java/com/groupproject/tictactoeclient/TicTacToeClient.java | 3---
11 files changed, 155 insertions(+), 158 deletions(-)

diff --git a/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/CustomPanel.java b/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/CustomPanel.java @@ -8,7 +8,7 @@ import javax.swing.JPanel; /** * - * @author Willi + * @author William */ public abstract class CustomPanel extends JPanel { public abstract void refresh(); diff --git a/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/MainContentPanel.java b/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/MainContentPanel.java @@ -7,6 +7,10 @@ import java.awt.event.ActionListener; import javax.swing.*; import javax.swing.event.ListSelectionListener; +/** + * + * @author William + */ public class MainContentPanel extends CustomPanel { TicTacToeClient client; @@ -33,7 +37,6 @@ public class MainContentPanel extends CustomPanel { JButton forfeitButton = new JButton("Forfeit Game"); JButton logoutButton = new JButton("Logout"); - openGamesList = new JList<>(); JScrollPane openGamesScrollPane = new JScrollPane(openGamesList); grid = new TicTacToeGrid(client, 3, 3); // A 3x3 TicTacToe grid @@ -109,7 +112,6 @@ public class MainContentPanel extends CustomPanel { layout.putConstraint(SpringLayout.SOUTH, scoreButton, -20, SpringLayout.SOUTH, this); layout.putConstraint(SpringLayout.EAST, scoreButton, -20, SpringLayout.EAST, this); - openGamesList.addListSelectionListener(e -> { if (!e.getValueIsAdjusting() && openGamesList.getSelectedValue() != null) { String selectedGame = openGamesList.getSelectedValue(); @@ -162,7 +164,7 @@ public class MainContentPanel extends CustomPanel { if (client.GID_Temp != null) { if (!client.UID.equals(client.HOST_UID)) { client.resetGame(); - client.UID2 = client.proxy.joinGame(Integer.parseInt(client.UID), Integer.parseInt(client.GID_Temp)); + client.proxy.joinGame(Integer.parseInt(client.UID), Integer.parseInt(client.GID_Temp)); client.GID = client.GID_Temp; client.HOST_UID = ""; } @@ -182,47 +184,40 @@ public class MainContentPanel extends CustomPanel { }); - - //forfeit button action listener forfeitButton.addActionListener(e -> { //If the user is also the host - if(client.UID.equals(client.HOST_UID)) - { + if (client.UID.equals(client.HOST_UID)) { //Set the game state to 2 indicating that player 2 has won client.proxy.setGameState(Integer.parseInt(client.GID), 2); - - } - else - { + + } else { //Set the game state to 1 indicating that player 1 has won client.proxy.setGameState(Integer.parseInt(client.GID), 1); } - + //Reset the game for the user after pressing forfeit client.resetGame(); //Go back to the main menu client.showPanel(new MainContentPanel(client)); refresh(); - + }); - - //Score button scoreButton.addActionListener(e -> { - + //Go to the clients score page client.showPanel(new score(client)); - + }); //leaderboard button allscoreButton.addActionListener(e -> { - + //Go to the leaderboard page client.showPanel(new allscore(client)); - + }); } @@ -287,57 +282,56 @@ public class MainContentPanel extends CustomPanel { remainingTime = 15 * 60; // timer that updates every second - timer = new Timer(1000,new ActionListener() { + timer = new Timer(1000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - - //countdown remaining timer - remainingTime--; - //Minutes - int minutes = remainingTime / 60; - - //seconds - int seconds = remainingTime % 60; + //countdown remaining timer + remainingTime--; - //Format the time - String time = String.format("%02d:%02d", minutes, seconds); + //Minutes + int minutes = remainingTime / 60; - //Update the game timer label on main content page with time - gameTimerLabel.setText(time); + //seconds + int seconds = remainingTime % 60; - //Check if theres been 2 moves - if (client.NUM_OF_MOVES >= 2) { - //if there has stop the timer - timer.restart(); - timer.stop(); - String time2 = String.format("15m 0s"); - gameTimerLabel.setText(time2); + //Format the time + String time = String.format("%02d:%02d", minutes, seconds); + //Update the game timer label on main content page with time + gameTimerLabel.setText(time); - } + //Check if theres been 2 moves + if (client.NUM_OF_MOVES >= 2) { + //if there has stop the timer + timer.restart(); + timer.stop(); + String time2 = String.format("15m 0s"); + gameTimerLabel.setText(time2); + + } + + //If the remaining time reaches 0 + if (remainingTime <= 0) { - //If the remaining time reaches 0 - if (remainingTime <= 0) { - - //Stop the timer - timer.stop(); - gameTimerLabel.setText("No opponent, please try again"); + //Stop the timer + timer.stop(); + gameTimerLabel.setText("No opponent, please try again"); - //delete the game using WS deleteGame() - String deleteGame = client.proxy.deleteGame(Integer.parseInt(client.GID), Integer.parseInt(client.UID)); + //delete the game using WS deleteGame() + String deleteGame = client.proxy.deleteGame(Integer.parseInt(client.GID), Integer.parseInt(client.UID)); - System.out.println(deleteGame); - //Reset the game - client.resetGame(); - - //Put user back into main menu - client.showPanel(new MainContentPanel(client)); - refresh(); + System.out.println(deleteGame); + //Reset the game + client.resetGame(); + + //Put user back into main menu + client.showPanel(new MainContentPanel(client)); + refresh(); + } } - } - + }); //start timer timer.start(); diff --git a/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/StartPanel.java b/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/StartPanel.java @@ -13,33 +13,32 @@ import javax.swing.SpringLayout; /** * - * @author Adam + * @author Adam */ public class StartPanel extends CustomPanel { + public StartPanel(TicTacToeClient client) { - + // Set panel layout to spring layout SpringLayout layout = new SpringLayout(); setLayout(layout); - + //Create the 2 buttons login and register JButton loginButton = new JButton("Login"); JButton registerButton = new JButton("Register"); - + //Add the Buttons to the panel add(loginButton); add(registerButton); - + //Login Button constraints layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, loginButton, -60, SpringLayout.HORIZONTAL_CENTER, this); layout.putConstraint(SpringLayout.VERTICAL_CENTER, loginButton, 0, SpringLayout.VERTICAL_CENTER, this); - + //Register Button constraints layout.putConstraint(SpringLayout.WEST, registerButton, 10, SpringLayout.EAST, loginButton); layout.putConstraint(SpringLayout.VERTICAL_CENTER, registerButton, 0, SpringLayout.VERTICAL_CENTER, this); - - - + //Login Button Action - go to login page loginButton.addActionListener(new ActionListener() { @Override @@ -47,7 +46,7 @@ public class StartPanel extends CustomPanel { client.showPanel(new login(client)); } }); - + //Register Button Action - go to the register page registerButton.addActionListener(new ActionListener() { @Override @@ -59,6 +58,6 @@ public class StartPanel extends CustomPanel { @Override public void refresh() { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + // not needed. } } diff --git a/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/TicTacToeGrid.java b/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/TicTacToeGrid.java @@ -39,15 +39,14 @@ public class TicTacToeGrid extends JPanel { add(button); button.addActionListener(e -> { - + if (client.OPPONENTS_TURN) { System.out.println("Not my turn!"); return; } System.out.println("It is my turn!"); - + //need to add an if statment that checks the GID - //client.UID2 = client.proxy.leagueTable(); if (client.UID.equals(client.HOST_UID)) { if (helperMethods.TakeSqure(index)) { button.setText("X"); @@ -59,53 +58,53 @@ public class TicTacToeGrid extends JPanel { } button.setEnabled(false); // prevents the player from clicking the same spot again client.OPPONENTS_TURN = true; // prevent user from taking square again - }); - } + }); + } } - public void refresh() { - System.out.println("UID: " + client.UID + ", HOST_UID: " + client.HOST_UID + ", GAME_ID: " + client.GID + ", MOVES: " + client.NUM_OF_MOVES + ", ISHOST: " + helperMethods.IsHost()); + public void refresh() { //go through the grid and clear the buttons for (var button : gridButtons) { button.setText(""); //set grid to empty button.setEnabled(true); } - + if (client.BOARD == null) { return; } - + final int[][] board = client.BOARD; client.NUM_OF_MOVES = client.BOARD.length; - + + // decide whose turn it is if (client.NUM_OF_MOVES % 2 == 0 && helperMethods.IsHost()) { client.OPPONENTS_TURN = false; } - + if (client.NUM_OF_MOVES % 2 == 1 && !helperMethods.IsHost()) { client.OPPONENTS_TURN = false; } - + for (int[] row : board) { // Convert grid coordinates to proper index int index = (row[2] * 3) + row[1]; - + // if there is no host player id saved save it from detected move if (!String.valueOf(row[0]).equals(client.UID) && client.HOST_UID.isBlank()) { client.HOST_UID = String.valueOf(row[0]); } - + if (String.valueOf(row[0]).equals(client.HOST_UID)) { gridButtons.get(index).setText("X"); gridButtons.get(index).setEnabled(false); } else { gridButtons.get(index).setText("O"); gridButtons.get(index).setEnabled(false); - } + } } - + this.revalidate(); this.repaint(); } - + } diff --git a/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/allscore.java b/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/allscore.java @@ -8,6 +8,10 @@ import java.awt.event.ActionListener; import java.util.HashMap; import java.util.Map; +/** + * + * Author: Luke + */ public class allscore extends CustomPanel { public allscore(TicTacToeClient client) { @@ -118,6 +122,6 @@ public class allscore extends CustomPanel { @Override public void refresh() { - //throw new UnsupportedOperationException("Not supported yet."); + // not needed } } diff --git a/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/login.java b/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/login.java @@ -3,40 +3,43 @@ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template */ package com.groupproject.tictactoeclient.ContentPanes; + import com.groupproject.tictactoeclient.TicTacToeClient; import java.awt.Color; import java.awt.event.*; import javax.swing.*; + /** * * @author adam */ public class login extends CustomPanel { + public login(TicTacToeClient client) { - + // Set panel layout to spring layout SpringLayout layout = new SpringLayout(); setLayout(layout); - + //Create the login Button JButton loginButton = new JButton("Login"); - + //Create the username and password Labels JLabel usernameLabel = new JLabel("username"); JLabel passwordLabel = new JLabel("password"); - + //Create the username and password text fields JTextField usernameTextField = new JTextField(20); JPasswordField passwordTextField = new JPasswordField(20); - + // Back button JButton backButton = new JButton("Back"); - + //Create a checkbox to show the password JCheckBox showPassword = new JCheckBox("show password"); - + //Create error message if login is not correct JLabel loginErrorLabel = new JLabel("Wrong username or password"); loginErrorLabel.setForeground(Color.red); @@ -51,59 +54,56 @@ public class login extends CustomPanel { add(showPassword); add(backButton); add(loginErrorLabel); - - + // UsernameLabel constraints layout.putConstraint(SpringLayout.EAST, usernameLabel, -20, SpringLayout.WEST, usernameTextField); layout.putConstraint(SpringLayout.VERTICAL_CENTER, usernameLabel, 0, SpringLayout.VERTICAL_CENTER, usernameTextField); - + //Username textfield Constraint layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, usernameTextField, 0, SpringLayout.HORIZONTAL_CENTER, this); layout.putConstraint(SpringLayout.VERTICAL_CENTER, usernameTextField, 0, SpringLayout.VERTICAL_CENTER, this); - + //PasswordLabel constraints layout.putConstraint(SpringLayout.EAST, passwordLabel, -20, SpringLayout.WEST, passwordTextField); layout.putConstraint(SpringLayout.VERTICAL_CENTER, passwordLabel, 0, SpringLayout.VERTICAL_CENTER, passwordTextField); - + //Password textfield constraint layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, passwordTextField, 0, SpringLayout.HORIZONTAL_CENTER, this); layout.putConstraint(SpringLayout.NORTH, passwordTextField, 20, SpringLayout.SOUTH, usernameTextField); - + //Show password checkbox constraint layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, showPassword, 0, SpringLayout.HORIZONTAL_CENTER, this); layout.putConstraint(SpringLayout.NORTH, showPassword, 20, SpringLayout.SOUTH, passwordTextField); - + //Login Button constraint layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, loginButton, 0, SpringLayout.HORIZONTAL_CENTER, this); layout.putConstraint(SpringLayout.NORTH, loginButton, 20, SpringLayout.SOUTH, showPassword); - + //Back button constraint layout.putConstraint(SpringLayout.WEST, backButton, 20, SpringLayout.WEST, this); layout.putConstraint(SpringLayout.NORTH, backButton, 20, SpringLayout.NORTH, this); - + //Error label constraint layout.putConstraint(SpringLayout.EAST, loginErrorLabel, -20, SpringLayout.EAST, this); layout.putConstraint(SpringLayout.NORTH, loginErrorLabel, 20, SpringLayout.NORTH, this); - - - + // Login Button Action - check the entries of the textFields loginButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String username = usernameTextField.getText(); // Get the username - client.username = username; + client.username = username; client.UID = String.valueOf(client.proxy.login(usernameTextField.getText(), String.valueOf(passwordTextField.getPassword()))); System.out.println("UID = " + client.UID); - + if (Integer.parseInt(client.UID) == -1) { loginErrorLabel.setVisible(true); } else { client.showPanel(new MainContentPanel(client)); } - } + } }); - + //Item listener to check if the showPassword checkbox has been selected //If selected show the password and if not display the password as **** normal char defaultPassword = passwordTextField.getEchoChar(); @@ -111,15 +111,15 @@ public class login extends CustomPanel { showPassword.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { - passwordTextField.setEchoChar((char) 0); + passwordTextField.setEchoChar((char) 0); } else { passwordTextField.setEchoChar(defaultPassword); } } }); - + // Back button listener - backButton.addActionListener( new ActionListener() { + backButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { client.showPanel(new StartPanel(client)); @@ -129,6 +129,6 @@ public class login extends CustomPanel { @Override public void refresh() { - + // not needed } } diff --git a/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/register.java b/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/register.java @@ -141,20 +141,16 @@ public class register extends CustomPanel { String response = client.proxy.register(usernameTextField.getText(), passwordTextField.getText(), nameTextField.getText(), surnameTextField.getText()); System.out.println(response); - //check if the username already exists, if not allow user to register if ("ERROR-REPEAT".equals(response)) { JOptionPane.showMessageDialog(client.frame, "User already exists"); return; } else { - //register the user and assign a User id to the client client.UID = response; //stores the username client.username = usernameTextField.getText(); - - System.out.println("Client.UID = " + client.UID); //once registered move to the main panel @@ -189,6 +185,6 @@ public class register extends CustomPanel { @Override public void refresh() { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + // not needed } } diff --git a/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/score.java b/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/ContentPanes/score.java @@ -6,7 +6,13 @@ import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; + +/** + * + * Author: Luke + */ public class score extends CustomPanel { + public score(TicTacToeClient client) { SpringLayout layout = new SpringLayout(); setLayout(layout); @@ -64,7 +70,7 @@ public class score extends CustomPanel { // Process league data String[] games = leagueData.split("\n"); // splits the league data into its diffrent games //counters for the wins, losses and draws - int wins = 0; + int wins = 0; int losses = 0; int draws = 0; @@ -118,6 +124,6 @@ public class score extends CustomPanel { @Override public void refresh() { - // Not supported yet + // Not needed } } diff --git a/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/HelperMethods.java b/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/HelperMethods.java @@ -9,81 +9,82 @@ import java.util.ArrayList; import java.util.Arrays; import javax.swing.JOptionPane; - /** * * @author William */ public class HelperMethods { + private TicTacToeClient client; - + public HelperMethods(TicTacToeClient client) { this.client = client; } - + public int[][] GetBoard(int gid) { System.out.println("Fetching board..."); String response = client.proxy.getBoard(gid); System.out.println(response); - + if ("ERROR-NOMOVES".equals(response)) { return null; } - + // Split by lines and map each line to an integer array return Arrays.stream(response.split("\n")) - .map(row -> Arrays.stream(row.split(",")) - .mapToInt(Integer::parseInt) - .toArray()) - .toArray(int[][]::new); + .map(row -> Arrays.stream(row.split(",")) + .mapToInt(Integer::parseInt) + .toArray()) + .toArray(int[][]::new); } - + public int[][] GetBoard() { if (client.GID.isBlank()) { return null; } - + return GetBoard(Integer.parseInt(client.GID)); } - + //Checks if the client is the Host or not public boolean IsHost() { return client.UID.equals(client.HOST_UID); } - - + /** * Take the square with selected index + * * @param index square to take - * @return return true if square was taken, false if it was already taken by opponent + * @return return true if square was taken, false if it was already taken by + * opponent */ public boolean TakeSqure(int index) { if ("0".equals(client.proxy.checkSquare(index % 3, (int) Math.floor(index / 3), Integer.parseInt(client.GID)))) { System.out.println("Taking square"); client.proxy.takeSquare(index % 3, (int) Math.floor(index / 3), Integer.parseInt(client.GID), Integer.parseInt(client.UID)); - + return true; } else { System.out.println("Cannot take square"); return false; } } - + //https://www.geeksforgeeks.org/java-joptionpane/ public void showOptions() { - + String[] options = {"Main Menu", "Quit"}; // Display an option dialog // The user's choice is stored in the 'choice' variable int choice = JOptionPane.showOptionDialog( - null, // Parent component (null means center on screen) - "Options", // Message to display - "Custom Options", // Dialog title - JOptionPane.YES_NO_CANCEL_OPTION, // Option type (Yes, No, Cancel) - JOptionPane.QUESTION_MESSAGE, // Message type (question icon) - null, // Custom icon (null means no custom icon) - options, // Custom options array - options[0] // Initial selection (default is "Cancel") + null, // Parent component (null means center on screen) + "Options", // Message to display + "Custom Options", // Dialog title + JOptionPane.YES_NO_CANCEL_OPTION, // Option type (Yes, No, Cancel) + JOptionPane.QUESTION_MESSAGE, // Message type (question icon) + null, // Custom icon (null means no custom icon) + options, // Custom options array + options[0] // Initial selection (default is "Cancel") ); // Check the user's choice and display a corresponding message @@ -92,19 +93,17 @@ public class HelperMethods { // reset their game and put them back to the main menu client.resetGame(); client.showPanel(new MainContentPanel(client)); - } - else if (choice == JOptionPane.NO_OPTION) { + } else if (choice == JOptionPane.NO_OPTION) { // If the user chose 'No' // quit the application System.exit(0); - } - else { + } else { // If the user chose 'Cancel' or closed the // dialog // show a message indicating the operation is // canceled JOptionPane.showMessageDialog(null, "Operation canceled."); } - + } } diff --git a/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/PollingThread.java b/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/PollingThread.java @@ -11,7 +11,7 @@ import javax.swing.JOptionPane; /** * - * @author Willi + * @author William */ public class PollingThread implements Runnable { @@ -26,6 +26,11 @@ public class PollingThread implements Runnable { helperMethods = new HelperMethods(client); } + /** + * TicTacToe polling thread. + * Calls on TicTacToeClient to update the currently open CustomPanel, extending JPanel + * Also used to periodically fetch new data from server (once per second) + */ @Override public void run() { while (true) { @@ -56,8 +61,6 @@ public class PollingThread implements Runnable { String result = client.proxy.checkWin(Integer.parseInt(client.GID)); System.out.println("checkWin: " + result); //if the game is not over check the result of the game - //if (!gameOver) { - System.out.println("gameOver not working"); switch (result) { case "1": diff --git a/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/TicTacToeClient.java b/TicTacToeClient/src/main/java/com/groupproject/tictactoeclient/TicTacToeClient.java @@ -31,7 +31,6 @@ public class TicTacToeClient { public String GID = ""; public boolean OPPONENTS_TURN = true; public int NUM_OF_MOVES = 0; - public String UID2; public String GID_Temp; public String HOST_UID = ""; public String username; @@ -88,7 +87,6 @@ public class TicTacToeClient { public void resetGame() { this.BOARD = null; this.GID = ""; - this.UID2 = null; this.HOST_UID = ""; this.NUM_OF_MOVES = 0; @@ -99,7 +97,6 @@ public class TicTacToeClient { public void logout() { this.UID = null; this.GID = ""; - this.UID2 = null; this.HOST_UID = ""; this.NUM_OF_MOVES = 0; this.BOARD = new int[2][2];