TicTacToe in java - java

I have problem with this code for test this is the error error 1 error 2
and this is the code
first class
import java.util.LinkedList;
import java.util.List;
public class Position {
public char[] board;
public char turn;
public int dim =3;
private int l;
public Position() {
this.board = " ".toCharArray();
this.turn = 'x';
}
public Position(char[] board, char turn) {
this.board = board;
this.turn = turn;
}
public Position(String str) {
this.board = str.toCharArray();
this.turn = 'x';
}
public Position(String str, char turn) {
this.board = str.toCharArray();
this.turn = turn;
}
public String toString () {
return new String(board);
}
public Position move (int idx) {
char[] newBoard = board.clone();
newBoard[idx] = turn;
return new Position(newBoard, turn == 'x' ? 'o' :'x');
}
public Integer[] possibleMoves() {
List<Integer> list = new LinkedList<Integer>();
for (int i = 0; i < board.length; i++) {
if (board[i] == ' ') {
list.add(i);
}
}
Integer[] array = new Integer[list.size()];
list.toArray(array);
return array;
}
public boolean win_line(char turn, int start, int step) {
for (int i = 0; i < 3; i++) {
if (board[start + step*i] != turn) {
return false;
}
}
return true;
}
public boolean win(char turn) {
for (int i = 0; i < dim; i++) {
if (win_line(turn, i*dim, l) || win_line(turn, i,dim)) {
return true;
}
}
if (win_line(turn, dim-1, dim-1) || win_line(turn, 0, dim+1)) {
return true;
}
return false;
}
public int minimax() {
if (win('x')) { return 100; }
if (win('o')) { return -100; }
if (possibleMoves().length == 0) { return 0; }
Integer mm = null;
for (Integer idx : possibleMoves()) {
Integer value = move(idx).minimax();
if (mm == null || turn == 'x' && mm < value || turn == 'o' && value < mm) {
mm = value;
}
}
return mm + (turn == 'x' ? -1 : 1);
}
public int bestMove() {
Integer mm = null;
int best = -1;
for (Integer idx : possibleMoves()) {
Integer value = move(idx).minimax();
if (mm == null || turn == 'x' && mm < value || turn == 'o' && value < mm) {
mm = value;
best = idx;
}
}
return best;
}
public boolean gameEnd() {
return win('x') || win('o') || possibleMoves().length ==0;
}
}
Second class for test
import static org.junit.Assert.*;
import org.junit.Test;
public class PositionTest {
#Test
public void testNew() throws Exception {
Position position = new Position();
assertEquals(" ", position.toString());
assertEquals('x', position.turn);
}
#Test
public void testMove() throws Exception {
Position position = new Position().move(1);
assertEquals(" x ", position.toString());
assertEquals('o', position.turn);
}
#Test
public void testPossibleMoves() throws Exception {
Position position = new Position().move(1).move(3).move(4);
assertArrayEquals(new Integer[] {0,2,5,6,7,8}, position.possibleMoves());
}
#Test
public void testWin() throws Exception {
assertFalse(new Position().win('x'));
assertTrue(new Position("xxx ").win('x'));
assertTrue(new Position(" ooo ").win('o'));
assertTrue(new Position("x x x ").win('x'));
assertTrue(new Position(" x x x ").win('x'));
assertTrue(new Position("x x x").win('x'));
}
#Test
public void testMinimax() throws Exception {
assertEquals( 100, new Position("xxx ").minimax());
assertEquals(-100, new Position("ooo ").minimax());
assertEquals( 0, new Position("xoxoxooxo").minimax());
assertEquals( 99, new Position(" xx ").minimax());
assertEquals( -99, new Position(" oo ", 'o').minimax());
}
#Test
public void testBestMove() throws Exception {
assertEquals(0, new Position(" xx ").bestMove());
assertEquals(1, new Position("o o ", 'o').bestMove());
}
#Test
public void testGameEnd() throws Exception {
assertFalse(new Position().gameEnd());
assertTrue(new Position("xxx ").gameEnd());
}
}
third class
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class Game {
Position position;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Java TTT");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(3, 3));
final Game game = new Game();
final JButton[] buttons = new JButton[9];
for (int i =0; i < 9; i++) {
final int idx = i;
final JButton button = new JButton();
buttons[i] = button;
button.setPreferredSize(new Dimension(100,100));
button.setBackground(Color.BLACK);
button.setOpaque(true);
button.setFont(new Font(null, Font.PLAIN, 100));
button.addMouseListener(new MouseListener() {
public void mouseReleased(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseClicked(MouseEvent e) {
button.setText("" + game.position.turn);
game.move(idx);
if (!game.position.gameEnd()){
int best = game.position.bestMove();
buttons[best].setText("" + game.position.turn);
game.move(best);
}
if (game.position.gameEnd()) {
String message = "";
if (game.position.win('x')) {
message = "You Won !!";
} else if (game.position.win('o')){
message = "Computer Won !!";
} else {
message = "Draw";
}
JOptionPane.showMessageDialog(null, message);
}
}});
frame.add(button);
}
frame.pack();
frame.setVisible(true);
}
});
}
protected void move(int idx) {
position = position.move(idx);
}
}
1- java.lang.AssertionError: array lengths differed, expected.length=6
actual.length=5
2-java.lang.AssertionError: expected:<0> but was:<100>

assertionsErrors within unit testcase runs are telling you that the actual result does not fit the expected one. thus your code does not work properly and you have to fix this.
please post the lines where these errors occurr.

Related

Recursion error in GUI

I am creating a simple 9x9 grid for Minesweeper. One of the primary functions of this game is to have a recursion to check all the sides when the tile clicked has no bombs surrounding it. In the code attached below, I have been able to create a function that checks the upper and left side of the tile. If I add more directions, such as lower and right side, the program will crash and will not properly display the tiles. (Check the method countBorders under the line //MY MAIN PROBLEM)
//displays the main GUI
package Minesweeper4;
public class mainFrame {
public static void main(String[] args) {
new Grid().setVisible(true);
}
}
// the main code
package Minesweeper4;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.*;
public class Grid extends JFrame implements ActionListener {
private JPanel mainGrid;
private JButton button1, button2;
private JButton[][] buttons = new JButton[9][9];
private String[][] mines = new String[9][9];
private ArrayList<ParentSquare> parentSquare = new ArrayList<ParentSquare>();
Random rand = new Random();
NumberSquare numberSquare = new NumberSquare();
MineSquare mineSquare = new MineSquare();
public void addMines() {
for (int j = 0; j < 9; j++) {
for (int k = 0; k < 9; k++) {
mines[j][k] = ".";
}
}
for (int i = 0; i < 3; i++) {
int temp_x = rand.nextInt(9);
int temp_y = rand.nextInt(9);
mines[temp_x][temp_y] = "x";
}
}
public void showMines() {
for (int x = 0; x < 9; x++) {
for (int y = 0; y < 9; y++) {
String temp = mines[x][y];
if (temp.equals("x")) {
System.out.println("X: " + (x + 1) + " Y: " + (y + 1) + " Value: " + temp);
}
}
}
}
public Grid() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(500, 500);
this.setTitle("Minesweeper 1.0");
mainGrid = new JPanel();
mainGrid.setLayout(new GridLayout(9, 9));
this.add(mainGrid);
button1 = new JButton("Boop");
button2 = new JButton("Poop");
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
buttons[i][j] = new JButton("");
buttons[i][j].addActionListener(this);
buttons[i][j].setBackground(Color.GRAY);
}
}
for (int k = 0; k < 9; k++) {
for (int l = 0; l < 9; l++) {
mainGrid.add(buttons[k][l]);
}
}
addMines();
showMines();
}
public void countBorders(int x, int y) {
int UL = 0, UU = 0, UR = 0, LL = 0, RR = 0, DL = 0, DD = 0, DR = 0, SUM = 0;
if (x > 0) {
UU = checkTile(x - 1, y);
}
if (y > 0) {
LL = checkTile(x, y - 1);
}
if (y < 8) {
RR = checkTile(x, y + 1);
}
if (x < 8) {
DD = checkTile(x + 1, y);
}
if ((x > 0) && (y > 0)) {
UL = checkTile(x - 1, y - 1);
}
if ((x > 0) && (y < 8)) {
UR = checkTile(x - 1, y + 1);
}
if ((x < 8) && (y > 0)) {
DL = checkTile(x + 1, y - 1);
}
if ((x < 8) && (y < 8)) {
DR = checkTile(x + 1, y + 1);
}
SUM = UL + UU + UR + LL + RR + DL + DD + DR;
printTile(x, y, SUM);
if (SUM == 0) { //MY MAIN PROBLEM
// if ((x > 0) && (y > 0)) {countBorders(x-1, y-1);} //Upper left
if (x > 0) {
countBorders(x - 1, y);
} //Upper
// if ((x > 0) && (y < 8)) {countBorders(x-1, y+1);} //Upper right
if (y > 0) {
countBorders(x, y - 1);
} //Left
// if (y < 8) {countBorders(x, y+1);} //Right
// if ((x < 8) && (y > 0)) {countBorders(x+1, y-1);} //Down Left
// if (x < 8) {countBorders(x+1, y);} //Down
// if ((x < 8) && (y < 8)) {countBorders(x+1, y+1);} //Down Right
}
}
public void printTile(int x, int y, int SUM) {
String text = Integer.toString(SUM);
buttons[x][y].setText(text);
buttons[x][y].setBackground(Color.CYAN);
}
public int checkTile(int x, int y) {
String c = mines[x][y];
if (c.equals("x")) {
return 1;
} else {
return 0;
}
}
public void click(int x, int y) {
String mine = mines[x][y];
if (mine.equals("x")) {
System.out.println("Bomb!!!");
buttons[x][y].setText("!");
buttons[x][y].setBackground(Color.RED);
} else {
countBorders(x, y);
System.out.println("Safe!!!");
// buttons[x][y].setText("√");
// buttons[x][y].setBackground(Color.WHITE);
}
}
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (e.getSource() == buttons[i][j]) {
System.out.println("Clicked Tile X: " + (i + 1) + " Y: " + (j + 1));
//buttons[i][j].setText("!");
click(i, j);
}
}
}
}
}
Is there a way on how to fix this recursion problem?
Thank you in advance and I'm really trying to learn Java. Have a nice day!
Your error-causing recursion has no stopping logic that I can find, and what you need to do is to somehow check to make sure that a cell hasn't already been counted or pressed before re-counting it. Otherwise the code risks throwing a stackoverflow error. This will require giving the cells being counted some state that would tell you this information, that would tell you if the cell has already been counted.
For an example of a successful program that does this logic, feel free to look at my Swing GUI example, one I created 5 years ago. In this code, I've got a class, MineCellModel, that provides the logic (not the GUI) for a single mine sweeper cell, and the class contains a boolean field, pressed, that is false until the cell is "pressed", either by the user pressing the equivalent button, or recursively in the model's logic. If the cell is pressed, if the boolean is true, the recursion stops with this cell.
You can find the code here: Minesweeper Action Events. It's an old program, and so I apologize for any concepts or code that may be off.
Running the code results in this:
Here's the code present in a single file:
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.SwingConstants;
import javax.swing.event.SwingPropertyChangeSupport;
#SuppressWarnings("serial")
public class MineSweeper {
private JPanel mainPanel = new JPanel();
private MineCellGrid mineCellGrid;
private JButton resetButton = new JButton("Reset");
public MineSweeper(int rows, int cols, int mineTotal) {
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
mineCellGrid = new MineCellGrid(rows, cols, mineTotal);
resetButton.setMnemonic(KeyEvent.VK_R);
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
mineCellGrid.reset();
}
});
mainPanel.add(mineCellGrid);
mainPanel.add(new JSeparator());
mainPanel.add(new JPanel() {
{
add(resetButton);
}
});
}
private JPanel getMainPanel() {
return mainPanel;
}
private static void createAndShowUI() {
JFrame frame = new JFrame("MineSweeper");
// frame.getContentPane().add(new MineSweeper(20, 20,
// 44).getMainPanel());
frame.getContentPane().add(new MineSweeper(12, 12, 13).getMainPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
#SuppressWarnings("serial")
class MineCellGrid extends JPanel {
private MineCellGridModel model;
private List<MineCell> mineCells = new ArrayList<MineCell>();
public MineCellGrid(final int maxRows, final int maxCols, int mineNumber) {
model = new MineCellGridModel(maxRows, maxCols, mineNumber);
setLayout(new GridLayout(maxRows, maxCols));
for (int row = 0; row < maxRows; row++) {
for (int col = 0; col < maxCols; col++) {
MineCell mineCell = new MineCell(row, col);
add(mineCell);
mineCells.add(mineCell);
model.add(mineCell.getModel(), row, col);
}
}
reset();
}
public void reset() {
model.reset();
for (MineCell mineCell : mineCells) {
mineCell.reset();
}
}
}
class MineCellGridModel {
private MineCellModel[][] cellModelGrid;
private List<Boolean> mineList = new ArrayList<Boolean>();
private CellModelPropertyChangeListener cellModelPropChangeListener = new CellModelPropertyChangeListener();
private int maxRows;
private int maxCols;
private int mineNumber;
private int buttonsRemaining;
public MineCellGridModel(final int maxRows, final int maxCols, int mineNumber) {
this.maxRows = maxRows;
this.maxCols = maxCols;
this.mineNumber = mineNumber;
for (int i = 0; i < maxRows * maxCols; i++) {
mineList.add((i < mineNumber) ? true : false);
}
cellModelGrid = new MineCellModel[maxRows][maxCols];
buttonsRemaining = (maxRows * maxCols) - mineNumber;
}
public void add(MineCellModel model, int row, int col) {
cellModelGrid[row][col] = model;
model.addPropertyChangeListener(cellModelPropChangeListener);
}
public void reset() {
buttonsRemaining = (maxRows * maxCols) - mineNumber;
// randomize the mine location
Collections.shuffle(mineList);
// reset the model grid and set mines
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
cellModelGrid[r][c].reset();
cellModelGrid[r][c].setMined(mineList.get(r * cellModelGrid[r].length + c));
}
}
// advance value property of all neighbors of a mined cell
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
if (cellModelGrid[r][c].isMined()) {
int rMin = Math.max(r - 1, 0);
int cMin = Math.max(c - 1, 0);
int rMax = Math.min(r + 1, cellModelGrid.length - 1);
int cMax = Math.min(c + 1, cellModelGrid[r].length - 1);
for (int row2 = rMin; row2 <= rMax; row2++) {
for (int col2 = cMin; col2 <= cMax; col2++) {
cellModelGrid[row2][col2].incrementValue();
}
}
}
}
}
}
private class CellModelPropertyChangeListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
MineCellModel model = (MineCellModel) evt.getSource();
int row = model.getRow();
int col = model.getCol();
if (evt.getPropertyName().equals(MineCellModel.BUTTON_PRESSED)) {
if (cellModelGrid[row][col].isMineBlown()) {
mineBlown();
} else {
buttonsRemaining--;
if (buttonsRemaining <= 0) {
JOptionPane.showMessageDialog(null, "You've Won!!!", "Congratulations",
JOptionPane.PLAIN_MESSAGE);
}
if (cellModelGrid[row][col].getValue() == 0) {
zeroValuePress(row, col);
}
}
}
}
private void mineBlown() {
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
MineCellModel model = cellModelGrid[r][c];
if (model.isMined()) {
model.setMineBlown(true);
}
}
}
}
private void zeroValuePress(int row, int col) {
int rMin = Math.max(row - 1, 0);
int cMin = Math.max(col - 1, 0);
int rMax = Math.min(row + 1, cellModelGrid.length - 1);
int cMax = Math.min(col + 1, cellModelGrid[row].length - 1);
for (int row2 = rMin; row2 <= rMax; row2++) {
for (int col2 = cMin; col2 <= cMax; col2++) {
cellModelGrid[row2][col2].pressedAction();
}
}
}
}
}
#SuppressWarnings("serial")
class MineCell extends JPanel {
private static final String LABEL = "label";
private static final String BUTTON = "button";
private static final int PS_WIDTH = 24;
private static final int PS_HEIGHT = PS_WIDTH;
private static final float LABEL_FONT_SIZE = (float) (24 * PS_WIDTH) / 30f;
private static final float BUTTON_FONT_SIZE = (float) (14 * PS_WIDTH) / 30f;
private JButton button = new JButton();
private JLabel label = new JLabel(" ", SwingConstants.CENTER);
private CardLayout cardLayout = new CardLayout();
private MineCellModel model;
public MineCell(final boolean mined, int row, int col) {
model = new MineCellModel(mined, row, col);
model.addPropertyChangeListener(new MyPCListener());
label.setFont(label.getFont().deriveFont(Font.BOLD, LABEL_FONT_SIZE));
button.setFont(button.getFont().deriveFont(Font.PLAIN, BUTTON_FONT_SIZE));
button.setMargin(new Insets(1, 1, 1, 1));
setLayout(cardLayout);
add(button, BUTTON);
add(label, LABEL);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
pressedAction();
}
});
button.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
model.upDateButtonFlag();
}
}
});
}
public MineCell(int row, int col) {
this(false, row, col);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PS_WIDTH, PS_HEIGHT);
}
public void pressedAction() {
if (model.isFlagged()) {
return;
}
model.pressedAction();
}
public void showCard(String cardConstant) {
cardLayout.show(this, cardConstant);
}
// TODO: have this change the button's icon
public void setFlag(boolean flag) {
if (flag) {
button.setBackground(Color.yellow);
button.setForeground(Color.red);
button.setText("f");
} else {
button.setBackground(null);
button.setForeground(null);
button.setText("");
}
}
private void setMineBlown(boolean mineBlown) {
if (mineBlown) {
label.setBackground(Color.red);
label.setOpaque(true);
showCard(LABEL);
} else {
label.setBackground(null);
}
}
public MineCellModel getModel() {
return model;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
model.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
model.removePropertyChangeListener(listener);
}
private class MyPCListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
String propName = evt.getPropertyName();
if (propName.equals(MineCellModel.MINE_BLOWN)) {
setMineBlown(true);
} else if (propName.equals(MineCellModel.FLAG_CHANGE)) {
setFlag(model.isFlagged());
} else if (propName.equals(MineCellModel.BUTTON_PRESSED)) {
if (model.isMineBlown()) {
setMineBlown(true);
} else {
String labelText = (model.getValue() == 0) ? "" : String.valueOf(model
.getValue());
label.setText(labelText);
}
showCard(LABEL);
}
}
}
public void reset() {
setFlag(false);
setMineBlown(false);
showCard(BUTTON);
label.setText("");
}
}
class MineCellModel {
public static final String FLAG_CHANGE = "Flag Change";
public static final String BUTTON_PRESSED = "Button Pressed";
public static final String MINE_BLOWN = "Mine Blown";
private int row;
private int col;
private int value = 0;
private boolean mined = false;;
private boolean flagged = false;
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
private boolean pressed = false;
private boolean mineBlown = false;
public MineCellModel(boolean mined, int row, int col) {
this.mined = mined;
this.row = row;
this.col = col;
}
public void incrementValue() {
int temp = value + 1;
setValue(temp);
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setMineBlown(boolean mineBlown) {
this.mineBlown = mineBlown;
PropertyChangeEvent evt = new PropertyChangeEvent(this, MINE_BLOWN, false, true);
pcSupport.firePropertyChange(evt);
}
public boolean isMineBlown() {
return mineBlown;
}
public void setMined(boolean mined) {
this.mined = mined;
}
public void setFlagged(boolean flagged) {
this.flagged = flagged;
}
public int getRow() {
return row;
}
public int getCol() {
return col;
}
public boolean isMined() {
return mined;
}
public boolean isFlagged() {
return flagged;
}
public void pressedAction() {
if (pressed) {
return;
}
pressed = true;
if (mined) {
setMineBlown(true);
}
PropertyChangeEvent evt = new PropertyChangeEvent(this, BUTTON_PRESSED, -1, value);
pcSupport.firePropertyChange(evt);
}
public void upDateButtonFlag() {
boolean oldValue = flagged;
setFlagged(!flagged);
PropertyChangeEvent evt = new PropertyChangeEvent(this, FLAG_CHANGE, oldValue, flagged);
pcSupport.firePropertyChange(evt);
}
public void reset() {
mined = false;
flagged = false;
pressed = false;
mineBlown = false;
value = 0;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
}
Edit Regarding Recursion
My code uses recursion, but with a level of indirection, since it is based on a Model-View-Controller type of design pattern, and the recursion is within the notification of listeners. Note that each GUI MineCell object holds its own MineCellModel object, the latter holds the MineCell's state. When a GUI JButton held within the MineCell object is pressed, its ActionListener calls the same class's pressed() method:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
pressedAction();
}
});
This method first checks the corresponding MineCellModel to see if it has been "flagged", if a boolean called flagged is true. If so, this means that the user has right-clicked on the button, and it is not active, and so the method returns. Otherwise the MineCellModel's pressedAction() method is called,
public void pressedAction() {
if (model.isFlagged()) {
return;
}
model.pressedAction();
}
and here is where the recursion starts, and it does so through an Observer Design Pattern:
// within MineCellModel
public void pressedAction() {
if (pressed) {
// if the button's already been pressed -- return, do nothing
return;
}
// otherwise make pressed true
pressed = true;
// if we've hit a mine -- blow it!
if (mined) {
setMineBlown(true);
}
// *** Here's the key *** notify all listeners that this button has been pressed
PropertyChangeEvent evt = new PropertyChangeEvent(this, BUTTON_PRESSED, -1, value);
pcSupport.firePropertyChange(evt);
}
The two lines of code on the bottom notify any listeners to this model that its BUTTON_PRESSED state has been changed, and it sends the MineCellModel's value to all listeners. The value int is key as its the number of neighbors that have mines. So what listens to the MineCellModel? Well, one key object is the MineCellGridModel, the model that represents the state of the entire grid. It has a CellModelPropertyChangeListener class that does the actual listening, and within this class is the following code:
private class CellModelPropertyChangeListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
// first get the MineCellModel for the cell that triggered this notification
MineCellModel model = (MineCellModel) evt.getSource();
int row = model.getRow();
int col = model.getCol();
// if the event is a button pressed event
if (evt.getPropertyName().equals(MineCellModel.BUTTON_PRESSED)) {
// first check if a mine was hit, and if so, call mineBlown()
if (cellModelGrid[row][col].isMineBlown()) {
mineBlown(); // this method iterates through all cells and blows all mines
} else {
// here we check for a winner
buttonsRemaining--;
if (buttonsRemaining <= 0) {
JOptionPane.showMessageDialog(null, "You've Won!!!", "Congratulations",
JOptionPane.PLAIN_MESSAGE);
}
// here is the key spot -- if cell's value is 0, call the zeroValuePress method
if (cellModelGrid[row][col].getValue() == 0) {
zeroValuePress(row, col);
}
}
}
}
private void mineBlown() {
// ... code to blow all the un-blown mines
}
// this code is called if a button pressed has 0 value -- no mine neighbors
private void zeroValuePress(int row, int col) {
// find the boundaries of the neighbors
int rMin = Math.max(row - 1, 0); // check for the top edge
int cMin = Math.max(col - 1, 0); // check for the left edge
int rMax = Math.min(row + 1, cellModelGrid.length - 1); // check for the bottom edge
int cMax = Math.min(col + 1, cellModelGrid[row].length - 1); // check for right edge
// iterate through the neighbors
for (int row2 = rMin; row2 <= rMax; row2++) {
for (int col2 = cMin; col2 <= cMax; col2++) {
// *** Here's the recursion ***
// call pressedAction on all the neighbors
cellModelGrid[row2][col2].pressedAction();
}
}
}
}
So the key method in the listener above is the zeroValuePress(...) method. It first finds the boundaries of the neighbors around the current mine cell, using Math.min(...) and Math.max(...) to be careful not to go beyond the right, left, or top or bottom boundaries of the grid. It then iterates through the cell neighbors calling pressedAction() on each one of the neighbors MineCellModels held by this grid. As you know from above, the pressedAction() method will check if the cell has already been pressed, and if not, changes its state, which then notifies this same listener, resulting in recursion.
One of the primary functions of this game is to have a recursion to check all the sides when the tile clicked has no bombs surrounding it.
Looks like you are stucked on the part where you need to update the cell with number according to the number of bombs surrounding it.
These are the things for you to take note:
To update the numbers on the cells, there is no need to use recursion. The only part I used recursion is when user clicks on a cell with value == 0(stepped on an empty grid).
Checking all 8 directions can be done easily without writing large number of if-conditions. All you need is a pair of nested for-loop. Just traverse the 3x3 grid like a 2D array (see diagram below for illustration).
In the loop, set conditions to ensure you are within bounds (of the 3x3 matrix) before reading current grid's value (see code below).
To traverse the 3x3 matrix as shown in the diagram, we can use a pair of nested loops:
for(int x=(coordX-1); x<=(coordX+1); x++)
for(int y=(coordY-1); y<=(coordY+1); y++)
if(x!=-1 && y!= -1 && x! = ROWS && y! = COLS && map[x][y] != 'B')
if(map[x][y] == '.')
map[x][y] = '1';
else
map[x][y] += 1;
The if-condition prevents working on array element which is out of bounds.

CheckTie function in Java Tic-tac-toe not functioning

So i'm having issues with getting my CheckTie method working, i've tried using boolean to get it working but it just announces that there's a tie when I press the first button. I do have a method that checks if the game board is full but it seems to be some issues when I try to have my view class implement it.
It shows the winners correctly atleast.
What am I doing wrong with the checkTie method?
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
public class Model extends Observable implements ModelInterface {
private int[][] board = new int[3][3];
private int player;
private List<Observer> observers;
private char winner;
private boolean tie;
public Model(){
player =1;
this.observers=new ArrayList<>();
reset();
}
public int [][] getBoard(){
return board;
}
#Override
public void movePlayer(String input) {
int tmp = Integer.parseInt(input);
int x = tmp %3;
int y = tmp /3;
updateBoard(x,y);
checkWin();
checkTie();
}
private void updateBoard(int x, int y) {
if ( board[x][y] == 0){
board[x][y] = player;
if (player == 1)
player = 2;
else
player = 1;
}
this.setChanged();
this.notifyObservers(this);
}
private void checkWin(){
if(board[0][0] != 0 && board[0][0] == board[1][1] && board[1][1] == board[2][2]){
winnerFound(board[0][0]);
}
else if(board[0][2] != 0 && board[0][2] == board[1][1] && board[1][1] == board[2][0]){
winnerFound(board[0][2]);
}
else{
for(int i = 0; i <3; i++){
if(board[i][0] != 0 && board[i][0] == board[i][1] && board[i][1] == board[i][2]){
winnerFound(board[i][0]);
break;
}
if(board[0][i] != 0 && board[0][i] == board[1][i] && board[1][i] == board[2][i]){
winnerFound(board[0][i]);
break;
}
}
}
}
private void winnerFound(int board){
this.winner= (char) board;
reset();
}
private boolean checkTie(){
boolean tie = true;
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
if(board[i][j] == 0)
{
tie = true;
}
}
}
return tie;
}
public int isThereAWinner() {
if (winner ==1)
return 1;
return winner;
}
public boolean isThereATie() {
if (tie = false)
return false;
else
return true;
}
#Override
public void register(Observer obj) {
if (obj == null) throw new NullPointerException();
if(!observers.contains(obj)) observers.add(obj);
}
private void reset() {
// for(JButton label : board){
// label.setText("");
// }
// panel.repaint();
setChanged();
this.notifyObservers();
}
#Override
public void unregister(Observer obj) {
}
#Override
public Object getUpdate(Observer obj) {
return null;
}
}
And here's the view class:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
#SuppressWarnings("serial")
public class View extends JFrame implements ViewInterface, Observer {
Controller controller;
JPanel panel;
ArrayList<JButton> board = new ArrayList();
JPanel messagePanel;
JLabel topText;
JPanel sidePanel;
JPanel westPanel;
JTextField Spelare;
JButton LäggTill, Exit;
JButton test;
JList lista;
DefaultListModel model; //Lista för spelare
//private String letter = " ";
// private int count = 0;
// private char winner;
public View(Controller controller){
super();
this.controller = controller;
setupUI();
}
private void setupUI(){
setupFrame();
setupMessagePanel();
setupPanel();
setupBoard();
setupPlayers();
setupLäggTill();
this.getContentPane().add(panel);
}
private void setupFrame(){
setSize(400,400);
setTitle("Tic-Tac-Toe");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new BorderLayout());
}
private void setupMessagePanel(){
messagePanel = new JPanel();
topText = new JLabel("X startar");
messagePanel.add(topText);
this.getContentPane().add(messagePanel, BorderLayout.SOUTH);
}
private void setupPlayers(){
sidePanel = new JPanel();
westPanel = new JPanel();
Spelare = new JTextField("Skriv ditt namn", 9);
Spelare.addActionListener(controller);
model = new DefaultListModel(); //DefaultListModel för att lägga till personer
lista = new JList(model);
lista.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
lista.setLayoutOrientation(JList.VERTICAL);
lista.setVisibleRowCount(7);
lista.setPreferredSize(new Dimension(50,200));
sidePanel.add(Spelare);
westPanel.add(lista);
this.getContentPane().add(sidePanel, BorderLayout.NORTH);
this.getContentPane().add(westPanel, BorderLayout.WEST);
}
private void setupLäggTill()
{
LäggTill = new JButton("Lägg till");
Exit = new JButton("Exit");
LäggTill.setActionCommand("Lägg till");
LäggTill.addActionListener(controller);
Exit.setActionCommand("Exit");
Exit.addActionListener(controller);
sidePanel.add(LäggTill);
messagePanel.add(Exit);
this.getContentPane().add(sidePanel, BorderLayout.NORTH);
}
private void setupPanel(){
panel = new JPanel();
panel.setLayout(new GridLayout(3, 3, -1, -1));
}
private void setupBoard(){
for(int i = 0; i < 9; i++){
JButton symbol = new JButton();
symbol.setText("");
symbol.setSize(new Dimension(400/3,400/3));
symbol.setHorizontalAlignment(JLabel.CENTER);
symbol.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2,Color.RED));
symbol.addActionListener(controller);
symbol.setActionCommand(String.valueOf(i));
board.add(symbol);
panel.add(symbol);
}
}
#Override
public void gameTie() {
giveMessage("Oavgjort", "Otur, ingen vann");
reset();
}
#Override
public void gameWon(char winner) {
giveMessage("Spel klart", winner + " vann!");
reset();
}
private void giveMessage(String header, String message){
JOptionPane.showMessageDialog(this,
message,
header,
JOptionPane.PLAIN_MESSAGE);
}
private void reset() {
for(JButton label : board){
label.setText("");
}
panel.repaint();
}
public void update(Observable o, Object arg) {
Model model_copy = (Model)o;
int[][] test = model_copy.getBoard();
int winner = model_copy.isThereAWinner();
boolean tie = model_copy.isThereATie();
int index = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if(test[j][i] == 1)
{
this.board.get(index).setText("X");
}
else if (test[j][i] == 2)
{
this.board.get(index).setText("O");
}
// else if(test[j][i]==3)
// {
// this.board.get(index).setEnabled(false);
// }
index ++;
}
}
if (winner ==1)
{
giveMessage("Spel klart", "X" + " vann!");
reset();
}
else if (winner ==2)
{
giveMessage("Spel klart", "O" + " vann!");
reset();
}
else if (tie ==false)
{
giveMessage("Oavgjort", "Otur, ingen vann");
}
}
}
Your condition must be the following. Otherwise, there is always a tie since you're always returning true. If we still have a cell with 0, it means the game is not over yet and it can't be a tie.
if(board[i][j] == 0) {
tie = false;
}
private boolean checkTie(){
boolean tie = true;
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
if(board[i][j] == 0) {
tie = false;
}
}
}
return tie;
}

Hello I am creating a TicTacToe game for myself to understand Java better

however I am not sure where I am supposed to enter the whoWins() method. Do I enter this method in the actionperformed Method of the buttons or do i need to something different. Please help.
public class TTT extends JFrame implements ActionListener {
private JButton buttons[] = new JButton[9];
private JButton exitButton;
public JLabel title;
public JPanel titlePanel, panel;
private int count = 0;
int symbolCount = 0;
private boolean win = false;
public TTT() {
title = new JLabel("Welcome to my Tic Tac Toe Game!");
titlePanel = new JPanel();
title.setFont(new Font(Font.SERIF, 0, 30));
titlePanel.add(title);
this.add(titlePanel, BorderLayout.NORTH);
panel = new JPanel(new GridLayout(3, 3));
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new JButton();
panel.add(buttons[i]);
buttons[i].setEnabled(true);
buttons[i].addActionListener(this);
}
this.add(panel, BorderLayout.CENTER);
JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.CENTER));
exitButton = new JButton("Quit");
panel1.add(exitButton);
this.add(panel1, BorderLayout.SOUTH);
exitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(WIDTH);
}
});
}
public void whoWins() {
//Determines who wins using for the horizontal rows.
if (buttons[0].getText() == buttons[1].getText() && buttons[1].getText() == buttons[2].getText() && buttons[0].getText() != "") {
win = true;
} else if (buttons[3].getText() == buttons[4].getText() && buttons[4].getText() == buttons[5].getText() && buttons[3].getText() != "") {
win = true;
} else if (buttons[6].getText() == buttons[7].getText() && buttons[7].getText() == buttons[8].getText() && buttons[6].getText() != "") {
win = true;
} //Determines the verticles wins
else if (buttons[0].getText() == buttons[3].getText() && buttons[3].getText() == buttons[6].getText() && buttons[0].getText() != "") {
win = true;
} else if (buttons[1].getText() == buttons[4].getText() && buttons[4].getText() == buttons[7].getText() && buttons[1].getText() != "") {
win = true;
} else if (buttons[2].getText() == buttons[5].getText() && buttons[5].getText() == buttons[8].getText() && buttons[2].getText() != "") {
win = true;
}
// Diagnol Wins
else if (buttons[0].getText()==buttons[4].getText()&&buttons[4].getText()==buttons[8].getText()&& buttons[0].getText()!= "") {
win = true;
}else if (buttons[2].getText()==buttons[4].getText()&&buttons[4].getText()==buttons[6].getText()&& buttons[1].getText()!= "") {
win = true;
}else {
win = false;
}
//who won
if (win = true) {
JOptionPane.showMessageDialog(null, "wins");
}else if (count == 9 && win == false) {
JOptionPane.showMessageDialog(null, "Tie game");
}
}
public static void main(String[] args) {
TTT ref1 = new TTT();
ref1.setTitle("Tic Tac Toe");
ref1.setVisible(true);
ref1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ref1.setSize(500, 500);
ref1.setLocationRelativeTo(null);
// ref1.whoWins();
}
#Override
public void actionPerformed(ActionEvent e) {
count++;
for (JButton button : buttons) {
if (button == e.getSource()) {
if (symbolCount % 2 == 0) {
button.setText("X");
button.setEnabled(false);
} else {
button.setText("O");
button.setEnabled(false);
}
}
}
if (count >= buttons.length) {
JOptionPane.showMessageDialog(null, "End");
}
symbolCount++;
}
}
If you really want to do this right, then I suggest making some big changes, some M-V-C type changes:
First and foremost, separate out the logic of the game from the game GUI. This would mean that the code that determines who wins should not be in any code that contains GUI type code. This will be your "model"
Next you should never have GUI code implement listener interfaces, so try to get that out of the GUI and possibly have it go into its own class, the "Control" class.
Finally the GUI or "View" class will concern itself with displaying the model's state and getting input from the user and transmitting this input to the control.
For example,...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.EnumMap;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;
public class TicTacToeMain {
private static void createAndShowGui() {
TttView view = null;
try {
view = new TttView();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
TttModel model = new TttModel();
new TttControl(model, view);
JFrame frame = new JFrame("Tic Tac Toe");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(view.getMainPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
enum TttPiece {
EMPTY, X, O
}
class TttView {
public static final String IMAGE = "/imgFolder/TicTacToe.png";
private static final int GAP = 5;
private JPanel mainPanel = new JPanel();
private JPanel tttPanel = new JPanel();
private Map<TttPiece, Icon> iconMap = new EnumMap<>(TttPiece.class);
private JLabel[][] grid = new JLabel[TttModel.ROWS][TttModel.COLS];
private TttControl control;
public TttView() throws IOException {
BufferedImage img = ImageIO.read(getClass().getResourceAsStream(IMAGE));
Icon[] imgIcons = splitImg(img);
iconMap.put(TttPiece.X, imgIcons[0]);
iconMap.put(TttPiece.O, imgIcons[1]);
iconMap.put(TttPiece.EMPTY, createEmptyIcon(imgIcons[0]));
tttPanel.setLayout(new GridLayout(grid.length, grid[0].length, GAP, GAP));
tttPanel.setBackground(Color.black);
MyMouseAdapter mouseAdapter = new MyMouseAdapter();
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[row].length; col++) {
grid[row][col] = new JLabel(iconMap.get(TttPiece.EMPTY));
grid[row][col].setOpaque(true);
grid[row][col].setBackground(Color.LIGHT_GRAY);
grid[row][col].addMouseListener(mouseAdapter);
tttPanel.add(grid[row][col]);
}
}
JPanel btnPanel = new JPanel(new GridLayout(1, 0, 5, 0));
btnPanel.add(new JButton(new ClearAction("Clear", KeyEvent.VK_C)));
btnPanel.add(new JButton(new ExitAction("Exit", KeyEvent.VK_X)));
int blGap = 2;
mainPanel.setLayout(new BorderLayout(blGap, blGap));
mainPanel.setBorder(BorderFactory.createEmptyBorder(blGap, blGap, blGap,
blGap));
mainPanel.add(tttPanel, BorderLayout.CENTER);
mainPanel.add(btnPanel, BorderLayout.SOUTH);
}
public void setControl(TttControl control) {
this.control = control;
}
public JComponent getMainPanel() {
return mainPanel;
}
private Icon createEmptyIcon(Icon icon) {
int width = icon.getIconWidth();
int height = icon.getIconHeight();
BufferedImage img = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
return new ImageIcon(img);
}
private Icon[] splitImg(BufferedImage img) {
int w = img.getWidth();
int h = img.getHeight();
int gap = 5;
Icon[] icons = new ImageIcon[2];
icons[0] = new ImageIcon(img.getSubimage(0, 0, w / 2 - gap, h / 2 - gap));
icons[1] = new ImageIcon(img.getSubimage(w / 2 + gap, 0, w / 2 - gap, h
/ 2 - gap));
return icons;
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
if (control == null) {
return;
}
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[row].length; col++) {
if (grid[row][col] == e.getSource()) {
control.gridPress(row, col);
}
}
}
}
}
private class ClearAction extends AbstractAction {
public ClearAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent evt) {
if (control != null) {
control.clear();
}
}
}
private class ExitAction extends AbstractAction {
public ExitAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent evt) {
if (control != null) {
control.exit(evt);
}
}
}
public void setGridIcon(int row, int col, TttPiece tttPiece) {
grid[row][col].setIcon(iconMap.get(tttPiece));
}
}
class TttControl {
private TttModel model;
private TttView view;
public TttControl(TttModel model, TttView view) {
this.model = model;
this.view = view;
view.setControl(this);
model.addPropertyChangeListener(new ModelListener());
}
public void exit(ActionEvent evt) {
Window win = SwingUtilities
.getWindowAncestor((Component) evt.getSource());
win.dispose();
}
public void gridPress(int row, int col) {
try {
model.gridPress(row, col);
} catch (TttException e) {
// TODO: notify user
// e.printStackTrace();
}
}
public void clear() {
model.clear();
}
private class ModelListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (TttModel.GRID_POSITION.equals(evt.getPropertyName())) {
TttPiece[][] tttGrid = model.getTttGrid();
for (int row = 0; row < tttGrid.length; row++) {
for (int col = 0; col < tttGrid[row].length; col++) {
view.setGridIcon(row, col, tttGrid[row][col]);
}
}
}
}
}
}
class TttModel {
public static final int ROWS = 3;
public static final int COLS = ROWS;
public static final String GRID_POSITION = "grid position";
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
this);
private TttPiece[][] tttGrid = new TttPiece[ROWS][COLS];
private TttPiece player = TttPiece.X;
private boolean gameOver;
public TttModel() {
clear();
}
public void setGridPosition(int row, int col, TttPiece piece)
throws TttException {
if (gameOver) {
return;
}
if (tttGrid[row][col] == TttPiece.EMPTY) {
tttGrid[row][col] = piece;
checkForWin(row, col, piece);
nextPlayer();
pcSupport.firePropertyChange(GRID_POSITION, null, tttGrid);
} else {
String message = "Invalid setGridPosition for row: %d, col: %d, piece: %s. "
+ "Spot already occupied by piece: %s";
message = String.format(message, row, col, piece, tttGrid[row][col]);
throw new TttException(message);
}
}
public TttPiece[][] getTttGrid() {
return tttGrid;
}
public void gridPress(int row, int col) throws TttException {
setGridPosition(row, col, player);
}
public void nextPlayer() {
player = player == TttPiece.X ? TttPiece.O : TttPiece.X;
}
private void checkForWin(int row, int col, TttPiece piece) {
// TODO finish
}
public void clear() {
for (int row = 0; row < tttGrid.length; row++) {
for (int col = 0; col < tttGrid[row].length; col++) {
tttGrid[row][col] = TttPiece.EMPTY;
}
}
player = TttPiece.X;
pcSupport.firePropertyChange(GRID_POSITION, null, tttGrid);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
}
#SuppressWarnings("serial")
class TttException extends Exception {
public TttException() {
super();
}
public TttException(String message) {
super(message);
}
}
Using for my images:
With GUI looking like:
I am also interested in writing a Tic Tac Toe game, so I copied your code, and did a little modification, and it passed test, check following:
package eric.j2se.swing;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
/**
* <p>
* Simple game of Tic Tac Toe.
* </p>
*
* #author eric
* #date Apr 16, 2014 11:03:48 AM
*/
#SuppressWarnings("serial")
public class TicTacToe extends JFrame implements ActionListener {
// 2 players
public static final char playerX = 'X';
public static final char playerO = 'O';
// null player
public static final char playerN = 'N';
// the winer, init to null player
private Character winner = playerN;
// indicate whether game over
private boolean gameOver = false;
// count of button used,
private int count = 0;
private Character buttonPlayers[] = new Character[9];
private JButton buttons[] = new JButton[9];
private JButton exitButton;
public JLabel title;
public JPanel titlePanel, panel;
public TicTacToe() {
// init buttonPlayers
for (int i = 0; i < 9; i++) {
buttonPlayers[i] = playerN;
}
// init title
title = new JLabel("Welcome to Tic Tac Toe!");
titlePanel = new JPanel();
title.setFont(new Font(Font.SERIF, 0, 30));
titlePanel.add(title);
this.add(titlePanel, BorderLayout.NORTH);
// init 9 button
panel = new JPanel(new GridLayout(3, 3));
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new JButton();
panel.add(buttons[i]);
buttons[i].setEnabled(true);
buttons[i].addActionListener(this);
}
// init exit button
this.add(panel, BorderLayout.CENTER);
JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.CENTER));
exitButton = new JButton("Quit");
panel1.add(exitButton);
this.add(panel1, BorderLayout.SOUTH);
exitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(WIDTH);
}
});
}
public void whoWins() {
// determine winner - horizontal rows
if (!gameOver) {
for (int i = 0; i < 3; i++) {
if ((buttonPlayers[0 + i * 3] != playerN) && (buttonPlayers[0 + i * 3].equals(buttonPlayers[1 + i * 3]))
&& buttonPlayers[1 + i * 3].equals(buttonPlayers[2 + i * 3])) {
winner = buttonPlayers[0 + i * 3];
gameOver = true;
break;
}
}
}
// determine winner - vertical rows
if (!gameOver) {
for (int i = 0; i < 3; i++) {
if ((buttonPlayers[i + 0 * 3] != playerN) && (buttonPlayers[i + 0 * 3].equals(buttonPlayers[i + 1 * 3]))
&& buttonPlayers[i + 1 * 3].equals(buttonPlayers[i + 2 * 3])) {
winner = buttonPlayers[i + 0 * 3];
gameOver = true;
break;
}
}
}
// determine winner - diagonal rows
if (!gameOver) {
int winButtonIndex = -1;
if ((buttonPlayers[0] != playerN) && (buttonPlayers[0].equals(buttonPlayers[4])) && buttonPlayers[4].equals(buttonPlayers[8])) {
winButtonIndex = 0;
} else if ((buttonPlayers[2] != playerN) && (buttonPlayers[2].equals(buttonPlayers[4])) && buttonPlayers[4].equals(buttonPlayers[6])) {
winButtonIndex = 2;
}
if (winButtonIndex >= 0) {
winner = buttonPlayers[winButtonIndex];
gameOver = true;
}
}
// full
if (count == 9) {
gameOver = true;
}
if (gameOver) {
String tip = "";
switch (winner) {
case playerO:
tip = "Player O win!";
break;
case playerX:
tip = "Player X win!";
break;
default:
tip = "Draw game!";
break;
}
JOptionPane.showMessageDialog(null, tip);
}
}
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < buttons.length; i++) {
JButton button = buttons[i];
if (button == e.getSource()) {
Character currentPlayer = (count % 2 == 1 ? playerX : playerO);
button.setText(String.valueOf(currentPlayer));
buttonPlayers[i] = currentPlayer;
button.setEnabled(false);
break;
}
}
count++;
whoWins();
}
public static void main(String[] args) {
TicTacToe ref1 = new TicTacToe();
ref1.setTitle("Tic Tac Toe");
ref1.setVisible(true);
ref1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ref1.setSize(500, 500);
ref1.setLocationRelativeTo(null);
}
}
about when to call the win check:
check each time you click 1 of the 9 buttons,
about the flag:
I use 2 flag instead of 1 flag to indicate game over & winner, because in TTT game, draw game is very usual, after play several times, you always get draw game ...
a little suggestion to your code:
when compare string, use equals(), not ==,
define const values in variable, not write it in logic, e.g. 'O' 'X',
don't repeat code, try use logic control to make it short & easy to read & easy to maintain,

Applet does not load on html page

I have this applet and i cant figure out why it doesnt load on html page.I have added full permissions in java.policy file. I use the default html file from NetBeans Applet's output.
/* Hearts Cards Game with AI*/
import java.applet.Applet;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Random;
import javax.swing.JOptionPane;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.awt.Graphics;
import java.awt.Image;
import java.security.AccessController;
import javax.swing.ImageIcon;
import javax.swing.*;
import javax.swing.JPanel;
public class Game extends JApplet implements MouseListener, Runnable {
int initNoCards = 13;
int width, height;
boolean endGame = false;
int turn = -1;
int firstCard = 0;
int firstTrick = 0;
String leadingSuit = null;
Cards leadingCard = null;
Cards playCard = null;
String startCard = "c2";
Cards[] trickCards = new Cards[4];
ArrayList<Cards>[] playerCards = new ArrayList[4];
ArrayList<Cards>[] takenCards = new ArrayList[4];
boolean heartsBroken = false;
ArrayList<Cards> cards = new ArrayList<Cards>();
String[] hearts = {"h2", "h3", "h4", "h5", "h6", "h7", "h8", "h9", "h10", "h12", "h13", "h14", "h15"};
String queen = "s13";
int cardHeight = 76;
int cardWidth = 48;
ArrayList<Rectangle> rectangles = new ArrayList<Rectangle>();
int selectedCard = -1;
//set the background image
Image backImage = new ImageIcon("deck\\back2.png").getImage();
public void GetDataFromXML() {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler() {
boolean name = false;
boolean image = false;
#Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if (qName.equalsIgnoreCase("NAME")) {
name = true;
}
if (qName.equalsIgnoreCase("IMAGE")) {
image = true;
}
}
#Override
public void endElement(String uri, String localName,
String qName) throws SAXException {
}
#Override
public void characters(char ch[], int start, int length) throws SAXException {
String s = new String(ch, start, length);
if (name) {
cards.add(new Cards(s));
name = false;
}
if (image) {
image = false;
}
}
};
saxParser.parse("deck\\deck.xml", handler);
} catch (Exception e) {
}
}
//function for comparing cards from same suite
public boolean lowerThan(Cards c1, Cards c2) {
int a, b;
a = Integer.parseInt(c1.getName().substring(1));
b = Integer.parseInt(c2.getName().substring(1));
return a < b;
}
//checks if a card is valid to play
public boolean ValidMove(Cards c) {
if (firstCard == 0) {
if (c.getName().equals(startCard)) {
firstCard = 1;
return true;
}
return false;
}
boolean result = playerCards[turn].indexOf(c) >= 0;
if (leadingSuit == null) {
return result;
}
boolean found = false;
for (int i = 0; i < playerCards[turn].size(); i++) {
if (playerCards[turn].get(i).getName().charAt(0) == leadingSuit.charAt(0)) {
found = true;
break;
}
}
if (!found) {
boolean justHearts = true;
for (int i = 0; i < playerCards[turn].size(); i++) {
if (playerCards[turn].get(i).getName().charAt(0) != 'h') {
justHearts = false;
break;
}
}
if (firstTrick == 0) {
if (c.getName().equals(queen)) {
return false;
}
if (!justHearts && c.getName().charAt(0) == 'h') {
return false;
}
} else {
if (c.getName().charAt(0) == 'h' && leadingSuit == null && !heartsBroken && !justHearts) {
return false;
}
}
} else {
if (c.getName().charAt(0) != leadingSuit.charAt(0)) {
return false;
}
}
return result;
}
#Override
public void init() {
GetDataFromXML();
setSize(500, 500);
width = super.getSize().width;
height = super.getSize().height;
setBackground(Color.white);
addMouseListener(this);
for (int i = 0; i < cards.size(); i++) {
System.out.println(cards.get(i).getName());
System.out.println(cards.get(i).getImage());
}
Shuffle();
}
public int GetTrickCount() {
int count = 0;
for (int i = 0; i < trickCards.length; i++) {
if (trickCards[i] != null) {
count++;
}
}
return count;
}
public void ResetTrick() {
for (int i = 0; i < trickCards.length; i++) {
trickCards[i] = null;
}
}
#Override
public void run() {
try {
PlayTurn();
} catch (InterruptedException ex) {
}
}
public void start() {
Thread th = new Thread(this);
th.start();
}
//function for shuffling cards and painting players cards
public void Shuffle() {
for (int i = 0; i < 4; i++) {
playerCards[i] = new ArrayList<Cards>();
takenCards[i] = new ArrayList<Cards>();
}
ArrayList<Cards> list = new ArrayList<Cards>();
list.addAll(cards);
Collections.shuffle(list);
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i).getName() + " ");
}
//initializare liste carti
for (int i = 0; i < 4; i++) {
playerCards[i] = new ArrayList<Cards>();
takenCards[i] = new ArrayList<Cards>();
for (int j = 0; j < initNoCards; j++) {
playerCards[i].add((list.get(j + i * initNoCards)));
if (list.get(j + i * initNoCards).getName().equals(startCard)) {
turn = i;
}
}
Collections.sort(playerCards[i], c);
ShowCards(i);
}
for (int i = 0; i < playerCards[0].size() - 1; i++) {
rectangles.add(new Rectangle((141 + 1) + 13 * i - 2, 350 + 1, 13 - 2, cardHeight - 1));
}
rectangles.add(new Rectangle((141 + 1) + 13 * 12 - 2, 350 + 1, cardWidth, cardHeight - 1));
ShowPlayersCards();
}
Comparator<Cards> c = new Comparator<Cards>() {
#Override
public int compare(Cards o1, Cards o2) {
if (o2.getName().charAt(0) != o1.getName().charAt(0)) {
return o2.getName().charAt(0) - o1.getName().charAt(0);
} else {
int a, b;
a = Integer.parseInt(o1.getName().substring(1));
b = Integer.parseInt(o2.getName().substring(1));
return a - b;
}
}
};
public void PlayTurn() throws InterruptedException {
endGame = true;
System.out.println("Its " + turn);
for (int i = 0; i < 4; i++) {
if (!playerCards[i].isEmpty()) {
endGame = false;
}
}
if (endGame) {
System.out.println("Game over!");
GetPlayersScore();
return;
}
if (turn != 0) {
Random r = new Random();
int k = r.nextInt(playerCards[turn].size());
Cards AIcard = playerCards[turn].get(k);
while (!ValidMove(AIcard)) {
k = r.nextInt(playerCards[turn].size());
AIcard = playerCards[turn].get(k);
}
leadingCard = AIcard;
playCard = AIcard;
} else {
System.out.println("\nIt is player's (" + turn + ") turn");
System.out.println("Player (" + turn + ") enter card to play:");
leadingCard = null;
playCard = null;//new Cards(read);
while (true) {
if (playCard != null) {
break;
}
Thread.sleep(50);
}
}
repaint();
Thread.sleep(1000);
repaint();
if (playCard.getName().charAt(0) == 'h') {
heartsBroken = true;
}
playerCards[turn].remove(playCard);
trickCards[turn] = playCard;
if (GetTrickCount() == 1)//setez leading suit doar pentru trickCards[0]
{
leadingSuit = GetSuit(playCard);
}
System.out.println("Leading suit " + leadingSuit);
System.out.println("Player (" + turn + ") chose card " + playCard.getName() + " to play");
ShowTrickCards();
ShowPlayersCards();
if (GetTrickCount() < 4) {
turn = (turn + 1) % 4;
} else {
turn = GetTrickWinner();
leadingSuit = null;
firstTrick = 1;
playCard = null;
repaint();
}
PlayTurn();
}
public void ShowTrickCards() {
System.out.println("Cards in this trick are:");
for (int i = 0; i < 4; i++) {
if (trickCards[i] != null) {
System.out.print(trickCards[i].getName() + " ");
}
}
}
public String GetSuit(Cards c) {
if (c.getName().contains("c")) {
return "c";
}
if (c.getName().contains("s")) {
return "s";
}
if (c.getName().contains("h")) {
return "h";
}
if (c.getName().contains("d")) {
return "d";
}
return null;
}
public String GetValue(Cards c) {
String get = null;
get = c.getName().substring(1);
return get;
}
public int GetTrickWinner() {
int poz = 0;
for (int i = 1; i < 4; i++) {
if (trickCards[poz].getName().charAt(0) == trickCards[i].getName().charAt(0) && lowerThan(trickCards[poz], trickCards[i]) == true) {
poz = i;
}
}
System.out.println("\nPlayer (" + poz + ") won last trick with card " + trickCards[poz].getName());
ResetTrick();
return poz;
}
public void ShowPlayersCards() {
ShowCards(0);
ShowCards(1);
ShowCards(2);
ShowCards(3);
}
public void GetPlayersScore() {
GetScore(0);
GetScore(1);
GetScore(2);
GetScore(3);
}
public void ShowCards(int player) {
System.out.print("\nPlayer (" + player + ") cards: ");
for (int i = 0; i < playerCards[player].size(); i++) {
System.out.print(playerCards[player].get(i).getName() + " ");
}
System.out.println();
}
public int GetScore(int player) {
int score = 0;
for (int i = 0; i < takenCards[player].size(); i++) {
for (int j = 0; j < hearts.length; j++) {
if (takenCards[player].get(i).getName().equals(hearts[j])) {
score++;
break;
}
}
if (takenCards[player].get(i).getName().equals(queen)) {
score += 13;
}
}
return score;
}
#Override
public void paint(Graphics g) {
g.drawImage(backImage, 0, 0, getWidth(), getHeight(), this);
for (int i = 0; i < playerCards[0].size(); i++) {
if (selectedCard == i) {
g.drawImage(playerCards[0].get(i).getImage(), 141 + i * 13, 340, null);
} else {
g.drawImage(playerCards[0].get(i).getImage(), 141 + i * 13, 350, null);
}
if (trickCards[0] != null) {
g.drawImage(trickCards[0].getImage(), 225, 250, 48, 76, null);
}
if (trickCards[1] != null) {
g.drawImage(trickCards[1].getImage(), 177, 174, 48, 76, null);
}
if (trickCards[2] != null) {
g.drawImage(trickCards[2].getImage(), 225, 98, 48, 76, null);
}
if (trickCards[3] != null) {
g.drawImage(trickCards[3].getImage(), 273, 174, 48, 76, null);
}
}
}
#Override
public void mouseClicked(MouseEvent e) {
if (turn != 0) {
return;
}
for (int i = 0; i < rectangles.size(); i++) {
if (rectangles.get(i).contains(e.getPoint())) {
if (i == selectedCard) {
if (ValidMove(playerCards[0].get(i))) {
selectedCard = -1;
rectangles.get(rectangles.size() - 2).width = rectangles.get(rectangles.size() - 1).width;
playCard = playerCards[0].get(i);
leadingCard = playCard;
rectangles.remove(rectangles.size() - 1);
trickCards[0] = playerCards[0].remove(i);
} else {
if (firstCard == 0) {
JOptionPane.showMessageDialog(this, "You have to play 2 of clubs!");
}
}
} else {
selectedCard = i;
rectangles.get(i).y -= 10;
}
repaint();
break;
}
}
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
class Cards extends JPanel {
private String name;
private String image;
private Image img;
public Cards(String name) {
super();
this.name = name;
this.image = "deck\\" + name + ".png";
this.img = new ImageIcon(image).getImage();
}
public Cards() {
super();
this.name = null;
this.image = null;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Image getImage() {
return img;
}
public void setImage(String image) {
this.image = image;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Cards)) {
return false;
}
Cards c = (Cards) obj;
return name.equals(c.getName()) && image.equals(c.getImage());
}
#Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + (this.name != null ? this.name.hashCode() : 0);
hash = 31 * hash + (this.image != null ? this.image.hashCode() : 0);
return hash;
}
#Override
public void paint(Graphics g) {
g.drawImage(img, WIDTH, HEIGHT, this);
}
public boolean lowerThan(Cards c1, Cards c2) {
int a, b;
a = Integer.parseInt(c1.getName().substring(1));
b = Integer.parseInt(c2.getName().substring(1));
return a < b;
}
public int compareTo(Cards c) {
if (c.getName().charAt(0) != name.charAt(0)) {
return c.getName().charAt(0) - name.charAt(0);
} else {
int a, b;
a = Integer.parseInt(name.substring(1));
b = Integer.parseInt(c.getName().substring(1));
return a - b;
}
}
}
HTML
<HTML>
<HEAD>
<TITLE>Applet HTML Page</TITLE>
</HEAD>
<BODY>
<H3><HR WIDTH="100%">Applet HTML Page<HR WIDTH="100%"></H3>
<P>
<APPLET codebase="classes" code="Game.class" width=350 height=200></APPLET>
</P>
<HR WIDTH="100%"><FONT SIZE=-1><I>Generated by NetBeans IDE</I></FONT>
</BODY>
</HTML>
Image backImage = new ImageIcon("deck\\back2.png").getImage();
If I am the user of the applet when it is on the internet, the will cause the JRE to search for a File relative to the current user directory on my PC, either that or the cache of FF. In either case, it will not locate an image by the name of back2.png.
For fear of sounding like a looping Clip:
Resources intended for an applet (icons, BG image, help files etc.) should be accessed by URL.
An applet will not need trust to access those resources, so long as the resources are on the run-time class-path, or on the same server as the code base or document base.
Further
I have added full permissions in java.policy file.
This is pointless. It will not be workable at time of deployment unless you control every machine it is intended to run on. If an applet needs trust in a general environment, it needs to be digitally signed. You might as well sign it while building the app.
cant figure out why it doesnt load on html page.
Something that would assist greatly is to configure the Java Console to open when an applet is loaded. There is a setting in the last tab of the Java Control Panel that configures it.

JTextField that has inner fields or preformated format, something like the ip field in windows

I want to create a text field that will be for dates and will have dd.mm.YYYY format. Now what I want the user to type only the numbers, not the dots to. So the field would be like:
_ _. _ _ . _ _ _ _
So when the user wants to type the date: 15.05.2010 for example, he will only type the numbers in the sequence 15052010.
Also I would like, when he presses on left or right arrow, the cursor to go from one field (not JTextField, but field in the JTextField) to the next. So lets say I have JTextField with this text in it: 15.05.2010 If the user is on the beginning and he presses the right arrow, the cursor should go to the .05 field.
I hope you understand me because right now I don't have any idea how to make this, or at least how to look for it on google.
Well, here are 4 classes that solve your problem.
In my case its version control but IP address has the same structure and its easy to modify it.
package com.demo.textfield.version;
import javax.swing.text.Document;
/**
* create documents for text fields
*/
public class DocumentsFactory {
private DocumentsFactory() {}
public static Document createIntDocument() {
return createIntDocument(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
public static Document createIntDocument(int maxValue) {
return createIntDocument(maxValue, Integer.MAX_VALUE);
}
public static Document createIntDocument(int maxValue, int maxLength) {
IntDocument intDocument = new IntDocument();
intDocument.setMaxVal(maxValue);
intDocument.setMaxLength(maxLength);
return intDocument;
}
}
in the followed class we define view:
package com.demo.textfield.version;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JPanel;
public class GridbagPanel extends JPanel {
private static final long serialVersionUID = 1L;
public static final Insets NO_INSETS = new Insets(0, 0, 0, 0);
public GridBagConstraints constraints;
private GridBagLayout layout;
public GridbagPanel() {
layout = new GridBagLayout();
constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.NONE;
constraints.anchor = GridBagConstraints.WEST;
constraints.insets = NO_INSETS;
setLayout(layout);
}
public void setHorizontalFill() {
constraints.fill = GridBagConstraints.HORIZONTAL;
}
public void setNoneFill() {
constraints.fill = GridBagConstraints.NONE;
}
public void add(Component component, int x, int y, int width, int
height, int weightX, int weightY) {
GridBagLayout gbl = (GridBagLayout) getLayout();
gbl.setConstraints(component, constraints);
add(component);
}
public void add(Component component, int x, int y, int width, int height) {
add(component, x, y, width, height, 0, 0);
}
public void setBothFill() {
constraints.fill = GridBagConstraints.BOTH;
}
public void setInsets(Insets insets) {
constraints.insets = insets;
}
}
We use a plain document that contains our main logic (your changes should be here):
package com.demo.textfield.version;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
/**
* a class for positive integers
*/
public class IntDocument extends PlainDocument {
/**
*
*/
private static final long serialVersionUID = 1L;
public static final String NUMERIC = "0123456789";
private int maxVal = -1;
private int maxLength = -1;
public IntDocument() {
this.maxVal = -1;
maxVal = Integer.MAX_VALUE;
maxLength = Integer.MAX_VALUE;
}
public void setMaxLength(int maxLength) {
if (maxLength < 0)
throw new IllegalArgumentException("maxLength<0");
this.maxLength = maxLength;
}
public void setMaxVal(int maxVal) {
this.maxVal = maxVal;
}
public void insertString
(int offset, String str, AttributeSet attr)
throws BadLocationException {
if (str == null)
return;
if (str.startsWith(" ") && offset == 0) {
beep();
str = "";
}
if (!isValidForAcceptedCharsPolicy(str))
return;
if (validateLength(offset, str) == false)
return;
if (!isValidForMaxVal(offset, str))
return;
super.insertString(offset, str, attr);
}
public boolean isValidForAcceptedCharsPolicy(String str) {
if (str.equals("")) {
beep();
return false;
}
for (int i = 0; i < str.length(); i++) {
if (NUMERIC.indexOf(String.valueOf(str.charAt(i))) == -1) {
beep();
return false;
}
}
return true;
}
public boolean isValidForMaxVal(int offset, String toAdd) {
String str_temp;
//String str_text = "";
String str1 = "";
String str2 = "";
try {
str1 = getText(0, offset);
str2 = getText(offset, getLength() - offset);
} catch (Exception e) {
e.printStackTrace();
}
int i_value;
str_temp = str1 + toAdd + str2;
//str_temp = str_temp.trim();
i_value = Integer.parseInt(str_temp);
if (i_value > maxVal) {
beep();
return false;
} else
return true;
}
private boolean validateLength(int offset, String toAdd) {
String str_temp;
//String str_text = "";
String str1 = "";
String str2 = "";
try {
str1 = getText(0, offset);
str2 = getText(offset, getLength() - offset);
} catch (Exception e) {
e.printStackTrace();
}
str_temp = str1 + toAdd + str2;
if (maxLength < str_temp.length()) {
beep();
return false;
} else
return true;
}
private void beep() {
//java.awt.Toolkit.getDefaultToolkit().beep();
}
}
And this is last one with main method that implements all above posted code and you get pretty good view. In my case I used list of 4 text fields separated by dot. You can jump from one "window" to another by using arrows or tab or dot or if your number length reached 4. It will work with implementation of FocusAdapter class:
package com.demo.textfield.version;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.FocusManager;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
/**
* diplays an version text field
*/
![enter image description here][1]public class VersionTextField extends GridbagPanel {
private static final long serialVersionUID = 1L;
/**
* a text field for each byte
*/
private JTextField[] textFields;
/**
* dots between text fields
*/
private JLabel[] dotsLabels;
/**
* used to calculate enable/disable color; never shown
*/
private static JTextField sampleTextField = new JTextField();
/**
* listen to changes in the byte fields
*/
private MyDocumentListener documentListener;
/**
* list of key listeners
*/
private List<KeyListener> keyListenersList;
/**
* List of Focus Adapter that select all data in JTextFiled during action
* */
private List<FocusAdapter> focusAdapterList;
/**
* list of key listeners
*/
private List<FocusListener> focusListenersList;
private int maxHeight = 0;
public VersionTextField() {
this(4);
}
/**
* #param byteCount
* number of bytes to display
*/
private VersionTextField(int byteCount) {
textFields = new JTextField[byteCount];
for (int i = 0; i < textFields.length; i++) {
textFields[i] = new JTextField(4);
}
//layout
//constraints.insets = new Insets(0, 0, 0, 0);
List<JLabel> dotsLabelsList = new ArrayList<JLabel>();
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.setHorizontalAlignment(JTextField.CENTER);
Document document = DocumentsFactory.createIntDocument(9999);
textField.setDocument(document);
if (i < textFields.length-1) {
add(textField, i * 2, 0, 1, 1);
if (textField.getPreferredSize().height > maxHeight)
maxHeight = textField.getPreferredSize().height;
JLabel label = new JLabel(".");
add(label, (i * 2) + 1, 0, 1, 1);
if (label.getPreferredSize().height > maxHeight)
maxHeight = label.getPreferredSize().height;
dotsLabelsList.add(label);
} else
add(textField, i * 2, 0, 1, 1);
}
//dotsLabels = new JLabel[dotsLabelsList.size()];
dotsLabels = new JLabel[dotsLabelsList.size()];
dotsLabels = dotsLabelsList.toArray(dotsLabels);
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.setBorder(BorderFactory.createEmptyBorder());
}
//init
Color backgroundColor = UIManager.getColor("TextField.background");
setBackground(backgroundColor);
Border border = UIManager.getBorder("TextField.border");
setBorder(border);
//register listeners
for (int i = 1; i < textFields.length; i++) {
JTextField field = textFields[i];
field.addKeyListener(new BackKeyAdapter());
}
documentListener = new MyDocumentListener();
for (int i = 0; i < textFields.length - 1; i++) {
JTextField field = textFields[i];
field.getDocument().addDocumentListener(documentListener);
field.addKeyListener(new ForwardKeyAdapter());
}
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.addKeyListener(new MyKeyListener());
}
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.addFocusListener(new MyFocusAdapter());
}
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.addFocusListener(new MyFocusAdapter());
}
keyListenersList = new ArrayList<KeyListener>();
focusListenersList = new ArrayList<FocusListener>();
focusAdapterList = new ArrayList<FocusAdapter>();
}
public synchronized void addKeyListener(KeyListener l) {
super.addKeyListener(l);
keyListenersList.add(l);
}
public synchronized void addFocusListener(FocusListener l) {
super.addFocusListener(l);
if (focusListenersList != null)
focusListenersList.add(l);
}
public synchronized void removeKeyListener(KeyListener l) {
super.removeKeyListener(l);
if (focusListenersList != null)
keyListenersList.remove(l);
}
public synchronized void removeFocusListener(FocusListener l) {
super.removeFocusListener(l);
keyListenersList.remove(l);
}
public void setEnabled(boolean b) {
super.setEnabled(b);
sampleTextField.setEnabled(b);
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.setEnabled(b);
}
for (int i = 0; i < dotsLabels.length; i++) {
JLabel dotsLabel = dotsLabels[i];
dotsLabel.setEnabled(b);
}
setBackground(sampleTextField.getBackground());
setForeground(sampleTextField.getForeground());
setBorder(sampleTextField.getBorder());
}
public void requestFocus() {
super.requestFocus();
textFields[0].requestFocus();
}
public void setEditable(boolean b) {
sampleTextField.setEditable(b);
setBackground(sampleTextField.getBackground());
setForeground(sampleTextField.getForeground());
setBorder(sampleTextField.getBorder());
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.setEditable(b);
}
for (int i = 0; i < dotsLabels.length; i++) {
JLabel dotsLabel = dotsLabels[i];
dotsLabel.setForeground(sampleTextField.getForeground());
}
}
public boolean isFieldEmpty() {
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
String sCell = textField.getText().trim();
if (!(sCell.equals("")))
return false;
}
return true;
}
public Dimension getPreferredSize() {
if (super.getPreferredSize().height > maxHeight)
maxHeight = super.getPreferredSize().height;
return new Dimension(super.getPreferredSize().width, maxHeight);
}
/**
* clears current text in text fiekd
*/
private void reset() {
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.getDocument().removeDocumentListener(documentListener);
textField.setText("");
textField.getDocument().addDocumentListener(documentListener);
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("test");
VersionTextField ipTextField = new VersionTextField();
ipTextField.setText("9.1.23.1479");
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(ipTextField);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public void setText(String version) {
if (version == null || "".equals(version) || "null".equals(version))
reset();
else {
setVer(version.split("[.]"));
}
}
private void setVer(String[] ver) {
if (ver == null) {
reset();
return;
}
Enumeration<String> enumeration = Collections.enumeration(Arrays.asList(ver));
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
String s = (String) enumeration.nextElement();
textField.getDocument().removeDocumentListener(documentListener);
textField.setText(s);
textField.getDocument().addDocumentListener(documentListener);
}
}
public void setToolTipText(String toolTipText) {
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.setToolTipText(toolTipText);
}
}
private class MyDocumentListener implements DocumentListener {
#Override
public void insertUpdate(DocumentEvent e) {
Document document = e.getDocument();
try {
JTextField textField = (JTextField) FocusManager.getCurrentManager().getFocusOwner();
String s = document.getText(0, document.getLength());
if (s.length() == 4){ // && textField.getCaretPosition() == 2) {
textField.transferFocus();
}
} catch (BadLocationException e1) {
e1.printStackTrace();
return;
}
}
public void removeUpdate(DocumentEvent e) {
}
#Override
public void changedUpdate(DocumentEvent e) {
// Document document = e.getDocument();
// try {
// Component component = FocusManager.getCurrentManager().getFocusOwner();
// String s = document.getText(0, document.getLength());
//
// // get selected integer
// int valueInt = Integer.parseInt(s);
//
// if (valueInt > 25) {
// component.transferFocus();
// }
//
// } catch (BadLocationException e1) {
// e1.printStackTrace();
// return;
// }
}
}
private class BackKeyAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
JTextField textField = (JTextField) e.getComponent();
if (textField.getCaretPosition() == 0
&& KeyEvent.VK_LEFT == e.getKeyCode()
&& e.getModifiers() == 0)
textField.transferFocusBackward();
if (textField.getCaretPosition() == 0
&& KeyEvent.VK_BACK_SPACE == e.getKeyCode()
&& e.getModifiers() == 0) {
textField.transferFocusBackward();
}
}
}
private class ForwardKeyAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
JTextField textField = (JTextField) e.getComponent();
if (KeyEvent.VK_RIGHT == e.getKeyCode() && e.getModifiers() == 0) {
int length = textField.getText().length();
int caretPosition = textField.getCaretPosition();
if (caretPosition == length) {
textField.transferFocus();
e.consume();
}
}
if (e.getKeyChar() == '.' &&
textField.getText().trim().length() != 0) {
textField.setText(textField.getText().trim());
textField.transferFocus();
e.consume();
}
}
}
/**
* #return current text in ip text field
*/
public String getText() {
StringBuffer buffer = new StringBuffer();
String ipResult;
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
if(textField.getText().trim().equals("")){
return "";
}
buffer.append(Integer.parseInt(textField.getText()));
if (i < textFields.length - 1){
buffer.append('.');
}
}
ipResult = buffer.toString();
return ipResult;
}
/**
* general purpose key listener
*/
private class MyKeyListener implements KeyListener {
public void keyPressed(KeyEvent e) {
for (int i = 0; i < keyListenersList.size(); i++) {
KeyListener keyListener = keyListenersList.get(i);
keyListener.keyPressed(new KeyEvent(VersionTextField.this,
e.getID(), e.getWhen(), e.getModifiers(), e
.getKeyCode(), e.getKeyChar(), e
.getKeyLocation()));
}
}
public void keyReleased(KeyEvent e) {
for (int i = 0; i < keyListenersList.size(); i++) {
KeyListener keyListener = keyListenersList.get(i);
keyListener.keyReleased(new KeyEvent(VersionTextField.this, e
.getID(), e.getWhen(), e.getModifiers(),
e.getKeyCode(), e.getKeyChar(), e.getKeyLocation()));
}
}
public void keyTyped(KeyEvent e) {
for (int i = 0; i < keyListenersList.size(); i++) {
KeyListener keyListener = keyListenersList.get(i);
keyListener.keyTyped(new KeyEvent(VersionTextField.this, e.getID(),
e.getWhen(), e.getModifiers(), e.getKeyCode(), e
.getKeyChar(), e.getKeyLocation()));
}
}
}
private class MyFocusAdapter extends FocusAdapter {
public void focusGained(FocusEvent e) {
for (int i = 0; i < focusListenersList.size(); i++) {
FocusListener focusListener = focusListenersList.get(i);
focusListener.focusGained(new FocusEvent(
VersionTextField.this,
e.getID(),
e.isTemporary(),
e.getOppositeComponent()
));
}
if(e.getComponent() instanceof javax.swing.JTextField){
highlightText((JTextField)e.getSource());
}
}
public void focusLost(FocusEvent e) {
for (int i = 0; i < focusListenersList.size(); i++) {
FocusListener focusListener = focusListenersList.get(i);
focusListener.focusLost(new FocusEvent(
VersionTextField.this,
e.getID(),
e.isTemporary(),
e.getOppositeComponent()
));
}
}
public void highlightText(javax.swing.JTextField ctr){
//ctr.setSelectionColor(Color.BLUE);
//ctr.setSelectedTextColor(Color.WHITE);
ctr.setSelectionStart(0);
ctr.setSelectionEnd(ctr.getText().length());
System.out.println(ctr.getText());
}
}
}
here a view what we got:
here you go
JFormattedTextField

Categories