这曾经是家庭作业,但现在它是个人的,因为学期结束了,我仍在努力学习 Swing 组件。这个程序是我尝试以最简单(看起来)的方式将程序控制台 TicTacToe 实现提升到一个小程序中,避免使用单个 JTextField 和提交按钮的传统按钮网格。
它在第一次运行良好,但是在我用 init() 函数中的一些逻辑重置游戏后(这确实有效,我很惊讶),getText() 在第 155 行返回空字符串(搜索“ARGH” )。在这一点上,我基本上是在黑暗中拍摄,所以,如果有人可以看看和批评,也许指出通过这条最短路线的方式,我真的很感激!
/**
* TTTapp.java - TicTacToe
* Implements a simple console-based version of the classic
* game Tic Tac Toe
* @author Todd Howe
* @version 1.0
* @since 2012-08-22
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.ArrayList;
import java.util.*;
/**
* Plays a simple game of Tic Tac Toe.
*
* A 3x3 char array is generated to accomodate a simple Tic Tac Toe
* game. The player picks a position, the computer picks randomly
* and the results are tallied in the usual manner.
*/
public class TTTapp extends JApplet implements ActionListener {
static boolean checkWin=false; // control variable to detect wins
static boolean boardFull=false; // control variable to detect ties
static String response=""; // user input
static int gridPos; // (1-9) 1D rep of position on the TTT board
static int x, y; // cartesian TTT board coordinates
static char player; // X or O to indicate current player
static char[][] board = new char[3][3]; // 2d TTT board matrix
static int[][] magicsquare = { {8, 1, 6}, // sekrit weapon
{3, 5, 7},
{4, 9, 2} };
Container con=getContentPane();
Font monoFont = new Font("Monospaced", Font.BOLD, 12);
JLabel gameBanner1=new JLabel("Welcome to Tic Tac Toe!");
JLabel gameBanner2=new JLabel("Player is X, Computer is O");
JLabel spacer1=new JLabel(" ");
JLabel spacer2=new JLabel(" ");
JLabel spacer3=new JLabel(" ");
JLabel board1=new JLabel(" 1 | 2 | 3 ");
JLabel board2=new JLabel("---|---|---");
JLabel board3=new JLabel(" 4 | 5 | 6 ");
JLabel board4=new JLabel("---|---|---");
JLabel board5=new JLabel(" 7 | 8 | 9 ");
JLabel announce=new JLabel("");
JLabel prompt=new JLabel("\nPick an available space by entering the number (1-9): ");
JTextField promptField=new JTextField("",4);
JButton submitButton=new JButton("Submit");
JButton restartButton=new JButton("RESTART GAME");
BoxLayout flow=new BoxLayout(con, BoxLayout.Y_AXIS);
public void init() {
// prep the application window
if (TTTapp.checkWin==false) {
con.setLayout(flow);
board1.setFont(monoFont);
board2.setFont(monoFont);
board3.setFont(monoFont);
board4.setFont(monoFont);
board5.setFont(monoFont);
gameBanner1.setAlignmentX(Component.CENTER_ALIGNMENT);
gameBanner2.setAlignmentX(Component.CENTER_ALIGNMENT);
board1.setAlignmentX(Component.CENTER_ALIGNMENT);
board2.setAlignmentX(Component.CENTER_ALIGNMENT);
board3.setAlignmentX(Component.CENTER_ALIGNMENT);
board4.setAlignmentX(Component.CENTER_ALIGNMENT);
board5.setAlignmentX(Component.CENTER_ALIGNMENT);
announce.setAlignmentX(Component.CENTER_ALIGNMENT);
prompt.setAlignmentX(Component.CENTER_ALIGNMENT);
promptField.setAlignmentX(Component.CENTER_ALIGNMENT);
submitButton.setAlignmentX(Component.CENTER_ALIGNMENT);
con.add(gameBanner1);
con.add(gameBanner2);
con.add(spacer1);
con.add(board1);
con.add(board2);
con.add(board3);
con.add(board4);
con.add(board5);
con.add(spacer2);
con.add(announce);
con.add(prompt);
con.add(promptField);
con.add(submitButton);
promptField.requestFocus();
System.out.println("Real INIT");
submitButton.addActionListener(this);
promptField.addActionListener(this);
}
else {
con.setLayout(flow);
board1.setFont(monoFont);
board2.setFont(monoFont);
board3.setFont(monoFont);
board4.setFont(monoFont);
board5.setFont(monoFont);
gameBanner1.setAlignmentX(Component.CENTER_ALIGNMENT);
gameBanner2.setAlignmentX(Component.CENTER_ALIGNMENT);
board1.setAlignmentX(Component.CENTER_ALIGNMENT);
board2.setAlignmentX(Component.CENTER_ALIGNMENT);
board3.setAlignmentX(Component.CENTER_ALIGNMENT);
board4.setAlignmentX(Component.CENTER_ALIGNMENT);
board5.setAlignmentX(Component.CENTER_ALIGNMENT);
announce.setAlignmentX(Component.CENTER_ALIGNMENT);
prompt.setAlignmentX(Component.CENTER_ALIGNMENT);
promptField.setAlignmentX(Component.CENTER_ALIGNMENT);
submitButton.setAlignmentX(Component.CENTER_ALIGNMENT);
restartButton.setAlignmentX(Component.CENTER_ALIGNMENT);
con.add(gameBanner1);
con.add(gameBanner2);
con.add(spacer1);
con.add(board1);
con.add(board2);
con.add(board3);
con.add(board4);
con.add(board5);
con.add(spacer2);
con.add(announce);
con.add(spacer3);
con.add(restartButton);
System.out.println("Else INIT");
restartButton.addActionListener(this);
}
}
public void actionPerformed(ActionEvent e) {
String discard="";
// MAIN GAME LOOP (CHANGED BOTH FORMER WHILE LOOPS TO IF TO ALLOW GETTEXT REFRESH)
// game reset
if (TTTapp.checkWin==true) {
TTTapp.checkWin=false;
TTTapp.boardFull=false;
TTTapp.response="";
TTTapp.board = new char[3][3];
TTTapp.gridPos=(-1);
announce.setText("");
con.remove(announce);
con.remove(restartButton);
con.remove(spacer3);
board1.setText(" 1 | 2 | 3 ");
board2.setText("---|---|---");
board3.setText(" 4 | 5 | 6 ");
board4.setText("---|---|---");
board5.setText(" 7 | 8 | 9 ");
promptField.requestFocus();
init();
TTTapp.response=promptField.getText();
promptField.setText("");
// ### ARGH THIS DOESN'T READ promptField IN INIT() ################
}
if (TTTapp.boardFull==false && TTTapp.checkWin==false) {
// ###############################################################
// System.out.println("boardFull: "+boardFull+" checkWin: "+checkWin);
displayBoard(TTTapp.board);
// player's turn
// System.out.println("Player's turn");
TTTapp.player='X';
TTTapp.gridPos=(-1);
// WAS WHILE
while (TTTapp.gridPos==(-1)) { // this was my last attempt to capture the bad response
if (TTTapp.gridPos==(-1)) {
TTTapp.response=promptField.getText();
promptField.setText("");
// ##################################################
System.out.println("Got here, response is "+response);
TTTapp.gridPos=validateResponse(TTTapp.response, TTTapp.board);
// #######################################
System.out.println("GridPos is "+gridPos);
TTTapp.boardFull=playGridPos(TTTapp.gridPos, TTTapp.board, TTTapp.player);
// ########################################
System.out.println("boardFull: "+boardFull);
displayBoard(TTTapp.board);
}
}
// check for player win
TTTapp.checkWin=scanBoard(TTTapp.board, TTTapp.magicsquare, TTTapp.player);
if (TTTapp.checkWin==true) {
displayBoard(TTTapp.board);
con.remove(prompt);
con.remove(promptField);
con.remove(submitButton);
announce.setText("\nPLAYER WINS");
}
// computer's turn
TTTapp.player='O';
if (TTTapp.checkWin==false) {
if (TTTapp.boardFull==false) {
TTTapp.gridPos=computerPlays(TTTapp.board);
TTTapp.boardFull=playGridPos(TTTapp.gridPos, TTTapp.board, TTTapp.player);
displayBoard(TTTapp.board);
}
//check for computer win here
TTTapp.checkWin=scanBoard(TTTapp.board, TTTapp.magicsquare, TTTapp.player);
if (TTTapp.checkWin==true) {
displayBoard(TTTapp.board);
con.remove(prompt);
con.remove(promptField);
con.remove(submitButton);
announce.setText("\nCOMPUTER WINS");
}
}
}
if (TTTapp.checkWin==false && TTTapp.boardFull==true) {
displayBoard(TTTapp.board);
con.remove(prompt);
con.remove(promptField);
con.remove(submitButton);
announce.setText("\nTIE GAME");
}
if (TTTapp.checkWin==true) {
init();
}
repaint();
}
/**
* Display the TicTacToe board as a grid
* @param board 2D char array representing game board
*/
public void displayBoard(char[][] board) {
int gridPos; // (1-9) 1d rep of position on the board
char[] cell=new char[9]; // array of parsed TTT board elements
char readCell; // single TTT element
int line; // printout line number
String[] boardDisplay = new String[5]; // array for 'console printing' to applet
// System.out.println("");
// stores each element of the displayBoard readout in cell[]
for (int x=0; x<3; x++) {
for (int y=0; y<3; y++) {
gridPos=((x*3)+y);
readCell=parseCell(board[x][y]);
if (readCell==' ') {
cell[gridPos]=(char)(gridPos+49);
}
else {
cell[(x*3)+y]=readCell;
}
}
// constructs tic tac toe grid display line by line
line=x*2;
boardDisplay[line]=(" "+cell[((x*3)+0)]+" | "+cell[((x*3)+1)]+" | "+cell[((x*3)+2)]);
if(x<2) {
line+=1;
boardDisplay[line]=("---|---|---");
}
}
board1.setText(boardDisplay[0]);
board2.setText(boardDisplay[1]);
board3.setText(boardDisplay[2]);
board4.setText(boardDisplay[3]);
board5.setText(boardDisplay[4]);
}
/**
* Checks desired player board position against vacancies on TTT grid
* @param response String of user response
* @param board 2D char array representing game board
*/
public int validateResponse(String response,char[][] board) {
int checkPos=(-1); // desired TTT board position
ArrayList emptyCells=new ArrayList(); // array of available positions
Integer somePos; // candidate TTT board position
int result=(-1); // result returns position or -1 signal to try again
boolean contains=false; // candidate cell matches desired position
// populate emptyCells with (1-9) positions
emptyCells=findEmptyCells(board);
// checks whether there's any empty cells left
if (emptyCells.size() > 0) {
// checks whether the input is at least one char long
if (response.length()>0) {
checkPos=(int)(response.charAt(0)-48);
int i=0;
while (i<emptyCells.size()) {
// #########################################################
// System.out.println("emptyCells("+i+"): "+emptyCells.get(i));
// checks whether requested cell is empty or not
somePos=(Integer)(emptyCells.get(i));
// ############################################################
// System.out.println("somePos: "+somePos+" checkPos: "+checkPos);
if ((somePos.intValue())!=checkPos) {
i++;
}
else {
if ((somePos.intValue())==checkPos) {
contains=true;
i=99;
}
}
}
// if requested cell is empty, validate request
if (contains==true) {
result=checkPos;
}
// otherwise send pick again signal
else {
// #################################################################
// System.out.println("Contains is "+contains+" checkPos is "+checkPos);
result=(-1);
}
}
// if no entry detected, send pick again signal
else {
result=(-1);
}
}
return(result);
}
/**
* Further validates and places player marker on the board
* @param gridPos Int desired position of marker on board
* @param board 2D char array representing game board
* @param player Char marker representing player
*/
public boolean playGridPos(int gridPos, char[][] board, char player) {
int x,y; // cartesian TTT board coordinates
ArrayList emptyCells=new ArrayList(); // array of available positions
boolean boardFull=false; // control variable to detect ties
switch (gridPos) {
// catch invalid entry signal
case(-1):
announce.setText("\nPLEASE ENTER ONE OF THE VISIBLE NUMBERS.");
break;
// place the player marker on the board
default:
gridPos--;
x=gridPos/3;
y=gridPos-(x*3);
board[x][y]=player;
}
emptyCells=findEmptyCells(board);
// check to see if the board is now full
if (emptyCells.size()==0) {
boardFull=true;
}
return(boardFull);
}
/**
* Determines the computer's next move
* @param board 2D char array representing game board
*/
public int computerPlays(char[][] board) {
int gridPos=(-1); // (1-9) 1d rep of position on the board
int temp; // random board position variable
String response=""; // user input
Integer availPos; // Integer rep of board position index
ArrayList emptyCells=new ArrayList(); // array of available positions
boolean vacant=false; // control variable for a position's vacancy
boolean checkWin=false; // control variable to detect a win
char[][] tempBoard = new char[3][3]; // board to test positions for a win
int[][] magicsquare = { {8, 1, 6}, // sekrit weapon
{3, 5, 7},
{4, 9, 2} };
emptyCells=findEmptyCells(board);
// check to see if we have an available win and pick that
for (int i=0; i<emptyCells.size(); i++) {
response=(""+emptyCells.get(i));
temp=validateResponse(response, board);
availPos=(Integer)temp;
temp=availPos.intValue();
// copy board to tempBoard
for(int x=0; x<3; x++) {
for(int y=0; y<3; y++) {
tempBoard[x][y]=board[x][y];
}
}
// if there's two adjacent Os, find the win
if (checkWin==false) {
checkWin=playGridPos(temp,tempBoard,'O');
checkWin=scanBoard(tempBoard,magicsquare,'O');
if (checkWin==true) {
gridPos=temp;
}
}
}
// else pick a random square
if (checkWin==false) {
while (vacant==false) {
temp=(int)(Math.random()*(emptyCells.size()-1));
response=(""+emptyCells.get(temp));
gridPos=validateResponse(response, board);
if (gridPos!=(-2) && gridPos!=(-1)) {
availPos=(Integer)gridPos;
gridPos=availPos.intValue();
vacant=true;
}
}
}
return(gridPos);
}
/**
* Detect vacant elements in TicTacToe matrix
* @param board 2D char array representing game board
*/
public ArrayList findEmptyCells(char[][] board) {
ArrayList emptyCells=new ArrayList(); // array of available positions
char readCell; // contents of a candidate cell
Integer availPos; // integer rep of board position index
for (int x=0; x<3; x++) {
for (int y=0; y<3; y++) {
availPos=Integer.valueOf((x*3)+y+1);
readCell=parseCell(board[x][y]);
if (readCell==' ') {
emptyCells.add(availPos);
}
}
}
return(emptyCells);
}
/**
* Scores the TTT board using a magic square to tally row/col/diag
* @param board 2D char array representing game board
* @param magicsquare 2D matrix to to help score TTT board
* @param player Char marker representing player
*/
public boolean scanBoard(char[][] board, int[][] magicsquare, char player) {
char readCell; // contents of a candidate cell
int[][] keyScores=new int[3][3]; // matrix for magicsquare scoring
boolean checkWin=false; // control variable to detect wins
// mask magicsquare with player's occupied cells
for (int x=0; x<3; x++) {
for (int y=0; y<3; y++) {
readCell=parseCell(board[x][y]);
if (readCell==player) {
keyScores[x][y]=magicsquare[x][y];
}
else {
keyScores[x][y]=0;
}
}
}
// check for a win
// horizontals
for (int x=0; x<3; x++) {
if ((keyScores[x][0]+keyScores[x][1]+keyScores[x][2])==15)
checkWin=true;
}
//verticals
for (int y=0; y<3; y++) {
if ((keyScores[0][y]+keyScores[1][y]+keyScores[2][y])==15)
checkWin=true;
}
//diagonals
if ((keyScores[0][0]+keyScores[1][1]+keyScores[2][2])==15)
checkWin=true;
if ((keyScores[0][2]+keyScores[1][1]+keyScores[2][0])==15)
checkWin=true;
return(checkWin);
}
/**
* Returns a processed representation of one TTT cell element
* @param token Char contents of a single TTT cell
*/
public char parseCell(char token) {
char result=' '; // holds processed contents of cell
switch(token) {
case('\u0000'):
result=(' ');
break;
case('x'):
case('X'):
result=('X');
break;
case('o'):
case('O'):
result=('O');
break;
default:
result=token;
}
return(result);
}
}