Created
June 22, 2019 19:28
-
-
Save ahmednasserpro/ff3a957e5bcff620c65f8724e337a68b to your computer and use it in GitHub Desktop.
(Game: play connect four with computer) Revise Exercise 18.34 to play the game with the computer. The program lets the user make a move first, followed by a move by the computer. The minimum requirement is for the computer to make a legal move. You are encouraged to design good strategies for the computer to make intelligent moves
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.*; | |
import java.awt.event.*; | |
import javax.swing.*; | |
public class PlayConnectFourWithComputer extends JFrame { | |
private Cell[][] cells = new Cell[6][7]; | |
private char nextDisc = 'R'; | |
private int[][] result; | |
private Timer timer = new Timer(100, new FlashingCells()); | |
private JButton startOver = new JButton("Start Over"); | |
public PlayConnectFourWithComputer() { | |
JPanel p1 = new JPanel(new GridLayout(6, 7)); | |
for (int i = 0; i < cells.length; i++) | |
for (int j = 0; j < cells[0].length; j++) | |
p1.add(cells[i][j] = new Cell(i, j)); | |
JPanel p2 = new JPanel(); | |
p2.add(startOver); | |
add(p1); | |
add(p2, BorderLayout.SOUTH); | |
startOver.addActionListener(new ActionListener() { | |
@Override | |
public void actionPerformed(ActionEvent e) { | |
timer.stop(); | |
startOver(); | |
} | |
}); | |
} | |
private class FlashingCells implements ActionListener { | |
@Override | |
public void actionPerformed(ActionEvent e) { | |
if (cells[result[0][0]][result[0][1]].token == ' ') { | |
cells[result[0][0]][result[0][1]].token = nextDisc; | |
cells[result[1][0]][result[1][1]].token = nextDisc; | |
cells[result[2][0]][result[2][1]].token = nextDisc; | |
cells[result[3][0]][result[3][1]].token = nextDisc; | |
} else { | |
cells[result[0][0]][result[0][1]].token = ' '; | |
cells[result[1][0]][result[1][1]].token = ' '; | |
cells[result[2][0]][result[2][1]].token = ' '; | |
cells[result[3][0]][result[3][1]].token = ' '; | |
} | |
repaint(); | |
} | |
} | |
class Cell extends JPanel { | |
public char token = ' '; | |
public int i, j; | |
public Cell(int i, int j) { | |
this.i = i; | |
this.j = j; | |
addMouseListener(new MouseAdapter() { | |
@Override | |
public void mousePressed(MouseEvent e) { | |
if (result != null) | |
return; // Game over | |
if (nextDisc == 'R' && isAvailabel(i, j)) { | |
token = nextDisc; | |
repaint(); | |
result = isConsecutiveFour(cells); | |
System.out.println(result); | |
if (result != null) { | |
timer.start(); | |
return; | |
} | |
if (isDraw()) { | |
JOptionPane.showMessageDialog(null, | |
"A draw, no winner, start over"); | |
startOver(); | |
} | |
nextDisc = 'Y'; | |
} | |
if (nextDisc == 'Y') { | |
int[][] availabelRowAndColumn = | |
getAvailabelRowAndColumn(cells); | |
int row = availabelRowAndColumn[0][0]; | |
int column = availabelRowAndColumn[0][1]; | |
cells[row][column].token = nextDisc; | |
cells[row][column].repaint(); | |
result = isConsecutiveFour(cells); | |
if (result != null) { | |
timer.start(); | |
return; | |
} | |
if (isDraw()) { | |
JOptionPane.showMessageDialog(null, | |
"A draw, no winner, start over"); | |
startOver(); | |
} | |
nextDisc = 'R'; | |
} | |
} | |
}); | |
} | |
@Override | |
protected void paintComponent(Graphics g) { | |
int radius = Math.min(getWidth(), getHeight()) * 4 / 10; | |
g.setColor(Color.blue); | |
g.fillRect(0, 0, getWidth(), getHeight()); | |
switch (token) { | |
case ' ': | |
g.setColor(Color.white); | |
g.fillOval(getWidth() / 2 - radius, getHeight() / 2 - radius, | |
radius * 2, radius * 2); | |
break; | |
case 'R': | |
g.setColor(Color.red); | |
g.fillOval(getWidth() / 2 - radius, getHeight() / 2 - radius, | |
radius * 2, radius * 2); | |
break; | |
case 'Y': | |
g.setColor(Color.yellow); | |
g.fillOval(getWidth() / 2 - radius, getHeight() / 2 - radius, | |
radius * 2, radius * 2); | |
} | |
} | |
public boolean isAvailabel(int i, int j) { | |
return cells[i][j].token == ' ' && (i == 5 || cells[i + 1][j].token != ' '); | |
} | |
private boolean isDraw() { | |
for (int i = 0; i < cells.length; i++) | |
for (int j = 0; j < cells[0].length; j++) | |
if (cells[i][j].token == ' ') | |
return false; | |
return true; | |
} | |
} | |
private void startOver() { | |
nextDisc = 'R'; | |
result = null; | |
for (int i = 0; i < cells.length; i++) | |
for (int j = 0; j < cells[0].length; j++) | |
cells[i][j].token = ' '; | |
repaint(); | |
} | |
private static int[][] getAvailabelRowAndColumn(Cell[][] cells) { | |
int numberOfElements = 0; | |
for (int i = 0; i < cells.length; i++) | |
for (int j = 0; j < cells[0].length; j++) | |
if (cells[i][j].isAvailabel(i, j)) | |
numberOfElements++; | |
int[][] array = new int[numberOfElements][2]; | |
int currentIndex = 0; | |
for (int i = 0; i < cells.length; i++) { | |
for (int j = 0; j < cells[0].length; j++) { | |
if (cells[i][j].isAvailabel(i, j)) { | |
array[currentIndex][0] = i; | |
array[currentIndex][1] = j; | |
currentIndex++; | |
} | |
} | |
} | |
if (numberOfElements != 0) { | |
int[][] result = new int[1][2]; | |
int random = (int) (Math.random() * numberOfElements); | |
result[0][0] = array[random][0]; | |
result[0][1] = array[random][1]; | |
return result; | |
} | |
return null; | |
} | |
private static int[][] isConsecutiveFour(Cell[][] cells) { | |
char[][] values = new char[cells.length][cells[0].length]; | |
for (int i = 0; i < cells.length; i++) | |
for (int j = 0; j < cells[0].length; j++) | |
values[i][j] = cells[i][j].token; | |
return isConsecutiveFour(values); | |
} | |
private static int[][] isConsecutiveFour(char[][] values) { | |
int numberOfRows = values.length; | |
int numberOfColumns = values[0].length; | |
// Check rows | |
for (int i = 0; i < numberOfRows; i++) { | |
if (isConsecutiveFour(values[i]) != null) { | |
int[][] result = new int[4][2]; | |
int k = isConsecutiveFour(values[i]); | |
result[0][0] = result[1][0] = result[2][0] = result[3][0] = i; | |
result[0][1] = k; | |
result[1][1] = k + 1; | |
result[2][1] = k + 2; | |
result[3][1] = k + 3; | |
return result; | |
} | |
} | |
// Check columns | |
for (int j = 0; j < numberOfColumns; j++) { | |
char[] column = new char[numberOfRows]; | |
for (int i = 0; i < numberOfRows; i++) | |
column[i] = values[i][j]; | |
if (isConsecutiveFour(column) != null) { | |
int[][] result = new int[4][2]; | |
int k = isConsecutiveFour(column); | |
result[0][0] = k; | |
result[1][0] = k + 1; | |
result[2][0] = k + 2; | |
result[3][0] = k + 3; | |
result[0][1] = result[1][1] = result[2][1] = result[3][1] = j; | |
return result; | |
} | |
} | |
// Check major diagnoal (lower part) | |
for (int i = 0; i < numberOfRows - 3; i++) { | |
int numberOfElements = numberOfRows - i; | |
char[] diagnoal = new char[numberOfElements]; | |
for (int j = 0; j < numberOfElements; j++) | |
diagnoal[j] = values[i + j][j]; | |
if (isConsecutiveFour(diagnoal) != null) { | |
int[][] result = new int[4][2]; | |
int k = isConsecutiveFour(diagnoal); | |
result[0][0] = i + k; | |
result[0][1] = i + k + 1; | |
result[0][2] = i + k + 2; | |
result[0][3] = i + k + 3; | |
result[0][1] = k; | |
result[1][1] = k + 1; | |
result[2][1] = k + 2; | |
result[3][1] = k + 3; | |
return result; | |
} | |
} | |
// Check major diagnoal (upper part) | |
for (int j = 1; j < numberOfColumns - 3; j++) { | |
int numberOfElements = numberOfColumns - j; | |
char[] diagnoal = new char[numberOfElements]; | |
for (int i = 0; i < numberOfElements; i++) | |
diagnoal[i] = values[i][j + i]; | |
if (isConsecutiveFour(diagnoal) != null) { | |
int[][] result = new int[4][2]; | |
int k = isConsecutiveFour(diagnoal); | |
result[0][0] = k; | |
result[1][0] = k + 1; | |
result[2][0] = k + 2; | |
result[3][0] = k + 3; | |
result[0][1] = k + j; | |
result[1][1] = k + j + 1; | |
result[2][1] = k + j + 2; | |
result[3][1] = k + j + 3; | |
return result; | |
} | |
} | |
// Check sub-diagnoal (left part) | |
for (int j = 3; j < numberOfColumns; j++) { | |
int numberOfElements = Math.min(j + 1, numberOfRows); | |
char[] diagnoal = new char[numberOfElements]; | |
for (int i = 0; i < numberOfElements; i++) | |
diagnoal[i] = values[i][j - i]; | |
if (isConsecutiveFour(diagnoal) != null) { | |
int[][] result = new int[4][2]; | |
int k = isConsecutiveFour(diagnoal); | |
result[0][0] = k; | |
result[1][0] = k + 1; | |
result[2][0] = k + 2; | |
result[3][0] = k + 3; | |
result[0][1] = j - k; | |
result[1][1] = j - k - 1; | |
result[2][1] = j - k - 2; | |
result[3][1] = j - k - 3; | |
return result; | |
} | |
} | |
// Check sub-diagnoal (right part) | |
for (int i = 1; i < numberOfRows - 3; i++) { | |
int numberOfElements = numberOfRows - i; | |
char[] diagnoal = new char[numberOfElements]; | |
for (int j = 0; j < numberOfElements; j++) | |
diagnoal[j] = values[i + j][numberOfColumns - j - 1]; | |
if (isConsecutiveFour(diagnoal) != null) { | |
int[][] result = new int[4][2]; | |
int k = isConsecutiveFour(diagnoal); | |
result[0][0] = i + k; | |
result[1][0] = i + k + 1; | |
result[2][0] = i + k + 2; | |
result[3][0] = i + k + 3; | |
result[0][1] = numberOfColumns - k - 1; | |
result[1][1] = numberOfColumns - k - 2; | |
result[2][1] = numberOfColumns - k - 3; | |
result[3][1] = numberOfColumns - k - 4; | |
return result; | |
} | |
} | |
return null; | |
} | |
private static Integer isConsecutiveFour(char[] values) { | |
for (int i = 0; i < values.length - 3; i++) { | |
boolean isEqual = true; | |
for (int j = i; j < i + 3; j++) { | |
if (values[j] == ' ' || values[j] != values[j + 1]) { | |
isEqual = false; | |
break; | |
} | |
} | |
if (isEqual) | |
return i; | |
} | |
return null; | |
} | |
public static void main(String[] args) { | |
JFrame frame = new PlayConnectFourWithComputer(); | |
frame.setSize(400, 300); | |
frame.setLocationRelativeTo(null); | |
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
frame.setVisible(true); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment