Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.util.stream.Collectors;
- import java.util.stream.IntStream;
- import java.awt.event.*;
- import javax.swing.*;
- import java.util.*;
- /**This program uses GUI, including a JTextField. Both javax.swing.* and java.awt.event.* need to be imported in this program.
- *This program also uses java.util.*
- */
- public class ConnectFour {
- private static final char[] players = new char[] { 'X', 'O' };
- private final int width, height;
- private int lastCol = -1, lastTop = -1;
- private GUI gui=new GUI(); //The GUI class needs to be used in the ConnectFour class to have GUI for this game.
- final char[][] grid;
- public ConnectFour(int width, int height) {
- this.width = width;
- this.height = height;
- this.grid = new char[height][];
- for (int h = 0; h < height; h++) {
- Arrays.fill(this.grid[h] = new char[width], '.');
- }
- }
- public String toString() {
- return IntStream.range(0, this.width)
- .mapToObj(Integer::toString)
- .collect(Collectors.joining()) + "n" +
- Arrays.stream(this.grid)
- .map(String::new)
- .collect(Collectors.joining("n"));
- }
- /**
- * Prompts the user for a column, repeating until a valid
- * choice is made.
- */
- public void chooseAndDrop(char symbol) {
- //This string variable is used by a label to give details on whether a user entered a valid column number or not.
- String columnInfo="";
- do {
- /**The chooseAndDrop GUI will update two labels to display important information to the user(s).
- * It will tell the user(s) whether Player X or Player O is supposed to play and also if a
- * valid column number was entered by the users.
- */
- gui.chooseAndDropGUI(symbol, columnInfo);
- int col = gui.readPlayerInputForProcessing();
- columnInfo="";
- if (! (0 <= col && col < this.width)) {
- /**If a user entered a column number that is outside of the accepted range,
- * the columnInfo variable is updated to tell the user to pick a column
- * in the accepted range.
- */
- columnInfo="Column must be between 0 and " +
- (this.width - 1);
- continue;
- }
- for (int h = this.height - 1; h >= 0; h--) {
- if (this.grid[h][col] == '.') {
- this.grid[this.lastTop=h][this.lastCol=col] = symbol;
- return;
- }
- }
- /**If a user entered in a column number and that column is already full,
- * the columnInfo variable is updated to tell the user to pick a different column.
- */
- columnInfo="Column "+col+" is full.";
- }while (true);
- }
- /**
- * Detects whether the last chip played was a winning move.
- */
- public boolean isWinningPlay() {
- char sym = this.grid[this.lastTop][this.lastCol];
- String streak = String.format("%c%c%c%c", sym, sym, sym, sym);
- return contains(this.horizontal(), streak) ||
- contains(this.vertical(), streak) ||
- contains(this.slashDiagonal(), streak) ||
- contains(this.backslashDiagonal(), streak);
- }
- /**
- * The contents of the row containing the last played chip.
- */
- private String horizontal() {
- return new String(this.grid[this.lastTop]);
- }
- /**
- * The contents of the column containing the last played chip.
- */
- private String vertical() {
- StringBuilder sb = new StringBuilder(this.height);
- for (int h = 0; h < this.height; h++) {
- sb.append(this.grid[h][this.lastCol]);
- }
- return sb.toString();
- }
- /**
- * The contents of the "/" diagonal containing the last played chip
- * (coordinates have a constant sum).
- */
- private String slashDiagonal() {
- StringBuilder sb = new StringBuilder(this.height);
- for (int h = 0; h < this.height; h++) {
- int w = this.lastCol + this.lastTop - h;
- if (0 <= w && w < this.width) {
- sb.append(this.grid[h][w]);
- }
- }
- return sb.toString();
- }
- /**
- * The contents of the "" diagonal containing the last played chip
- * (coordinates have a constant difference).
- */
- private String backslashDiagonal() {
- StringBuilder sb = new StringBuilder(this.height);
- for (int h = 0; h < this.height; h++) {
- int w = this.lastCol - this.lastTop + h;
- if (0 <= w && w < this.width) {
- sb.append(this.grid[h][w]);
- }
- }
- return sb.toString();
- }
- private static boolean contains(String haystack, String needle) {
- return haystack.indexOf(needle) >= 0;
- }
- public static void main(String[] args) {
- int height = 6, width = 8, moves = height * width;
- ConnectFour board = new ConnectFour(width, height);
- /**The emptyChar char is used for the first time the function label_That_Tells_Player_What_Columns_They_Can_Pick_Or_Tells_Them_Who_Won_Function
- *is called. This is because no specific char value is needed for the first time this function is called. Due to the number in the first parameter,
- *this function sets the text of a label to tell the user(s) the acceptable range an inputed column number is supposed to be in.
- */
- char emptyChar=' ';
- board.gui.label_That_Tells_Player_What_Columns_They_Can_Pick_Or_Tells_Them_Who_Won_Function(2,width,emptyChar);
- //Since the board does not already exist, the last parameter is set to false to create a new empty board.
- board.gui.createBoard(width, height, board, false);
- for (int player = 0; moves-- > 0; player = 1 - player) {
- char symbol = players[player];
- board.chooseAndDrop(symbol);
- //Since the board already does exist, the last parameter is set to true to update the existing board.
- board.gui.createBoard(width, height, board, true);
- if (board.isWinningPlay()) {
- /**The symbol char is used for the second time the function label_That_Tells_Player_What_Columns_They_Can_Pick_Or_Tells_Them_Who_Won_Function
- *is called. Due to the number in the first parameter, this function will tell which player won. The symbol of the player who
- *won (X or O) is stored in the symbol char. Therefore, the symbol char is used to tell which player won.
- */
- board.gui.label_That_Tells_Player_What_Columns_They_Can_Pick_Or_Tells_Them_Who_Won_Function(1,width,symbol);
- return;
- }
- }
- /**The empty char is used for the third time the function label_That_Tells_Player_What_Columns_They_Can_Pick_Or_Tells_Them_Who_Won_Function
- *is called. This is because no specific char value is needed for the third time this function is called. Due to the number in the first parameter,
- *this function sets the text of a label to tell the user(s) that nobody has won.
- */
- board.gui.label_That_Tells_Player_What_Columns_They_Can_Pick_Or_Tells_Them_Who_Won_Function(0,width,emptyChar);
- }
- }
- //This class GUI is used to create GUI for the game.
- class GUI{
- private static JFrame jframe; //This variable is used to create a JFrame window.
- private static List<JLabel> boardLabels; //This list is used to store a group of labels related to the board's graphics.
- private static JLabel labelDisplayingWhosTurnItIs;
- private static JLabel labelTellingDetailsRegardingColumns;
- private static JLabel labelThatTellsPlayerWhatColumnsTheyCanPickOrTellsThemWhoWon;
- private final int defaultLabelWidth=100;
- private final int defaultLabelHeight=100;
- private final int lengthyLabelsWidth=400; //This width is used for labels that have a long width
- private final int defaultTextFieldWidth=200;
- private final int defaultTextFieldHeight=50;
- //The initial x coordinate for each label in the board's graphics is multiplied by this value to add spacing among each label in the board's graphics.
- private final int xScaling=50;
- //The initial y coordinate for each label in the board's graphics is multiplied by this value to add spacing among each label in the board's graphics.
- private final int yScaling=50;
- //After being multiplied, the x coordinate is added with xOffset to translate it to the right a little bit.
- private final int xOffset=50;
- //After being multiplied, the y coordinate is added with yOffset to translate it up a little bit.
- private final int yOffset=100;
- //The two variables below are used to set the size of the JFrame.
- private final int screenXSize=500;
- private final int screenYSize=900;
- //When a user presses the Enter key inside the text field, this variable is set to true.
- private static boolean inputReadyForProcessing=false;
- //This is the text field where input is entered by the player.
- private static JTextField playerInput=new JTextField("");
- public GUI() {
- /** A basic GUI window is created, and variables are initialized.
- * GUI elements are positioned in coordinates by setBounds
- * and are added to the JFrame window.
- */
- jframe=new JFrame();
- boardLabels=new ArrayList<JLabel>();
- jframe.setVisible(true);
- jframe.setSize(screenXSize,screenYSize);
- jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- jframe.setLayout(null);
- jframe.setResizable(false);
- labelDisplayingWhosTurnItIs=new JLabel("");
- labelDisplayingWhosTurnItIs.setBounds(150,550,defaultLabelWidth,defaultLabelHeight);
- labelTellingDetailsRegardingColumns=new JLabel("");
- labelTellingDetailsRegardingColumns.setBounds(150,600,lengthyLabelsWidth, defaultLabelHeight);
- labelThatTellsPlayerWhatColumnsTheyCanPickOrTellsThemWhoWon=new JLabel("");
- labelThatTellsPlayerWhatColumnsTheyCanPickOrTellsThemWhoWon.setBounds(150,750,lengthyLabelsWidth, defaultLabelHeight);
- playerInput.setBounds(125, 700, defaultTextFieldWidth, defaultTextFieldHeight);
- jframe.add(labelDisplayingWhosTurnItIs);
- jframe.add(labelThatTellsPlayerWhatColumnsTheyCanPickOrTellsThemWhoWon);
- jframe.add(labelTellingDetailsRegardingColumns);
- jframe.add(playerInput);
- /**An ActionListener is added to the text field variable. Whenever a player presses the Enter key inside this text field,
- * an action will be performed. In this case, inputReadyForProcessing is set to true, which will be useful in this program.
- */
- playerInput.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- inputReadyForProcessing=true;
- }
- });
- }
- //This function can both be used to create a new empty board and to update an existing board.
- public void createBoard(int width, int height, ConnectFour board, boolean updateExsistingBoard) {
- int indexOfLabel=0;
- for(int x=0; x<width; x++) {
- for(int y=0; y<height; y++) {
- /** Labels are set to the string variable slotLabelString.
- * This string variable adds a char to an empty string, which makes it
- * basically equal to a string version of the char. This variable
- * stores the value of a point in the grid array. This value is used
- * to set each label equal to its corresponding point in the grid array.
- * The grid array is used in the backbone for this program for basic
- * game logic.
- */
- String slotLabelString=board.grid[y][x]+"";
- if(updateExsistingBoard) {
- //If the board already exists, just update the label's text.
- boardLabels.get(indexOfLabel).setText(slotLabelString);
- }
- else {
- //If the board does not already exist, create a new label.
- boardLabels.add(new JLabel(slotLabelString));
- boardLabels.get(indexOfLabel).setBounds(x*xScaling+xOffset,y*yScaling+yOffset,defaultLabelWidth,defaultLabelHeight);
- }
- //Each label is added to the JFrame window.
- jframe.add(boardLabels.get(indexOfLabel));
- indexOfLabel++;
- }
- }
- }
- //This function can change the text of a specific label.
- public void label_That_Tells_Player_What_Columns_They_Can_Pick_Or_Tells_Them_Who_Won_Function(int did_Someone_Win_One_For_Yes_Two_For_No_Other_For_Draw, int width, char symbol) {
- if (did_Someone_Win_One_For_Yes_Two_For_No_Other_For_Draw==1) {
- labelThatTellsPlayerWhatColumnsTheyCanPickOrTellsThemWhoWon.setText("Player " + symbol + " wins!");
- }
- else if (did_Someone_Win_One_For_Yes_Two_For_No_Other_For_Draw==2) {
- labelThatTellsPlayerWhatColumnsTheyCanPickOrTellsThemWhoWon.setText("Use 0-" + (width - 1) + " to choose a column.");
- }
- else {
- labelThatTellsPlayerWhatColumnsTheyCanPickOrTellsThemWhoWon.setText("Game over, no winner.");
- }
- }
- /**This function is used to return the integer version of the string entered in the text field.
- *This function is called in the chooseAndDropGUI from the ConnectFour class.
- */
- public int readPlayerInputForProcessing()
- {
- while(true)
- {
- int playerInputValue;
- /**If a player entered an input that is not a number, trying to convert it into an integer would result in errors.
- * Therefore, the try and catch method is used.
- */
- try
- {
- playerInputValue=Integer.valueOf(playerInput.getText());
- }
- catch(Exception err)
- {
- //If an error is caused, the program goes back to the beginning of the while loop.
- continue;
- }
- /**This if statement is intentionally not the first if statement in the function.
- *This allows the function to have some time to process if whether inputReadyForProcessing is equal to true or not.
- *This variable is equal to true only if an Enter key was pressed in the text field. Therefore, the playerInputValue
- *is only returned when a user presses the Enter key. Otherwise, the program goes back to the beginning of the while loop.
- */
- if(!inputReadyForProcessing)
- {
- continue;
- }
- /** This variable is set back to its initial state, false. To make this variable true again, the Enter key will have to be
- * pressed inside the text field once again. This makes the program only return numerical input inside the text field only when
- * the Enter key is pressed inside the text field.
- */
- inputReadyForProcessing=false;
- return playerInputValue;
- }
- }
- /**
- * This function is created to create the GUI aspects for the function chooseAndDropGUI in the ConnectFour class.
- */
- public void chooseAndDropGUI(char symbol, String columnInfo) {
- labelDisplayingWhosTurnItIs.setText("nPlayer " + symbol + " turn: ");
- labelTellingDetailsRegardingColumns.setText(columnInfo);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement