五子棋小游戏 java版(代码+详细注释)

article/2025/10/12 15:31:19
游戏展示

        这周闲来无事,再来写个五子棋小游戏。基本功能都实现了,包括人人对战、人机对战。界面布局和功能都写的还行,没做到很优秀,但也不算差。如有需要,做个java初学者的课程设计或者自己写着玩玩也都是不错的(非常简单,小白照着就能写出来)。完整代码在最后,可直接到最后粘贴,代码里面也附有详细的注释,我也会在前面对设计思路和程序的一些地方进行讲解,希望对各位有用。(如果有什么讲的不好的地方,也欢迎大家批评指正...)


目录

游戏展示​编辑

讲解

界面布局

创建窗口

 创建容器面板MPanel继承JPanel

 重写paint方法

放置按钮和JLabel组件

基本功能

画棋子和画选择框

 判断输赢

按钮功能 

五元组算法

代码


游戏展示

共有两种模式,一种人与人下棋,一种为人机对战,人机又分人持黑或持白。在游戏中也有悔棋和重新游戏的功能。大家也都玩过五子棋,这里也没什么特别好讲的。


讲解

这里分三个方面讲,包括界面的布局实现、基本功能的实现,和五元法实现的人机对战。

界面布局

创建窗口

创建一个游戏窗口MFrame,new一个JFrame(也可以直接继承),然后在给它添加一系列属性。

public class MFrame {public static void main(String[] args) {JFrame jf = new JFrame("五子棋小游戏");jf.add(new TablePanel());jf.pack();  //自动适配大小jf.setLocationRelativeTo(null);     //界面居中jf.setResizable(false); //不可调整大小jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //按×关闭jf.setVisible(true);    //是否可见}
}

 创建容器面板TablePanel继承JPanel

设置它的长宽、背景图片和布局方式,布局方式的应用后面会详细讲一下。

public class TablePanel extends JPanel {//Panel的长宽final int TABLE_WIDTH = 700;final int TABLE_HEIGHT = 580;SpringLayout springLayout = new SpringLayout(); //设置springLayout布局,方便按钮位置的部署public TablePanel() {setLayout(springLayout);    //设置弹性布局方式setPreferredSize(new Dimension(TABLE_WIDTH, TABLE_HEIGHT)); //设置组件的首选大小setBackground(Color.green); //设置背景颜色}
}

运行一下,就能得到一个绿色的面板。

 重写paint方法

重写paint方法,后面还有三个方法,分别来画棋盘、棋子和右上角的提示区域。

@Overridepublic void paint(Graphics g) {//定义一个Graphics2DGraphics2D gg = (Graphics2D) g;gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);gg.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);//画棋盘initPaint(g, gg);//画棋子ovalPaint(gg);//画提示框sidePaint(gg);}

这个定义了个Graphics2D,并设置了一些属性,主要是为了消除棋子的锯齿。

效果可以看下面的图,左边是没有消除锯齿的,右边是消除的,可以看到效果还是有点明显的。

 画棋盘

简单的画几条线,稍微的再装饰一下,来画出一个棋盘。

这里面用Graphics2D是为了改变一些线的宽度。

    final int NUM = 15;             //棋盘线的条数final int OFFSET_X = 30;  //棋盘左上角相对于panel左上角的偏移量(棋盘的起始位置)final int OFFSET_Y = 80;final int SP = 33; //棋盘每条线的间隔final int RECT_SIZE = 6;    //棋盘上五个提示点的位置BasicStroke bs; //定义画笔宽度(因为不止一个方法用,就定义在外面)private void initPaint(Graphics g, Graphics2D gg) {super.paint(g);//画棋盘的线g.setColor(Color.BLACK);for (int i = 0; i < NUM; i++) {g.drawLine(OFFSET_X + SP * i, OFFSET_Y, OFFSET_X + SP * i, OFFSET_Y + SP * (NUM - 1));}for (int i = 0; i < NUM; i++) {g.drawLine(OFFSET_X, OFFSET_Y + SP * i, OFFSET_X + SP * (NUM - 1), OFFSET_Y + SP * i);}//加点点缀//五个定位的小方块g.fillRect(OFFSET_X + SP * 3 - RECT_SIZE / 2, OFFSET_Y + SP * 3 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);g.fillRect(OFFSET_X + SP * 11 - RECT_SIZE / 2, OFFSET_Y + SP * 3 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);g.fillRect(OFFSET_X + SP * 3 - RECT_SIZE / 2, OFFSET_Y + SP * 11 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);g.fillRect(OFFSET_X + SP * 11 - RECT_SIZE / 2, OFFSET_Y + SP * 11 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);g.fillRect(OFFSET_X + SP * 7 - RECT_SIZE / 2, OFFSET_Y + SP * 7 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);//再加几条粗一点的线bs = new BasicStroke(3);       // 画笔宽度为5gg.setStroke(bs);gg.drawRect(OFFSET_X - 7, OFFSET_Y - 7, (NUM - 1) * SP + 14, (NUM - 1) * SP + 14);bs = new BasicStroke(2);gg.setStroke(bs);for (int i = 1; i < NUM; i = i + 4) {gg.drawLine(OFFSET_X + SP * i, OFFSET_Y, OFFSET_X + SP * i, OFFSET_Y + SP * (NUM - 1));}for (int i = 1; i < NUM; i = i + 4) {gg.drawLine(OFFSET_X, OFFSET_Y + SP * i, OFFSET_X + SP * (NUM - 1), OFFSET_Y + SP * i);}}

效果如下

 画棋子

主要的实现思路是:定义了一个table二维数组,刷新整个二维数组,里面数值为2的,则在相对应的地方画出黑色棋子;为1则画白色;0则不用管。

    int[][] table = new int[NUM][NUM];  //二维数字记录棋盘上每个位置上的棋子 (0无棋子  1白子  2黑子)final int OVAL_SIZE = 32;   //棋子的大小private void ovalPaint(Graphics2D gg) {//画棋子//每次点击后,会刷新一下棋盘,根据table的值画黑或白字//画实体棋子for (int i = 0; i < NUM; i++) {for (int j = 0; j < NUM; j++) {int x = OFFSET_X + SP * i - OVAL_SIZE / 2;int y = OFFSET_Y + SP * j - OVAL_SIZE / 2;if (table[i][j] == 2) {gg.setColor(Color.BLACK);gg.fillOval(x, y, OVAL_SIZE, OVAL_SIZE);} else if (table[i][j] == 1) {gg.setColor(Color.WHITE);gg.fillOval(x, y, OVAL_SIZE, OVAL_SIZE);} else if (table[i][j] == 3) {gg.setColor(Color.RED);gg.drawOval(x, y, OVAL_SIZE, OVAL_SIZE);}}}}

 画提示框

就是画右上角的一些东西,我也不知道叫啥好,就叫提示区域吧。

根据游戏的进行,来显示出不同的文字。

这里的文字是用drawString()方法写出来的,但是屏幕中另外的字是用JLabel组件实现的。效果差不多,怎么方便怎么来吧!

    int isStart;boolean isWin;int oval_type = 2; //所要下的棋子的颜色 1白 2黑int step;private void sidePaint(Graphics2D gg) {if (isStart != 0) {//开始游戏时if (isWin) {//赢了后gg.setColor((oval_type == 1 ? Color.black : Color.white));gg.setFont(font3);gg.drawString((oval_type == 1 ? "黑方赢" : "白方赢"), 520, 170);} else {//没赢之前gg.setColor(Color.red);gg.setFont(font4);gg.drawString("轮到:", 520, 105);if (oval_type == 2) {gg.setColor(Color.black);} else if (oval_type == 1) {gg.setColor(Color.white);}gg.drawString((oval_type == 2 ? "黑方" : "白方"), 530, 150);gg.fillOval(610, 125, 40, 40);gg.setColor(Color.red);gg.drawString("步数:", 520, 200);gg.setColor(Color.black);gg.drawString(step + "", 620, 200);}} else {gg.setColor(Color.RED);gg.setFont(font4);gg.drawString("请选择游", 525, 150);gg.drawString("戏类型", 525, 190);}}

放置按钮和JLabel组件

创建一些Font 

    Dimension buttonSize = new Dimension(130, 30);    //设置按钮大小//设置字体的形状Font font1 = new Font("华文行楷", Font.PLAIN, 30);Font font2 = new Font("楷体", Font.PLAIN, 20);Font font3 = new Font("华文行楷", Font.PLAIN, 50);Font font4 = new Font("华文行楷", Font.PLAIN, 35);

创建按钮和JLabel组件

    JLabel titleLabel = new JLabel("逗呵呵五子棋");JLabel selectLabel = new JLabel("游戏选择:");JButton rrBtn = new JButton("人人对战");JButton rjbBtn = new JButton("人机.持黑");JButton rjwBtn = new JButton("人机.持白");JLabel elseLabel = new JLabel("其他设置:");JButton regretBtn = new JButton("悔棋");JButton restartBtn = new JButton("重新游戏");JButton endBtn = new JButton("结束游戏");

放置这些组件 

        private void initBtn() {//将button和label设置各自的属性selectLabel.setFont(font1);rrBtn.setPreferredSize(buttonSize);rrBtn.setFont(font2);rjbBtn.setPreferredSize(buttonSize);rjbBtn.setFont(font2);rjwBtn.setPreferredSize(buttonSize);rjwBtn.setFont(font2);elseLabel.setFont(font1);regretBtn.setPreferredSize(buttonSize);regretBtn.setFont(font2);restartBtn.setPreferredSize(buttonSize);restartBtn.setFont(font2);endBtn.setPreferredSize(buttonSize);endBtn.setFont(font2);titleLabel.setFont(font3); // 标题//将其放入add(selectLabel);add(rrBtn);add(rjbBtn);add(rjwBtn);add(elseLabel);add(regretBtn);add(restartBtn);add(endBtn);add(titleLabel);//设置各自的位置,使用弹性布局//将标题放置到中建位置int offsetX = Spring.width(titleLabel).getValue() / 2;springLayout.putConstraint(SpringLayout.WEST, titleLabel, -offsetX,SpringLayout.HORIZONTAL_CENTER, this);springLayout.putConstraint(SpringLayout.NORTH, titleLabel, 10, SpringLayout.NORTH, this);springLayout.putConstraint(SpringLayout.WEST, selectLabel, 525,SpringLayout.WEST, this);springLayout.putConstraint(SpringLayout.NORTH, selectLabel, 260, SpringLayout.NORTH, this);springLayout.putConstraint(SpringLayout.WEST, rrBtn, 5,SpringLayout.WEST, selectLabel);springLayout.putConstraint(SpringLayout.NORTH, rrBtn, 5, SpringLayout.SOUTH, selectLabel);springLayout.putConstraint(SpringLayout.WEST, rjbBtn, 0,SpringLayout.WEST, rrBtn);springLayout.putConstraint(SpringLayout.NORTH, rjbBtn, 5, SpringLayout.SOUTH, rrBtn);springLayout.putConstraint(SpringLayout.WEST, rjwBtn, 0,SpringLayout.WEST, rjbBtn);springLayout.putConstraint(SpringLayout.NORTH, rjwBtn, 5, SpringLayout.SOUTH, rjbBtn);springLayout.putConstraint(SpringLayout.WEST, elseLabel, 0,SpringLayout.WEST, selectLabel);springLayout.putConstraint(SpringLayout.NORTH, elseLabel, 10, SpringLayout.SOUTH, rjwBtn);springLayout.putConstraint(SpringLayout.WEST, regretBtn, 5,SpringLayout.WEST, elseLabel);springLayout.putConstraint(SpringLayout.NORTH, regretBtn, 5, SpringLayout.SOUTH, elseLabel);springLayout.putConstraint(SpringLayout.WEST, restartBtn, 0,SpringLayout.WEST, regretBtn);springLayout.putConstraint(SpringLayout.NORTH, restartBtn, 5, SpringLayout.SOUTH, regretBtn);springLayout.putConstraint(SpringLayout.WEST, endBtn, 0,SpringLayout.WEST, restartBtn);springLayout.putConstraint(SpringLayout.NORTH, endBtn, 5, SpringLayout.SOUTH, restartBtn);}

 写完后效果如下

 这里用的是SpringLayout(弹性布局),个人感觉这个布局还是挺好用的,虽然看起来复杂,用起来还是挺简单的。

拿一个例子来讲一下

        springLayout.putConstraint(SpringLayout.WEST, rrBtn, 5,SpringLayout.WEST, selectLabel);springLayout.putConstraint(SpringLayout.NORTH, rrBtn, 5, SpringLayout.SOUTH, selectLabel);

 这代码是设置rrBtn的位置,即rrBtn组件的西边距离selectLabel组件的西边正5个像素,rrBtn组件的北边距离selectLabel的南边正5个像素。(还是比较简单的吧,只是看着比较多)

布局到这就完成了,要是觉得不好看,自己也可以改,我个人感觉还是能看的。

基本功能

也没啥什么复杂的功能,也就包括画出棋子,画选择框,判断输赢,还有按钮的一些功能。

画棋子和画选择框

创建鼠标事件

MouseAdapter mouseAdapter = new MouseAdapter() {};

 重写mouseClicked()方法

基本思路是,获得鼠标的xy值,在棋盘区域内,则讲鼠标的xy转换为二维数组的行和列,当点击时,将二维数组该处的值设置为2或者1,然后重绘画布。下完后改变棋子类型(oval_type)以便改变颜色。随着棋子的下出,改变提示框响应的内容。根据选择类型的不同,来确定下棋的方法,大体上是相同的,看看代码应该也能明白,这里写的有点乱,各位可以自己优化一下。(能用就好)

        @Overridepublic void mouseClicked(MouseEvent e) {//赢的时候不能用if (!isWin) {if (isStart == 1) {//来判断是否在棋盘内if (e.getX() > OFFSET_X - OVAL_SIZE / 2 && e.getX() < OFFSET_X + (NUM - 1) * SP + OVAL_SIZE / 2&& e.getY() > OFFSET_Y - OVAL_SIZE / 2 && e.getY() < OFFSET_Y + (NUM - 1) * SP + OVAL_SIZE / 2) {//将坐标转换为二维数组的i和jmouse_X = (e.getX() - OFFSET_X + OVAL_SIZE / 2) / SP;mouse_Y = (e.getY() - OFFSET_Y + OVAL_SIZE / 2) / SP;if (table[mouse_X][mouse_Y] == 0) {table[mouse_X][mouse_Y] = oval_type;if (oval_type == 2) {oval_type = 1;step++; //根据黑棋下的次数来增加总步数} else if (oval_type == 1) {oval_type = 2;}last_xy.add(mouse_X);last_xy.add(mouse_Y);//如果下了棋子,才能使用悔棋和重新游戏的按钮restartBtn.setEnabled(true);regretBtn.setEnabled(true);judge(oval_type % 2 + 1, mouse_X, mouse_Y);}repaint();}} else if (isStart == 2) {if (e.getX() > OFFSET_X - OVAL_SIZE / 2 && e.getX() < OFFSET_X + (NUM - 1) * SP + OVAL_SIZE / 2&& e.getY() > OFFSET_Y - OVAL_SIZE / 2 && e.getY() < OFFSET_Y + (NUM - 1) * SP + OVAL_SIZE / 2) {mouse_X = (e.getX() - OFFSET_X + OVAL_SIZE / 2) / SP;mouse_Y = (e.getY() - OFFSET_Y + OVAL_SIZE / 2) / SP;if (table[mouse_X][mouse_Y] == 0) {table[mouse_X][mouse_Y] = 2;oval_type = 1;last_xy.add(mouse_X);last_xy.add(mouse_Y);repaint();judge(2, mouse_X, mouse_Y);if (!isWin) {machine();table[robot_x][robot_y] = 1;oval_type = 2;judge(1, robot_x, robot_y);last_xy.add(robot_x);last_xy.add(robot_y);}step++;restartBtn.setEnabled(true);regretBtn.setEnabled(true);}}} else if (isStart == 3) {if (e.getX() > OFFSET_X - OVAL_SIZE / 2 && e.getX() < OFFSET_X + (NUM - 1) * SP + OVAL_SIZE / 2&& e.getY() > OFFSET_Y - OVAL_SIZE / 2 && e.getY() < OFFSET_Y + (NUM - 1) * SP + OVAL_SIZE / 2) {mouse_X = (e.getX() - OFFSET_X + OVAL_SIZE / 2) / SP;mouse_Y = (e.getY() - OFFSET_Y + OVAL_SIZE / 2) / SP;if (table[mouse_X][mouse_Y] == 0) {table[mouse_X][mouse_Y] = 1;oval_type = 2;last_xy.add(mouse_X);last_xy.add(mouse_Y);repaint();judge(1, mouse_X, mouse_Y);if (!isWin) {machine();table[robot_x][robot_y] = 2;oval_type = 1;judge(2, robot_x, robot_y);last_xy.add(robot_x);last_xy.add(robot_y);}step++;restartBtn.setEnabled(true);regretBtn.setEnabled(true);}}}}}

重写mouseMoved()方法

用来画红色的框框,也是比较简单的,和画棋子差不多。

        @Overridepublic void mouseMoved(MouseEvent e) {if (!isWin) {if (isStart > 0) {if (e.getX() > OFFSET_X - OVAL_SIZE / 2 && e.getX() < OFFSET_X + (NUM - 1) * SP + OVAL_SIZE / 2&& e.getY() > OFFSET_Y - OVAL_SIZE / 2 && e.getY() < OFFSET_Y + (NUM - 1) * SP + OVAL_SIZE / 2) {select_X = (e.getX() - OFFSET_X + OVAL_SIZE / 2) / SP;select_Y = (e.getY() - OFFSET_Y + OVAL_SIZE / 2) / SP;} else {select_X = -10;select_Y = -10;}}}repaint();}

 判断输赢

思路:判断下的位置的四个方向上是否有五个一样的。

    private void judge(int type, int x, int y) {//传入参数,来判断是黑(2)或白(1)子int sum;//判断四个方向//1.左 右sum = 0;for (int k = x - 1; k >= 0; k--) {if (table[k][y] == type) {sum++;} else {break;}}for (int k = x + 1; k < NUM; k++) {if (table[k][y] == type) {sum++;} else {break;}}if (sum >= 4) {isWin = true;return;}//2.上 下sum = 0;for (int k = y - 1; k >= 0; k--) {if (table[x][k] == type) {sum++;} else {break;}}for (int k = y + 1; k < NUM; k++) {if (table[x][k] == type) {sum++;} else {break;}}if (sum >= 4) {isWin = true;return;}//3。左上 右下sum = 0;for (int i = x - 1, j = y - 1; i >= 0 && j >= 0; i--, j--) {if (table[i][j] == type) {sum++;} else {break;}}for (int i = x + 1, j = y + 1; i < NUM && j < NUM; i++, j++) {if (table[i][j] == type)sum++;else {break;}}if (sum >= 4) {isWin = true;return;}//3。右上 左下sum = 0;for (int i = x - 1, j = y + 1; i >= 0 && j < NUM; i--, j++) {if (table[i][j] == type) {sum++;} else {break;}}for (int i = x + 1, j = y - 1; i < NUM && j >= 0; i++, j--) {if (table[i][j] == type)sum++;else {break;}}if (sum >= 4) {isWin = true;//return;}}

按钮功能 

每次进行点击后,改变某些属性的值,并重绘画布。

也没有啥难点。在改变按键是否可用的功能时已经晚上了,脑袋昏昏的,就哪里需要就加在哪里,使用可能导致全部代码里好多地方都有这些方法,各位也是可以自己优化的。

    ActionListener actionListener = new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JButton jButton = (JButton) e.getSource();String text = jButton.getText();if ("重新游戏".equals(text)) {init();if(isStart==3){machine();step++;table[robot_x][robot_y] = 2;oval_type = 1;}regretBtn.setEnabled(false);restartBtn.setEnabled(false);} else if ("悔棋".equals(text)) {int x = last_xy.get(last_xy.size() - 2);int y = last_xy.get(last_xy.size() - 1);table[x][y] = 0;last_xy.remove(last_xy.size() - 2);last_xy.remove(last_xy.size() - 1);oval_type = oval_type % 2 + 1;if (isStart == 2 || isStart == 3) {x = last_xy.get(last_xy.size() - 2);y = last_xy.get(last_xy.size() - 1);table[x][y] = 0;last_xy.remove(last_xy.size() - 2);last_xy.remove(last_xy.size() - 1);oval_type = oval_type % 2 + 1;}if (oval_type == 2||isStart==3) {step--;}if (isWin) {isWin = false;}if (last_xy.size() == 0) {regretBtn.setEnabled(false);restartBtn.setEnabled(false);}} else if ("结束游戏".equals(text)) {isStart = 0;init();rrBtn.setEnabled(true);rjbBtn.setEnabled(true);rjwBtn.setEnabled(true);regretBtn.setEnabled(false);restartBtn.setEnabled(false);endBtn.setEnabled(false);} else {//上面三个按钮if ("人人对战".equals(text)) {isStart = 1;} else if ("人机.持黑".equals(text)) {isStart = 2;} else if ("人机.持白".equals(text)) {isStart = 3;machine();step++;table[robot_x][robot_y] = 2;oval_type = 1;}rrBtn.setEnabled(false);rjbBtn.setEnabled(false);rjwBtn.setEnabled(false);endBtn.setEnabled(true);}repaint();}};

五元组算法

这也是我在别人博客里面看到的方法,大家可以自行搜索详细的学习。

参考:五元组评价算法实现简易五子棋【人工智能】_YouthUpward的博客-CSDN博客_五元组算法

简单来讲,就是根据不同的情况给每个棋子赋值。我按照网上给的分值写了一下,虽然是做出来了,但感觉不是很强,不知道是哪里写错了还是怎么回事。

代码如下,供各位参考

     private void machine() {//传入棋子种类,判断颜色int[][] ts = new int[NUM][NUM]; //来记录每个点上的得分for (int i = 0; i < NUM; i++) {for (int j = 0; j < NUM; j++) {ts[i][j] = 0;}}int wn; //白色个数int bn; //黑色个数//分4种情况//横向for (int i = 0; i < NUM; i++) {for (int j = 0; j < NUM - 4; j++) {wn = 0;bn = 0;//5个for (int k = j; k < j + 5; k++) {if (table[i][k] == 1) {wn++;} else if (table[i][k] == 2) {bn++;}}for (int k = j; k < j + 5; k++) {if (table[i][k] == 0) {ts[i][k] += score(wn, bn);}}}}//纵向for (int j = 0; j < NUM; j++) {for (int i = 0; i < NUM - 4; i++) {wn = 0;bn = 0;for (int k = i; k < i + 5; k++) {if (table[k][j] == 1) {wn++;} else if (table[k][i] == 2) {bn++;}}for (int k = i; k < i + 5; k++) {if (table[k][i] == 0) {ts[k][i] += score(wn, bn);}}}}//左上 右下for (int i = 0; i < NUM - 4; i++) {for (int j = 0; j < NUM - 4; j++) {wn = 0;bn = 0;for (int ki = i, kj = j; ki < i + 5; ki++, kj++) {if (table[ki][kj] == 1) {wn++;} else if (table[ki][kj] == 2) {bn++;}}for (int ki = i, kj = j; ki < i + 5; ki++, kj++) {if (table[ki][kj] == 0) {ts[ki][kj] += score(wn, bn);}}}}//右上 左下for (int i = 4; i < NUM; i++) {for (int j = 0; j < NUM - 4; j++) {wn = 0;bn = 0;for (int ki = i, kj = j; kj < j + 5; ki--, kj++) {if (table[ki][kj] == 1) {wn++;} else if (table[ki][kj] == 2) {bn++;}}for (int ki = i, kj = j; kj < j + 5; ki--, kj++) {if (table[ki][kj] == 0) {ts[ki][kj] += score(wn, bn);}}}}Vector<Integer> vv = new Vector<>();int max = Integer.MIN_VALUE;for (int i = 0; i < NUM; i++) {for (int j = 0; j < NUM; j++) {if (ts[i][j] > max) {max = ts[i][j];}}}for (int i = 0; i < NUM; i++) {for (int j = 0; j < NUM; j++) {if (ts[i][j] == max) {vv.add(i);vv.add(j);}}}Random random = new Random();int r = random.nextInt(vv.size() / 2);robot_x = vv.get(r * 2);robot_y = vv.get(r * 2 + 1);vv.clear();}private int score(int w, int b) {if (w > 0 && b > 0) {return 0;}if (w == 0 && b == 0) {return 7;}if (w == 1) {return 35;}if (w == 2) {return 800;}if (w == 3) {return 15000;}if (w == 4) {return 800000;}if (b == 1) {return 15;}if (b == 2) {return 400;}if (b == 3) {return 1800;}if (b == 4) {return 100000;}return -1;}

代码

TablePanel.java

package game_gobang;import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import java.util.Vector;public class TablePanel extends JPanel {//Panel的大小final int TABLE_WIDTH = 700;final int TABLE_HEIGHT = 580;final int NUM = 15;             //棋盘线的条数final int OFFSET_X = 30;  //棋盘左上角相对于panel左上角的偏移量(棋盘的起始位置)final int OFFSET_Y = 80;final int SP = 33; //棋盘每条线的间隔final int RECT_SIZE = 6;    //棋盘上五个提示点的位置final int OVAL_SIZE = 32;   //棋子的大小int[][] table = new int[NUM][NUM];  //二维数字记录棋盘上每个位置上的棋子 (0无棋子  1白子  2黑子)int step;int oval_type = 2; //所要下的棋子的颜色 1白 2黑int mouse_X;int mouse_Y;int select_X = -10;int select_Y = -10;//定义一个Vector,存储每次下的位置,来实现悔棋功能Vector<Integer> last_xy = new Vector<>();boolean isWin;  //是否赢int isStart;    //是否开始游戏 0未开始 1 2 3int robot_x;int robot_y;BasicStroke bs; //定义画笔宽度(因为不止一个方法用,就定义在外面)SpringLayout springLayout = new SpringLayout(); //设置springLayout布局,方便按钮位置的部署Dimension buttonSize = new Dimension(130, 30);    //设置按钮大小//设置字体的形状Font font1 = new Font("华文行楷", Font.PLAIN, 30);Font font2 = new Font("楷体", Font.PLAIN, 20);Font font3 = new Font("华文行楷", Font.PLAIN, 50);Font font4 = new Font("华文行楷", Font.PLAIN, 35);//定义一系列button和labelJLabel titleLabel = new JLabel("逗呵呵五子棋");JLabel selectLabel = new JLabel("游戏选择:");JButton rrBtn = new JButton("人人对战");JButton rjbBtn = new JButton("人机.持黑");JButton rjwBtn = new JButton("人机.持白");JLabel elseLabel = new JLabel("其他设置:");JButton regretBtn = new JButton("悔棋");JButton restartBtn = new JButton("重新游戏");JButton endBtn = new JButton("结束游戏");public TablePanel() {setLayout(springLayout);    //设置弹性布局方式setPreferredSize(new Dimension(TABLE_WIDTH, TABLE_HEIGHT)); //设置组件的首选大小setBackground(Color.green); //设置背景颜色initBtn();  //初始化按钮init(); //初始化一些属性isStart = 0;addMouseListener(mouseAdapter); //添加鼠标监听addMouseMotionListener(mouseAdapter);}//初始化一些属性private void init() {//初始化二维数组for (int i = 0; i < NUM; i++) {for (int j = 0; j < NUM; j++) {table[i][j] = 0;}}//初始化stepstep = 0;isWin = false;oval_type = 2;//初始化listlast_xy.clear();}@Overridepublic void paint(Graphics g) {//定义一个Graphics2DGraphics2D gg = (Graphics2D) g;gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);gg.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);//画棋盘initPaint(g, gg);//画棋子ovalPaint(gg);//画提示框sidePaint(gg);}private void ovalPaint(Graphics2D gg) {//画棋子//每次点击后,会刷新一下棋盘,根据table的值画黑或白字//画实体棋子for (int i = 0; i < NUM; i++) {for (int j = 0; j < NUM; j++) {int x = OFFSET_X + SP * i - OVAL_SIZE / 2;int y = OFFSET_Y + SP * j - OVAL_SIZE / 2;if (table[i][j] == 2) {gg.setColor(Color.BLACK);gg.fillOval(x, y, OVAL_SIZE, OVAL_SIZE);} else if (table[i][j] == 1) {gg.setColor(Color.WHITE);gg.fillOval(x, y, OVAL_SIZE, OVAL_SIZE);} else if (table[i][j] == 3) {gg.setColor(Color.RED);gg.drawOval(x, y, OVAL_SIZE, OVAL_SIZE);}}}if (isWin) {//赢了就把选择框隐藏起来select_X = -10;select_Y = -10;} else {bs = new BasicStroke(1);       // 画笔宽度为1gg.setStroke(bs);//画选择框gg.setColor(Color.RED);gg.drawOval(OFFSET_X + SP * select_X - OVAL_SIZE / 2,OFFSET_Y + SP * select_Y - OVAL_SIZE / 2,OVAL_SIZE, OVAL_SIZE);}}//画棋盘private void initPaint(Graphics g, Graphics2D gg) {super.paint(g);//画棋盘的线g.setColor(Color.BLACK);for (int i = 0; i < NUM; i++) {g.drawLine(OFFSET_X + SP * i, OFFSET_Y, OFFSET_X + SP * i, OFFSET_Y + SP * (NUM - 1));}for (int i = 0; i < NUM; i++) {g.drawLine(OFFSET_X, OFFSET_Y + SP * i, OFFSET_X + SP * (NUM - 1), OFFSET_Y + SP * i);}//加点点缀//五个定位的小方块g.fillRect(OFFSET_X + SP * 3 - RECT_SIZE / 2, OFFSET_Y + SP * 3 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);g.fillRect(OFFSET_X + SP * 11 - RECT_SIZE / 2, OFFSET_Y + SP * 3 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);g.fillRect(OFFSET_X + SP * 3 - RECT_SIZE / 2, OFFSET_Y + SP * 11 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);g.fillRect(OFFSET_X + SP * 11 - RECT_SIZE / 2, OFFSET_Y + SP * 11 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);g.fillRect(OFFSET_X + SP * 7 - RECT_SIZE / 2, OFFSET_Y + SP * 7 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);//再加几条粗一点的线bs = new BasicStroke(3);       // 画笔宽度为5gg.setStroke(bs);gg.drawRect(OFFSET_X - 7, OFFSET_Y - 7, (NUM - 1) * SP + 14, (NUM - 1) * SP + 14);bs = new BasicStroke(2);gg.setStroke(bs);for (int i = 1; i < NUM; i = i + 4) {gg.drawLine(OFFSET_X + SP * i, OFFSET_Y, OFFSET_X + SP * i, OFFSET_Y + SP * (NUM - 1));}for (int i = 1; i < NUM; i = i + 4) {gg.drawLine(OFFSET_X, OFFSET_Y + SP * i, OFFSET_X + SP * (NUM - 1), OFFSET_Y + SP * i);}}//画侧面(右上角)的提示框private void sidePaint(Graphics2D gg) {if (isStart != 0) {//开始游戏时if (isWin) {//赢了后gg.setColor((oval_type == 1 ? Color.black : Color.white));gg.setFont(font3);gg.drawString((oval_type == 1 ? "黑方赢" : "白方赢"), 520, 170);} else {//没赢之前gg.setColor(Color.red);gg.setFont(font4);gg.drawString("轮到:", 520, 105);if (oval_type == 2) {gg.setColor(Color.black);} else if (oval_type == 1) {gg.setColor(Color.white);}gg.drawString((oval_type == 2 ? "黑方" : "白方"), 530, 150);gg.fillOval(610, 125, 40, 40);gg.setColor(Color.red);gg.drawString("步数:", 520, 200);gg.setColor(Color.black);gg.drawString(step + "", 620, 200);}} else {gg.setColor(Color.RED);gg.setFont(font4);gg.drawString("请选择游", 525, 150);gg.drawString("戏类型", 525, 190);}}private void initBtn() {//将button和label设置各自的属性selectLabel.setFont(font1);rrBtn.setPreferredSize(buttonSize);rrBtn.setFont(font2);rjbBtn.setPreferredSize(buttonSize);rjbBtn.setFont(font2);rjwBtn.setPreferredSize(buttonSize);rjwBtn.setFont(font2);elseLabel.setFont(font1);regretBtn.setPreferredSize(buttonSize);regretBtn.setFont(font2);restartBtn.setPreferredSize(buttonSize);restartBtn.setFont(font2);endBtn.setPreferredSize(buttonSize);endBtn.setFont(font2);titleLabel.setFont(font3); // 标题//给按钮加上监听rrBtn.addActionListener(actionListener);rjbBtn.addActionListener(actionListener);rjwBtn.addActionListener(actionListener);regretBtn.addActionListener(actionListener);restartBtn.addActionListener(actionListener);endBtn.addActionListener(actionListener);//将其放入add(selectLabel);add(rrBtn);add(rjbBtn);add(rjwBtn);add(elseLabel);add(regretBtn);add(restartBtn);add(endBtn);add(titleLabel);//设置各自的位置,使用弹性布局//将标题放置到中建位置int offsetX = Spring.width(titleLabel).getValue() / 2;springLayout.putConstraint(SpringLayout.WEST, titleLabel, -offsetX,SpringLayout.HORIZONTAL_CENTER, this);springLayout.putConstraint(SpringLayout.NORTH, titleLabel, 10, SpringLayout.NORTH, this);springLayout.putConstraint(SpringLayout.WEST, selectLabel, 525,SpringLayout.WEST, this);springLayout.putConstraint(SpringLayout.NORTH, selectLabel, 260, SpringLayout.NORTH, this);springLayout.putConstraint(SpringLayout.WEST, rrBtn, 5,SpringLayout.WEST, selectLabel);springLayout.putConstraint(SpringLayout.NORTH, rrBtn, 5, SpringLayout.SOUTH, selectLabel);springLayout.putConstraint(SpringLayout.WEST, rjbBtn, 0,SpringLayout.WEST, rrBtn);springLayout.putConstraint(SpringLayout.NORTH, rjbBtn, 5, SpringLayout.SOUTH, rrBtn);springLayout.putConstraint(SpringLayout.WEST, rjwBtn, 0,SpringLayout.WEST, rjbBtn);springLayout.putConstraint(SpringLayout.NORTH, rjwBtn, 5, SpringLayout.SOUTH, rjbBtn);springLayout.putConstraint(SpringLayout.WEST, elseLabel, 0,SpringLayout.WEST, selectLabel);springLayout.putConstraint(SpringLayout.NORTH, elseLabel, 10, SpringLayout.SOUTH, rjwBtn);springLayout.putConstraint(SpringLayout.WEST, regretBtn, 5,SpringLayout.WEST, elseLabel);springLayout.putConstraint(SpringLayout.NORTH, regretBtn, 5, SpringLayout.SOUTH, elseLabel);springLayout.putConstraint(SpringLayout.WEST, restartBtn, 0,SpringLayout.WEST, regretBtn);springLayout.putConstraint(SpringLayout.NORTH, restartBtn, 5, SpringLayout.SOUTH, regretBtn);springLayout.putConstraint(SpringLayout.WEST, endBtn, 0,SpringLayout.WEST, restartBtn);springLayout.putConstraint(SpringLayout.NORTH, endBtn, 5, SpringLayout.SOUTH, restartBtn);regretBtn.setEnabled(false);restartBtn.setEnabled(false);endBtn.setEnabled(false);}ActionListener actionListener = new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JButton jButton = (JButton) e.getSource();String text = jButton.getText();if ("重新游戏".equals(text)) {init();if(isStart==3){machine();step++;table[robot_x][robot_y] = 2;oval_type = 1;}regretBtn.setEnabled(false);restartBtn.setEnabled(false);} else if ("悔棋".equals(text)) {int x = last_xy.get(last_xy.size() - 2);int y = last_xy.get(last_xy.size() - 1);table[x][y] = 0;last_xy.remove(last_xy.size() - 2);last_xy.remove(last_xy.size() - 1);oval_type = oval_type % 2 + 1;if (isStart == 2 || isStart == 3) {x = last_xy.get(last_xy.size() - 2);y = last_xy.get(last_xy.size() - 1);table[x][y] = 0;last_xy.remove(last_xy.size() - 2);last_xy.remove(last_xy.size() - 1);oval_type = oval_type % 2 + 1;}if (oval_type == 2||isStart==3) {step--;}if (isWin) {isWin = false;}if (last_xy.size() == 0) {regretBtn.setEnabled(false);restartBtn.setEnabled(false);}} else if ("结束游戏".equals(text)) {isStart = 0;init();rrBtn.setEnabled(true);rjbBtn.setEnabled(true);rjwBtn.setEnabled(true);regretBtn.setEnabled(false);restartBtn.setEnabled(false);endBtn.setEnabled(false);} else {//上面三个按钮if ("人人对战".equals(text)) {isStart = 1;} else if ("人机.持黑".equals(text)) {isStart = 2;} else if ("人机.持白".equals(text)) {isStart = 3;machine();step++;table[robot_x][robot_y] = 2;oval_type = 1;}rrBtn.setEnabled(false);rjbBtn.setEnabled(false);rjwBtn.setEnabled(false);endBtn.setEnabled(true);}repaint();}};MouseAdapter mouseAdapter = new MouseAdapter() {@Overridepublic void mouseClicked(MouseEvent e) {//赢的时候不能用if (!isWin) {if (isStart == 1) {//来判断是否在棋盘内if (e.getX() > OFFSET_X - OVAL_SIZE / 2 && e.getX() < OFFSET_X + (NUM - 1) * SP + OVAL_SIZE / 2&& e.getY() > OFFSET_Y - OVAL_SIZE / 2 && e.getY() < OFFSET_Y + (NUM - 1) * SP + OVAL_SIZE / 2) {//将坐标转换为二维数组的i和jmouse_X = (e.getX() - OFFSET_X + OVAL_SIZE / 2) / SP;mouse_Y = (e.getY() - OFFSET_Y + OVAL_SIZE / 2) / SP;if (table[mouse_X][mouse_Y] == 0) {table[mouse_X][mouse_Y] = oval_type;if (oval_type == 2) {oval_type = 1;step++; //根据黑棋下的次数来增加总步数} else if (oval_type == 1) {oval_type = 2;}last_xy.add(mouse_X);last_xy.add(mouse_Y);//如果下了棋子,才能使用悔棋和重新游戏的按钮restartBtn.setEnabled(true);regretBtn.setEnabled(true);judge(oval_type % 2 + 1, mouse_X, mouse_Y);}repaint();}} else if (isStart == 2) {if (e.getX() > OFFSET_X - OVAL_SIZE / 2 && e.getX() < OFFSET_X + (NUM - 1) * SP + OVAL_SIZE / 2&& e.getY() > OFFSET_Y - OVAL_SIZE / 2 && e.getY() < OFFSET_Y + (NUM - 1) * SP + OVAL_SIZE / 2) {mouse_X = (e.getX() - OFFSET_X + OVAL_SIZE / 2) / SP;mouse_Y = (e.getY() - OFFSET_Y + OVAL_SIZE / 2) / SP;if (table[mouse_X][mouse_Y] == 0) {table[mouse_X][mouse_Y] = 2;oval_type = 1;last_xy.add(mouse_X);last_xy.add(mouse_Y);repaint();judge(2, mouse_X, mouse_Y);if (!isWin) {machine();table[robot_x][robot_y] = 1;oval_type = 2;judge(1, robot_x, robot_y);last_xy.add(robot_x);last_xy.add(robot_y);}step++;restartBtn.setEnabled(true);regretBtn.setEnabled(true);}}} else if (isStart == 3) {if (e.getX() > OFFSET_X - OVAL_SIZE / 2 && e.getX() < OFFSET_X + (NUM - 1) * SP + OVAL_SIZE / 2&& e.getY() > OFFSET_Y - OVAL_SIZE / 2 && e.getY() < OFFSET_Y + (NUM - 1) * SP + OVAL_SIZE / 2) {mouse_X = (e.getX() - OFFSET_X + OVAL_SIZE / 2) / SP;mouse_Y = (e.getY() - OFFSET_Y + OVAL_SIZE / 2) / SP;if (table[mouse_X][mouse_Y] == 0) {table[mouse_X][mouse_Y] = 1;oval_type = 2;last_xy.add(mouse_X);last_xy.add(mouse_Y);repaint();judge(1, mouse_X, mouse_Y);if (!isWin) {machine();table[robot_x][robot_y] = 2;oval_type = 1;judge(2, robot_x, robot_y);last_xy.add(robot_x);last_xy.add(robot_y);}step++;restartBtn.setEnabled(true);regretBtn.setEnabled(true);}}}}}@Overridepublic void mouseMoved(MouseEvent e) {if (!isWin) {if (isStart > 0) {if (e.getX() > OFFSET_X - OVAL_SIZE / 2 && e.getX() < OFFSET_X + (NUM - 1) * SP + OVAL_SIZE / 2&& e.getY() > OFFSET_Y - OVAL_SIZE / 2 && e.getY() < OFFSET_Y + (NUM - 1) * SP + OVAL_SIZE / 2) {select_X = (e.getX() - OFFSET_X + OVAL_SIZE / 2) / SP;select_Y = (e.getY() - OFFSET_Y + OVAL_SIZE / 2) / SP;} else {select_X = -10;select_Y = -10;}}}repaint();}};//判断谁赢,扫描整个棋盘,来判断是否练成五个private void judge(int type, int x, int y) {//传入参数,来判断是黑(2)或白(1)子int sum;//判断四个方向//1.左 右sum = 0;for (int k = x - 1; k >= 0; k--) {if (table[k][y] == type) {sum++;} else {break;}}for (int k = x + 1; k < NUM; k++) {if (table[k][y] == type) {sum++;} else {break;}}if (sum >= 4) {isWin = true;return;}//2.上 下sum = 0;for (int k = y - 1; k >= 0; k--) {if (table[x][k] == type) {sum++;} else {break;}}for (int k = y + 1; k < NUM; k++) {if (table[x][k] == type) {sum++;} else {break;}}if (sum >= 4) {isWin = true;return;}//3。左上 右下sum = 0;for (int i = x - 1, j = y - 1; i >= 0 && j >= 0; i--, j--) {if (table[i][j] == type) {sum++;} else {break;}}for (int i = x + 1, j = y + 1; i < NUM && j < NUM; i++, j++) {if (table[i][j] == type)sum++;else {break;}}if (sum >= 4) {isWin = true;return;}//3。右上 左下sum = 0;for (int i = x - 1, j = y + 1; i >= 0 && j < NUM; i--, j++) {if (table[i][j] == type) {sum++;} else {break;}}for (int i = x + 1, j = y - 1; i < NUM && j >= 0; i++, j--) {if (table[i][j] == type)sum++;else {break;}}if (sum >= 4) {isWin = true;//return;}}//来写自动下棋的方法private void machine() {//传入棋子种类,判断颜色int[][] ts = new int[NUM][NUM]; //来记录每个点上的得分for (int i = 0; i < NUM; i++) {for (int j = 0; j < NUM; j++) {ts[i][j] = 0;}}int wn; //白色个数int bn; //黑色个数//分4种情况//横向for (int i = 0; i < NUM; i++) {for (int j = 0; j < NUM - 4; j++) {wn = 0;bn = 0;//5个for (int k = j; k < j + 5; k++) {if (table[i][k] == 1) {wn++;} else if (table[i][k] == 2) {bn++;}}for (int k = j; k < j + 5; k++) {if (table[i][k] == 0) {ts[i][k] += score(wn, bn);}}}}//纵向for (int j = 0; j < NUM; j++) {for (int i = 0; i < NUM - 4; i++) {wn = 0;bn = 0;for (int k = i; k < i + 5; k++) {if (table[k][j] == 1) {wn++;} else if (table[k][i] == 2) {bn++;}}for (int k = i; k < i + 5; k++) {if (table[k][i] == 0) {ts[k][i] += score(wn, bn);}}}}//左上 右下for (int i = 0; i < NUM - 4; i++) {for (int j = 0; j < NUM - 4; j++) {wn = 0;bn = 0;for (int ki = i, kj = j; ki < i + 5; ki++, kj++) {if (table[ki][kj] == 1) {wn++;} else if (table[ki][kj] == 2) {bn++;}}for (int ki = i, kj = j; ki < i + 5; ki++, kj++) {if (table[ki][kj] == 0) {ts[ki][kj] += score(wn, bn);}}}}//右上 左下for (int i = 4; i < NUM; i++) {for (int j = 0; j < NUM - 4; j++) {wn = 0;bn = 0;for (int ki = i, kj = j; kj < j + 5; ki--, kj++) {if (table[ki][kj] == 1) {wn++;} else if (table[ki][kj] == 2) {bn++;}}for (int ki = i, kj = j; kj < j + 5; ki--, kj++) {if (table[ki][kj] == 0) {ts[ki][kj] += score(wn, bn);}}}}Vector<Integer> vv = new Vector<>();int max = Integer.MIN_VALUE;for (int i = 0; i < NUM; i++) {for (int j = 0; j < NUM; j++) {if (ts[i][j] > max) {max = ts[i][j];}}}for (int i = 0; i < NUM; i++) {for (int j = 0; j < NUM; j++) {if (ts[i][j] == max) {vv.add(i);vv.add(j);}}}Random random = new Random();int r = random.nextInt(vv.size() / 2);robot_x = vv.get(r * 2);robot_y = vv.get(r * 2 + 1);vv.clear();}private int score(int w, int b) {if (w > 0 && b > 0) {return 0;}if (w == 0 && b == 0) {return 7;}if (w == 1) {return 35;}if (w == 2) {return 800;}if (w == 3) {return 15000;}if (w == 4) {return 800000;}if (b == 1) {return 15;}if (b == 2) {return 400;}if (b == 3) {return 1800;}if (b == 4) {return 100000;}return -1;}
}

MFrame.java

package game_gobang;import javax.swing.*;public class MFrame {public static void main(String[] args) {JFrame jf = new JFrame("五子棋小游戏");jf.add(new TablePanel());jf.pack();  //自动适配大小jf.setLocationRelativeTo(null);     //居中jf.setResizable(false); //不可调整大小jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //按×关闭jf.setVisible(true);    //是否可见}
}


http://chatgpt.dhexx.cn/article/13i7AsTp.shtml

相关文章

【Java实现小游戏】飞翔的小鸟(源码)

游戏玩法&#xff1a;通过鼠标点击使小鸟上下移动穿过柱子并完成得分&#xff0c;小鸟碰到柱子或掉落到地面上都会结束游戏。 &#xff08;游戏内图片&#xff09; 下面是实现这个游戏的代码&#xff1a; Brid类&#xff1a; package bird;import org.omg.CORBA.IMP_LIMIT;im…

用简单Java代码尝试在控制台写游戏(附源码)

尝试写了一个在Java控制台运行的代码游戏&#xff0c;由于写这个的时候&#xff0c;博主还没学到可视化界面&#xff0c;也没有学到面向对象&#xff0c;甚至没有集合&#xff0c;运用的全是之前C语言的语法&#xff0c;因此应该很容易看懂吧。末尾附上源码。 以下是效果展示 …

Java小游戏练习---超级玛丽代码实现

B站教学视频&#xff1a; 01_超级玛丽_创建窗口_哔哩哔哩_bilibili 素材提取&#xff1a; 【超级会员V2】我通过百度网盘分享的文件&#xff1a;Java游戏项目… 链接:百度网盘 请输入提取码 提取码:k6j1 复制这段内容打开「百度网盘APP 即可获取」 百度网盘 请输入提取码 百度…

java 300行代码 冒险闯关小游戏(代码+讲解)

作为一个男孩子&#xff0c;从小就喜欢晚一些游戏。今天就用java写一个类似马里奥的冒险闯关小游戏&#xff0c;但这也不是一两天能完成的事情&#xff0c;我将会持续更新这个游戏&#xff08;有什么好的介意也非常欢迎大家提出来&#xff0c;也能在我的基础上自己接着写&#…

宝塔php防盗链,[宝塔面板]如何开启防盗链?

为了节省建站成本&#xff0c;大多数站长都会选择一些小服务器&#xff0c;在另加CDN、云存储之类的来减轻服务器的压力&#xff0c;但是这类功能大多收费。 如果自己网站的图片都让别人复制图片链接地址&#xff0c;那么自己CDN流量就跑得贼快&#xff0c;花了钱得不到好处。 …

HTTP防盗链(Referer)

HTTP请求防盗链&#xff1a;只允许某些域名请求来源才可以访问。比如A网站有一张图片或音频等资源被B网站直接通过img等标签属性引入使用&#xff0c;这样就是B网站盗用了A网站的资源。那么对于A网站来说&#xff0c;流量怎么被消耗的都不知道。 解决思路&#xff1a; 判断http…

Nginx防盗链的配置

Nginx防盗链的配置 通常站点&#xff0c;都会想让自己网站的视频和图片&#xff0c;免被盗用&#xff0c;毕竟视频流量&#xff0c;花的都是白花花银子   首先我们没有配置防盗链的情况下&#xff0c;放开静态资源你的访问。我们来看看效果 location ~* .*\.(gif|jpg|ico|pn…

python爬虫的防盗链

文章目录 前言一、防盗链是什么&#xff1f;二、 防盗链如何实现三、分析四、 对有防盗链的网站进行爬取对有视频连接的网站发出请求并且获取源码信息提取出我们的视频网站对我们提取的网址进行修改&#xff0c;和拼凑下载视频结束爬取 完整代码 前言 随着python的发展网页的反…

Nginx静态资源防盗链

1.什么是资源盗链 简单地说&#xff0c;就是将别人的资源用到自己的页面展示给用户。 2.效果演示 1&#xff09;准备图片 这两张图片直接在浏览器中访问都是可以打开的。 github图片地址&#xff1a;https://github.githubassets.com/images/modules/site/home-campaign/her…

取消文件服务器防盗链,如何取消防盗链保护

http标准协议中有专门的字段记录referer 一来可以追溯上一个入站地址是什么 二来对于资源文件&#xff0c;可以跟踪到包含显示他的网页地址是什么。 因此所有防盗链方法都是基于这个Referer字段 网上比较多的2种 一种是使用apache文件FileMatch限制&#xff0c;在httpd.conf中增…

视频防盗链

解析器链接&#xff1a; https://www.administratorw.com/index/qqvod.php?url 清晰度高url后面支持mp4、m3u8地址 https://z1.m1907.cn?jx 清晰度底&#xff0c;链接后面只支持电影名 此接口解析出来的m3u8地址为&#xff1a;&#xff08;雄狮少年&#xff09; https…

html 图片防盗链,【反防盗链】介绍一个对付图片防盗链的方法

悲催的声明: 由于腾讯也采用了防盗链技术,本文方法已经失效了! 当我们想在文章里引用某张图片时,如果对方设置了防盗链,我们看到的将是404或forbidden或其他图片,而不是想要的那张图片,为此,我们有无方法进行“反防盗链”呢?答案是有的,本文将介绍一个对付图片防盗链…

简单的视频防盗链

1.使用hls.js播放视频&#xff0c;页面中无法获得视频的src hls.js是视频播放的工具文件&#xff0c;在官网上有播放方式&#xff0c;可以产生如上图所示的效果&#xff0c;没有source标签&#xff0c;也就是说&#xff0c;在页面上隐藏掉了视频的url hls.js文件地址&#xff…

html设置referer防盗链,referer与防盗链

referer是什么 referer 中文意思是:参照页面,引用页。 下图直观感受,(づ ̄ 3 ̄)づ image 直接在浏览器中输入url地址来直接访问图片/js/css等资源时是没有referer的, 如果有referer说明是引用过来的,要么是从HTML页面,要么是通过css @import,再或则通过background(url)引用…

防盗链使用

现在很多网站启用了防盗链反爬&#xff0c;防止服务器上的资源被人恶意盗取。什么是防盗链呢&#xff1f; 以图片为例&#xff0c;访问图片要从他的网站访问才可以&#xff0c;否则直接访问图片地址得不到图片 练习&#xff1a;抓取微博图片&#xff1a;http://blog.sina.com…

nginx配置防盗链

现在流行前后端分离开发的情况下&#xff0c;一般我们都会将静态资源放在nginx的html目录下。这种情况下&#xff0c;我们就无法通过Java代码写拦截器来防盗链了。所以这里我们来说明一下如何使用nginx来配置防盗链。 1.我们先修改本地hosts文件&#xff0c;将 www.czx.com 映…

java防盗链_javaWeb防止恶意登陆或防盗链的使用

使用场景:明明引用了一个正确的图片地址,但显示出来的却是一个红叉或写有“此图片仅限于***网站用户交流沟通使用”之类的“假图片”。用嗅探软件找到了多媒体资源的真实地址用下载软件仍然不能下载。下载一些资源时总是出错,如果确认地址没错的话,大多数情况都是遇上防盗链…

防盗链机制

防盗链机制的几种实现 通常防盗链是为了防止图片&#xff0c;视频被盗用。下面简单介绍几种防盗链的机制&#xff1a; 1. 利用HTTP Referer字段 HTTP请求中会包含来自哪个url的点击来源&#xff0c;通过这个referer字段可以检测是否别的网站发送的请求。 2.利用登录验证信息 有…

网络中的防盗链是指什么?

什么是盗链&#xff1f; 比如,别人上传的东西,你直接拿了LINK去,贴到别的论坛或者网站,宣称"有好东西,快来下载",又或者告诉你的朋友"你要这个文件?俺有连接,快下",然后在那里接受别人的滔滔不绝的景仰之情。 “盗链” 的定义是&#xff1a; 此内容不在…

Nginx防盗链

Nginx防盗链的实现原理&#xff1a; 了解防盗链的原理之前&#xff0c;我们得先学习一个HTTP的头信息Referer,当浏览器向web服务器发送请求的时候&#xff0c;一般都会带上Referer,来告诉浏览器该网页是从哪个页面链接过来的。 后台服务器可以根据获取到的这个Referer信息来判…