还在动手画棋盘 ?20分钟带你用Java写一个井字棋!
文章目录
- 还在动手画棋盘 ?20分钟带你用Java写一个井字棋!
- 前言
- 设计过程
- 1.创建窗体类MyGameWindow
- 2.创建窗体的构造器
- 3.创建棋盘
- 4.编写下棋方法
- 5.编写寻找下棋位置的方法
- 完善事件监听器
- 6.增加限制,一个位置只能下一颗棋子
- 7.编写胜利方法
- 8.编写清楚数据方法
- 最终源代码
前言
上课无聊的时候,肯定会有很多人拿出一张白纸,老师在上面讲的津津有味,我和同桌已经开始下起了井字棋,老师课也讲完了,我也画满了一张白纸。无聊想要玩井字棋,不仅浪费纸张,还要自己动手画棋。,今天小编带着你,用Java编写一个井字棋小游戏。
设计过程
1.创建窗体类MyGameWindow
创建MyGameWindow类使其继承JFrame类成为窗体类并实现ActionListener接口,并实现ActionListener接口中的actionPerformed(ActionEvent e)方法。
public class MyGameWindow extends JFrame implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
}
}
2.创建窗体的构造器
创建窗体的构造器,进行一些基础的设置,并在主方法中进行实例化。
public class MyGameWindow extends JFrame implements ActionListener {
public MyGameWindow(){
//设置窗口的标题
setTitle("井字棋");
//设置窗体的位置和大小
setBounds(100,100,600,600);
//设置窗体的布局方式
setLayout(new GridLayout(3,3));
//设置窗体的关闭方式
setDefaultCloseOperation(EXIT_ON_CLOSE);
//设置窗体可见
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
}
public static void main(String[] args) {
new MyGameWindow();
}
}
此时,我们已经造出了一个空的窗口。
3.创建棋盘
创建一个三行三列的按钮数组表示棋盘,并将按钮数组实例化添加到窗体中,并为各按钮设置事件监听器。
public class MyGameWindow extends JFrame implements ActionListener {
//以3行3列数组的形式创建表盘
private JButton[][] boards = new JButton[3][3];
public MyGameWindow(){
//设置窗口的标题
setTitle("井字棋");
//设置窗体的位置和大小
setBounds(100,100,600,600);
//设置窗体的布局方式
setLayout(new GridLayout(3,3));
//将按钮数组添加到窗体中去并为按钮添加事件监听方法
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//实例化按钮
boards[i][j] = new JButton();
//将按钮添加到窗体中去
add(boards[i][j]);
//为按钮添加时间监听方法
boards[i][j].addActionListener(this);
}
}
//设置窗体的关闭方式
setDefaultCloseOperation(EXIT_ON_CLOSE);
//设置窗体可见
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
}
public static void main(String[] args) {
new MyGameWindow();
}
}
此时,我们已经可以看到我们造好的棋盘了。
4.编写下棋方法
棋盘有了,那该怎么下呢。接下来就需要编写下棋的方法。
首先我们需要添加一个标志flag,这个标志将表明此时是谁在下棋。
当flag=0时,表示此时下棋的是执X的玩家,当flag=1时,表示此时下棋的是执O的玩家。我们将标志变量初始化为0,这表明每一局都将是由执X的玩家先手。
接着我们就可以编写下棋方法了。当flag=0时,下X,将flag赋值为1,表示此时该执O的玩家下棋了。同理,当flag=1,时,下O,将flag赋值为0,表示此时该执X的玩家下棋了。
//下棋方法
private void play(JButton clickBtn,int i,int j){
if(flag == 0){
clickBtn.setText(“X”);
flag = 1;
}else if(flag == 1){
clickBtn.setText(“O”);
flag = 0;
}
}
public class MyGameWindow extends JFrame implements ActionListener {
//以3行3列数组的形式创建表盘
private JButton[][] boards = new JButton[3][3];
//X先手
private int flag = 0;//flag = 0 表示落子X flag = 1表示落子O
public MyGameWindow(){
//设置窗口的标题
setTitle("井字棋");
//设置窗体的位置和大小
setBounds(100,100,600,600);
//设置窗体的布局方式
setLayout(new GridLayout(3,3));
//将按钮数组添加到窗体中去并为按钮添加事件监听方法
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//实例化按钮
boards[i][j] = new JButton();
//将按钮添加到窗体中去
add(boards[i][j]);
//为按钮添加时间监听方法
boards[i][j].addActionListener(this);
}
}
//设置窗体的关闭方式
setDefaultCloseOperation(EXIT_ON_CLOSE);
//设置窗体可见
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
}
//下棋方法
private void play(JButton clickBtn,int i,int j){
if(flag == 0){
clickBtn.setText("X");
flag = 1;
}else if(flag == 1){
clickBtn.setText("O");
flag = 0;
}
}
public static void main(String[] args) {
new MyGameWindow();
}
}
5.编写寻找下棋位置的方法
编写完了下棋的方法之后,我们需要准确的知道玩家在棋盘的哪一个位置下了棋。因此需要编写一个寻找下棋位置的方法。
这个方法返回一个长度为2的location数组,location[0]记录玩家下棋位置的行数,location[1]记录玩家下棋位置的列数。
这样我们就能够在棋盘中准确的找到玩家下棋的位置了。
//寻找按钮位置
private int[] location(JButton clickBtn){
int[] location = new int[2];//location[0]表示第i行,location[1]表示第j列
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if(boards[i][j] == clickBtn){
location[0] = i;
location[1] = j;
}
}
}
return location;
}
public class MyGameWindow extends JFrame implements ActionListener {
//以3行3列数组的形式创建表盘
private JButton[][] boards = new JButton[3][3];
//X先手
private int flag = 0;//flag = 0 表示落子X flag = 1表示落子O
public MyGameWindow(){
//设置窗口的标题
setTitle("井字棋");
//设置窗体的位置和大小
setBounds(100,100,600,600);
//设置窗体的布局方式
setLayout(new GridLayout(3,3));
//将按钮数组添加到窗体中去并为按钮添加事件监听方法
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//实例化按钮
boards[i][j] = new JButton();
//将按钮添加到窗体中去
add(boards[i][j]);
//为按钮添加时间监听方法
boards[i][j].addActionListener(this);
}
}
//设置窗体的关闭方式
setDefaultCloseOperation(EXIT_ON_CLOSE);
//设置窗体可见
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
}
//下棋方法
private void play(JButton clickBtn,int i,int j){
if(flag == 0){
clickBtn.setText("X");
flag = 1;
}else if(flag == 1){
clickBtn.setText("O");
flag = 0;
}
}
//寻找按钮位置
private int[] location(JButton clickBtn){
int[] location = new int[2];//location[0]表示第i行,location[1]表示第j列
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if(boards[i][j] == clickBtn){
location[0] = i;
location[1] = j;
}
}
}
return location;
}
public static void main(String[] args) {
new MyGameWindow();
}
}
完善事件监听器
前期的准备工作基本上已经完成。想要让棋子跑到棋盘上去,我们还需要完善按钮的事件监听器。
首先我们需要获取玩家点击的到底是哪一个按钮,然后记录下这个按钮的行数和列数。然后我们就可以在棋盘上落下棋子啦。
@Override
public void actionPerformed(ActionEvent e) {
//获取点击的按钮
JButton clickBtn = (JButton) e.getSource();
//找到落子的位置
int[] places = location(clickBtn);
int i = places[0];
int j = places[1];
//下棋
play(clickBtn, i, j);
}
public class MyGameWindow extends JFrame implements ActionListener {
//以3行3列数组的形式创建表盘
private JButton[][] boards = new JButton[3][3];
//X先手
private int flag = 0;//flag = 0 表示落子X flag = 1表示落子O
public MyGameWindow(){
//设置窗口的标题
setTitle("井字棋");
//设置窗体的位置和大小
setBounds(100,100,600,600);
//设置窗体的布局方式
setLayout(new GridLayout(3,3));
//将按钮数组添加到窗体中去并为按钮添加事件监听方法
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//实例化按钮
boards[i][j] = new JButton();
//将按钮添加到窗体中去
add(boards[i][j]);
//为按钮添加时间监听方法
boards[i][j].addActionListener(this);
}
}
//设置窗体的关闭方式
setDefaultCloseOperation(EXIT_ON_CLOSE);
//设置窗体可见
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
//获取点击的按钮
JButton clickBtn = (JButton) e.getSource();
//找到落子的位置
int[] places = location(clickBtn);
int i = places[0];
int j = places[1];
//下棋
play(clickBtn, i, j);
}
//下棋方法
private void play(JButton clickBtn,int i,int j){
if(flag == 0){
clickBtn.setText("X");
flag = 1;
}else if(flag == 1){
clickBtn.setText("O");
flag = 0;
}
}
//寻找按钮位置
private int[] location(JButton clickBtn){
int[] location = new int[2];//location[0]表示第i行,location[1]表示第j列
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if(boards[i][j] == clickBtn){
location[0] = i;
location[1] = j;
}
}
}
return location;
}
public static void main(String[] args) {
new MyGameWindow();
}
}
6.增加限制,一个位置只能下一颗棋子
看看上面的两张图片没有,有没有发现什么问题。
第一张图片是正常的,此时棋盘已满,但是我们仍然可以在棋盘的任意位置下棋,这就导致了第二幅图的情况。满屏的O,执X的玩家表示这不公平!
这不合理。那么怎么解决呢?
我们定义一个二维数组place,存储棋盘上棋子的情况。
当place[i][j]=1时,表示此位置有棋子X
当place[i][j]=-1时,表示此位置有棋子O
当place[i][j]=0时,表示此位置没有棋子
当玩家想要在已经有棋子的位置下棋时,我们应该给出提示,提醒他不能下在这里。
既然已经做出了规定,我们就需要在玩家下棋的时候记录下棋盘的情况,所以我们对下棋的方法稍作更改,让其及时记录棋盘的情况。
//下棋方法
private void play(JButton clickBtn,int i,int j){
if(flag == 0){
clickBtn.setText(“X”);
flag = 1;
place[i][j] = 1;
}else if(flag == 1){
clickBtn.setText(“O”);
flag = 0;
place[i][j] = -1;
}
}//判断当前位置是否落子
if(place[i][j] == 1 || place[i][j] == -1){
JOptionPane.showMessageDialog(this, “该处已经落子,请选择其他位置!”);
return ;
}
public class MyGameWindow extends JFrame implements ActionListener {
//以3行3列数组的形式创建表盘
private JButton[][] boards = new JButton[3][3];
//X先手
private int flag = 0;//flag = 0 表示落子X flag = 1表示落子O
private int[][] place = new int[3][3];//落子X将对应的place设置为1,落子O设置为-1
public MyGameWindow(){
//设置窗口的标题
setTitle("井字棋");
//设置窗体的位置和大小
setBounds(100,100,600,600);
//设置窗体的布局方式
setLayout(new GridLayout(3,3));
//将按钮数组添加到窗体中去并为按钮添加事件监听方法
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//实例化按钮
boards[i][j] = new JButton();
//将按钮添加到窗体中去
add(boards[i][j]);
//为按钮添加时间监听方法
boards[i][j].addActionListener(this);
}
}
//设置窗体的关闭方式
setDefaultCloseOperation(EXIT_ON_CLOSE);
//设置窗体可见
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
//获取点击的按钮
JButton clickBtn = (JButton) e.getSource();
//找到落子的位置
int[] places = location(clickBtn);
int i = places[0];
int j = places[1];
//判断当前位置是否落子
if(place[i][j] == 1 || place[i][j] == -1){
JOptionPane.showMessageDialog(this, "该处已经落子,请选择其他位置!");
return ;
}
//下棋
play(clickBtn, i, j);
}
//下棋方法
private void play(JButton clickBtn,int i,int j){
if(flag == 0){
clickBtn.setText("X");
flag = 1;
place[i][j] = 1;
}else if(flag == 1){
clickBtn.setText("O");
flag = 0;
place[i][j] = -1;
}
}
//寻找按钮位置
private int[] location(JButton clickBtn){
int[] location = new int[2];//location[0]表示第i行,location[1]表示第j列
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if(boards[i][j] == clickBtn){
location[0] = i;
location[1] = j;
}
}
}
return location;
}
public static void main(String[] args) {
new MyGameWindow();
}
}
7.编写胜利方法
通过上面的运行结果我们又发现了什么问题?对,就是明明X已经赢了,可是游戏仍然在继续。这就需要我们编写胜利方法来判断谁是赢家。
胜利的方式有几种?横着的三种,竖着的三种,斜着的两种。那么一共就是八种方法。
int first = place[0][0] + place[0][1] + place[0][2];
int second = place[1][0] + place[1][1] + place[1][2];
int third = place[2][0] + place[2][1] + place[2][2];
int forth = place[0][0] + place[1][0] + place[2][0];
int fifth = place[0][1] + place[1][1] + place[2][1];
int sixth = place[0][2] + place[1][2] + place[2][2];
int seventh = place[0][0] + place[1][1] + place[2][2];
int eighth = place[0][2] + place[1][1] + place[2][0];
那么我们怎么判断是谁赢了呢?前面我们规定,下X的位置places数组的值被设为1,下O的位置places数组的值被设为-1。
当此上八种方法中的一种的值为3,则表明执X的玩家胜利。
当此上八种方法中的一种的值为-3,则表明执O的玩家胜利。
if(first == 3 || second == 3 || third == 3 || forth == 3 ||fifth == 3||sixth == 3||seventh == 3||eighth ==3){
return 1;//X胜利
}
else if(first == -3 || second == -3 || third == -3 || forth == -3 ||fifth == -3||sixth == -3||seventh == -3||eighth ==-3){
return -1;//O胜利
}
若棋盘未满,则继续游戏。
for (int i = 0; i < 3 ; i++) {
for (int j = 0; j < 3; j++) {
if(place[i][j] == 0)
return -2;//表示继续进行
}
}
否则,双方平局。
rerturn 0;
public class MyGameWindow extends JFrame implements ActionListener {
//以3行3列数组的形式创建表盘
private JButton[][] boards = new JButton[3][3];
//X先手
private int flag = 0;//flag = 0 表示落子X flag = 1表示落子O
private int[][] place = new int[3][3];//落子X将对应的place设置为1,落子O设置为-1
public MyGameWindow(){
//设置窗口的标题
setTitle("井字棋");
//设置窗体的位置和大小
setBounds(100,100,600,600);
//设置窗体的布局方式
setLayout(new GridLayout(3,3));
//将按钮数组添加到窗体中去并为按钮添加事件监听方法
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//实例化按钮
boards[i][j] = new JButton();
//将按钮添加到窗体中去
add(boards[i][j]);
//为按钮添加时间监听方法
boards[i][j].addActionListener(this);
}
}
//设置窗体的关闭方式
setDefaultCloseOperation(EXIT_ON_CLOSE);
//设置窗体可见
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
//获取点击的按钮
JButton clickBtn = (JButton) e.getSource();
//找到落子的位置
int[] places = location(clickBtn);
int i = places[0];
int j = places[1];
//判断当前位置是否落子
if(place[i][j] == 1 || place[i][j] == -1){
JOptionPane.showMessageDialog(this, "该处已经落子,请选择其他位置!");
return ;
}
//下棋
play(clickBtn, i, j);
//判断输赢
int judge = judge();
if(judge == 1){
JOptionPane.showMessageDialog(this, "X胜利!");
}else if(judge == -1){
JOptionPane.showMessageDialog(this, "O胜利!");
}else if(judge == -2){
return;
}else{
JOptionPane.showMessageDialog(this, "平局!");
}
}
//判断输赢
private int judge(){
int first = place[0][0] + place[0][1] + place[0][2];
int second = place[1][0] + place[1][1] + place[1][2];
int third = place[2][0] + place[2][1] + place[2][2];
int forth = place[0][0] + place[1][0] + place[2][0];
int fifth = place[0][1] + place[1][1] + place[2][1];
int sixth = place[0][2] + place[1][2] + place[2][2];
int seventh = place[0][0] + place[1][1] + place[2][2];
int eighth = place[0][2] + place[1][1] + place[2][0];
if(first == 3 || second == 3 || third == 3 || forth == 3 ||fifth == 3||sixth == 3||seventh == 3||eighth ==3){
return 1;//X胜利
}
else if(first == -3 || second == -3 || third == -3 || forth == -3 ||fifth == -3||sixth == -3||seventh == -3||eighth ==-3){
return -1;//O胜利
}
for (int i = 0; i < 3 ; i++) {
for (int j = 0; j < 3; j++) {
if(place[i][j] == 0)
return -2;//表示继续进行
}
}
return 0;//表示平局
}
//下棋方法
private void play(JButton clickBtn,int i,int j){
if(flag == 0){
clickBtn.setText("X");
flag = 1;
place[i][j] = 1;
}else if(flag == 1){
clickBtn.setText("O");
flag = 0;
place[i][j] = -1;
}
}
//寻找按钮位置
private int[] location(JButton clickBtn){
int[] location = new int[2];//location[0]表示第i行,location[1]表示第j列
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if(boards[i][j] == clickBtn){
location[0] = i;
location[1] = j;
}
}
}
return location;
}
public static void main(String[] args) {
new MyGameWindow();
}
}
8.编写清楚数据方法
以上我们已经基本上实现了井字棋游戏了,但是我们每玩一局都需要重新启动一次程序,这很麻烦,这不是我们想要的。
我们想要每一次游戏结束后,棋盘会自动刷新为最开始的样子,那么我们就可以随心所欲的想下几局就下几局,不想玩的时候直接关闭程序即可。
我们需要清楚两个数据,一个棋盘中的棋子,一个是存储棋子位置的数组。
将其重新初始化,就可以进行下一局游戏了。
//清屏方法
private void clear(){
flag = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
boards[i][j].setText("");
place[i][j] = 0;
}
}
}
最终源代码
这样所有的代码都写完了,是不是很简单。
代码整理如下:
package com.zhang.game;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* @author nanqi-code
* @create 2021/9/1-23:11
*/
public class MyGameWindow extends JFrame implements ActionListener {
//以3行3列数组的形式创建表盘
private JButton[][] boards = new JButton[3][3];
//X先手
private int flag = 0;//flag = 0 表示落子X flag = 1表示落子O
private int[][] place = new int[3][3];//落子X将对应的place设置为1,落子O设置为-1
public MyGameWindow(){
//设置窗口的标题
setTitle("井字棋");
//设置窗体的位置和大小
setBounds(100,100,600,600);
//设置窗体的布局方式
setLayout(new GridLayout(3,3));
//将按钮数组添加到窗体中去并为按钮添加事件监听方法
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//实例化按钮
boards[i][j] = new JButton();
//将按钮添加到窗体中去
add(boards[i][j]);
//为按钮添加时间监听方法
boards[i][j].addActionListener(this);
}
}
//设置窗体的关闭方式
setDefaultCloseOperation(EXIT_ON_CLOSE);
//设置窗体可见
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
//获取点击的按钮
JButton clickBtn = (JButton) e.getSource();
//找到落子的位置
int[] places = location(clickBtn);
int i = places[0];
int j = places[1];
//判断当前位置是否落子
if(place[i][j] == 1 || place[i][j] == -1){
JOptionPane.showMessageDialog(this, "该处已经落子,请选择其他位置!");
return ;
}
//下棋
play(clickBtn, i, j);
//判断输赢
int judge = judge();
if(judge == 1){
JOptionPane.showMessageDialog(this, "X胜利!");
clear();
}else if(judge == -1){
JOptionPane.showMessageDialog(this, "O胜利!");
clear();
}else if(judge == -2){
return;
}else{
JOptionPane.showMessageDialog(this, "平局!");
clear();
}
}
//判断输赢
private int judge(){
int first = place[0][0] + place[0][1] + place[0][2];
int second = place[1][0] + place[1][1] + place[1][2];
int third = place[2][0] + place[2][1] + place[2][2];
int forth = place[0][0] + place[1][0] + place[2][0];
int fifth = place[0][1] + place[1][1] + place[2][1];
int sixth = place[0][2] + place[1][2] + place[2][2];
int seventh = place[0][0] + place[1][1] + place[2][2];
int eighth = place[0][2] + place[1][1] + place[2][0];
if(first == 3 || second == 3 || third == 3 || forth == 3 ||fifth == 3||sixth == 3||seventh == 3||eighth ==3){
return 1;//X胜利
}
else if(first == -3 || second == -3 || third == -3 || forth == -3 ||fifth == -3||sixth == -3||seventh == -3||eighth ==-3){
return -1;//O胜利
}
for (int i = 0; i < 3 ; i++) {
for (int j = 0; j < 3; j++) {
if(place[i][j] == 0)
return -2;//表示继续进行
}
}
return 0;//表示平局
}
//下棋方法
private void play(JButton clickBtn,int i,int j){
if(flag == 0){
clickBtn.setText("X");
flag = 1;
place[i][j] = 1;
}else if(flag == 1){
clickBtn.setText("O");
flag = 0;
place[i][j] = -1;
}
}
//寻找按钮位置
private int[] location(JButton clickBtn){
int[] location = new int[2];//location[0]表示第i行,location[1]表示第j列
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if(boards[i][j] == clickBtn){
location[0] = i;
location[1] = j;
}
}
}
return location;
}
//清屏方法
private void clear(){
flag = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
boards[i][j].setText("");
place[i][j] = 0;
}
}
}
public static void main(String[] args) {
new MyGameWindow();
}
}