Problem:
Connect four is a two-player board game in which the players alternately drop colored disks into a seven-column, six-row vertically suspended grid, as shown below.
The objective of the game is to connect four same-colored disks in a row, a column, or a diagonal before your opponent can do likewise. The program prompts two players to drop a RED or YELLOW disk alternately. Whenever a disk is dropped, the program re-displays the board on the console and determines the status of the game (win, draw, or continue).Output:
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
---------------
Drop a red disk at column (0–6):
0
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
|R| | | | | | |
---------------
Drop a yellow disk at column (0–6):
1
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
|R|Y| | | | | |
---------------
Drop a red disk at column (0–6):
2
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
|R|Y|R| | | | |
---------------
Drop a yellow disk at column (0–6):
3
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
|R|Y|R|Y| | | |
---------------
Drop a red disk at column (0–6):
4
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
|R|Y|R|Y|R| | |
---------------
Drop a yellow disk at column (0–6):
3
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | |Y| | | |
|R|Y|R|Y|R| | |
---------------
Drop a red disk at column (0–6):
2
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | |R|Y| | | |
|R|Y|R|Y|R| | |
---------------
Drop a yellow disk at column (0–6):
1
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| |Y|R|Y| | | |
|R|Y|R|Y|R| | |
---------------
Drop a red disk at column (0–6):
2
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | |R| | | | |
| |Y|R|Y| | | |
|R|Y|R|Y|R| | |
---------------
Drop a yellow disk at column (0–6):
1
| | | | | | | |
| | | | | | | |
| | | | | | | |
| |Y|R| | | | |
| |Y|R|Y| | | |
|R|Y|R|Y|R| | |
---------------
Drop a red disk at column (0–6):
1
| | | | | | | |
| | | | | | | |
| |R| | | | | |
| |Y|R| | | | |
| |Y|R|Y| | | |
|R|Y|R|Y|R| | |
---------------
Drop a yellow disk at column (0–6):
2
| | | | | | | |
| | | | | | | |
| |R|Y| | | | |
| |Y|R| | | | |
| |Y|R|Y| | | |
|R|Y|R|Y|R| | |
---------------
Drop a red disk at column (0–6):
4
| | | | | | | |
| | | | | | | |
| |R|Y| | | | |
| |Y|R| | | | |
| |Y|R|Y|R| | |
|R|Y|R|Y|R| | |
---------------
Drop a yellow disk at column (0–6):
3
| | | | | | | |
| | | | | | | |
| |R|Y| | | | |
| |Y|R|Y| | | |
| |Y|R|Y|R| | |
|R|Y|R|Y|R| | |
---------------
Drop a red disk at column (0–6):
4
| | | | | | | |
| | | | | | | |
| |R|Y| | | | |
| |Y|R|Y|R| | |
| |Y|R|Y|R| | |
|R|Y|R|Y|R| | |
---------------
Drop a yellow disk at column (0–6):
3
| | | | | | | |
| | | | | | | |
| |R|Y|Y| | | |
| |Y|R|Y|R| | |
| |Y|R|Y|R| | |
|R|Y|R|Y|R| | |
---------------
The yello player won.
import java.util.Scanner; //This will be.. a huge code so we will have to make //lots of methods for each aspect of the game public class ConnectFour { //We need to first create the basic visual pattern public static String[][] createPattern() { //Although the game is more like a table of 6 //columns and 6 rows, we're going to have to make //a 2D array of 7 rows and 15 columns because graphically //there's an extra row to show the ___ at the bottom //and you have double the columns that show | | | //between each number String[][] f = new String[7][15]; //Time to loop over each row from up to down for (int i =0;i<f.length;i++) { //Time to loop over each column from left to right for (int j =0;j<f[i].length;j++) { //Note how it is always the even column //that has the border and the odd column //between them that will be either empty or //have a number if (j% 2 == 0) f[i][j] ="|"; else f[i][j] = " "; //Time to make our lowest row if (i==6) f[i][j]= "-"; } } return f; } //Yes, we even need to make a new method for visually //printing our game, but at least it's not hard to do public static void printPattern(String[][] f) { for (int i =0;i<f.length;i++) { for (int j=0;j<f[i].length;j++) { System.out.print(f[i][j]); } System.out.println(); } } //Here's are basic move, making the lowest empty row //of a specific column have a Red public static void dropRedPattern(String[][] f) { //We need to have the user tell us what column he wants //to drop a red into //Note: the user isn't supposed to know that we have 15 columns //starting at index 0 till 14 but just 6 nice ones System.out.println("Drop a red disk at column (0–6): "); Scanner scan = new Scanner (System.in); //Thankfully, there's a simple formula for converting a 1-2-3-4-5-6 //user column number into a 1-3-5-7-9-11-13 int c = 2*scan.nextInt()+1; //Now that we know our column, we have to loop //over each row from the bottom to the top //till we find the first empty space, drop, and //then finish (i.e., break) the move //Note: although as coders we're used to starting from //0 to the end, here that wouldn't work so well because //it would involve multiple if statements, but try it out //on your own if you want to for (int i =5;i>=0;i--) { if (f[i][c] == " ") { f[i][c] = "R"; break; } } } //Same as the above step, just yellow public static void dropYellowPattern(String[][] f) { System.out.println("Drop a yellow disk at column (0–6): "); Scanner scan = new Scanner (System.in); int c = 2*scan.nextInt()+1; for (int i =5;i>=0;i--) { if (f[i][c] == " ") { f[i][c] = "Y"; break; } } } //Here's where it gets hard. //That's because there are basically four patterns //of Reds or Yellows that can win the game //One pattern is a horizontal line of four Rs or Ys, //another is a vertical line, another is a left-up to right-down //diagonal line, and the last is left-down to right-up diagonal, //We thus need to code for each type of line //and the various places where the line can be public static String checkWinner(String[][] f) { //Time to look for the first type of winning line, //a horizontal line //This line can be on any row, so let's loop over //each row starting from 0 to 5 (since 6 is just ___) for (int i =0;i<6;i++) { //On every row, the four-dotted line can look like //----_ _, _----_, or _ _---- //Here, _ can be an empty space or one of the colors //and - is not empty space AND every - has the same // color (R or Y) //Note: since our R/Y/Empty's can only be in odd places, //because of how we created the pattern in the first //method, then our count has to be incremented by 2 //and will start from 0 (which will be 1, ----_ _) //and stop at 6 (which will be 7, _ _----) for (int j=0;j<7;j+=2) { if ((f[i][j+1] != " ") && (f[i][j+3] != " ") && (f[i][j+5] != " ") && (f[i][j+7] != " ") && ((f[i][j+1] == f[i][j+3]) && (f[i][j+3] == f[i][j+5]) && (f[i][j+5] == f[i][j+7]))) //If we found a same-colored pattern, we'll return //the color so that we will know who won return f[i][j+1]; } } //For a vertical line, let's first loop over each //odd-numbered column by incrementing with 2 //and check for consecutive boxes in the same column //that are the same color //Note: make sure you understand the horizontal line's //codes first or else everything below this point will //make no sense to you for (int i=1;i<15;i+=2) { //Of course, our lines will look like ----__ but reversed //and there is need to our rows by 2 but just one //and we have to start at the vertical version of ----__ and //and stop at _ _ ---- so it's from 0 to 2 for (int j =0;j<3;j++) { if((f[j][i] != " ") && (f[j+1][i] != " ") && (f[j+2][i] != " ") && (f[j+3][i] != " ") && ((f[j][i] == f[j+1][i]) && (f[j+1][i] == f[j+2][i]) && (f[j+2][i] == f[j+3][i]))) return f[j][i]; } } //For the left-up to right-down diagonal line //We'll have to loop over the 3 uppermost //rows and then go from left to right column-wise for (int i=0;i<3;i++) { //As expected, our uppermost box will start from 1 //and increase by 2 until it becomes 7 (the 3rd box //on a row) //Note how we used 1 instead 0 for the count here //There's no real reason to use 1 instead of 0 or //vice versa, since we're still using an odd index //for the columns and incrementing by 2 for (int j=1;j<9;j+=2) { if((f[i][j] != " ") && (f[i+1][j+2] != " ") && (f[i+2][j+4] != " ") && (f[i+3][j+6] != " ") && ((f[i][j] == f[i+1][j+2]) && (f[i+1][j+2] == f[i+2][j+4]) && (f[i+2][j+4] == f[i+3][j+6]))) return f[i][j]; } } //Similar to the method above, but we're just reversing our //trajectory, i.e. we're starting from the rightmost column //instead of the leftmost like we did above for (int i=0;i<3;i++) { for (int j=7;j<15;j+=2) { if((f[i][j] != " ") && (f[i+1][j-2] != " ") && (f[i+2][j-4] != " ") && (f[i+3][j-6] != " ") && ((f[i][j] == f[i+1][j-2]) && (f[i+1][j-2] == f[i+2][j-4]) && (f[i+2][j-4] == f[i+3][j-6]))) return f[i][j]; } } //If after going over the table and we find no //same colored lines, then we have to return something //that says that we didn't find a winning color :P return null; } //The easy part: using these methods public static void main (String[] args) { //Time to make a pattern String[][] f = createPattern(); //Time to make a condition for our game to keep on //playing boolean loop = true; //We need something to keep track of whose turn it is int count = 0; printPattern(f); while(loop) { //Let's say that Red gets the first turn and thus //every other turn if (count % 2 == 0) dropRedPattern(f); else dropYellowPattern(f); count++;//We need to keep track of the turns printPattern(f); //Let's say we want to check for a winner during every //turn made and say who it is if (checkWinner(f) != null) { if (checkWinner(f) == "R") System.out.println("The red player won."); else if (checkWinner(f)== "Y") System.out.println("The yello player won."); //Well, if someone one, then the game has to end loop = false; } } } }
Thank you for your post, I have to do exactly the same thing for an assignment, and your solution works, whereas mine does not. I will now try to work out the differences. Thanks again.
ReplyDeleteI personally don't like to fill an array with the spacers.
ReplyDeleteI prefer to add such things in the to.String() method,
just before it's printed out, as they have no value in the rest of the code.
Thank you so much for the code. It was really helpful. I just had a question. How would you handle the ArrayIndexOutofBounds exception in this program?
ReplyDeleteThe code compiles and runs but the board won't print again after 1 move.
ReplyDeleteclick to read more
ReplyDeleteThank you so much for the code. It was really helpful.
ReplyDeletethank you for the code may i ask what algo did you use in here?
ReplyDelete