发表于: 2017-07-27 05:48:32
2 1069
高亮的问题:
如下图:
书上所说的人工智能怎么应用在本程序中?
一 今天做的事情:
1 在书上所给的程序的基础上完善了五子棋游戏。具体完善的功能:
a 增加了傻瓜式的电脑来求虐。因为电脑是随机产生坐标来下棋,因此很容易赢电脑。好奇上述问题的人工智能能否解决这个问题,变得更聪明一点。
b 解决了用户和电脑能重复下棋的问题;
c 写了扫描谁赢了的程序。
经上述三个功能,基本完善了五子棋程序。结果:
a 横向扫描:
b 纵向扫描:
c 左斜扫描:
d 右斜扫描:
因为书上的一个错误,我耽误了不少的时间,还有就是这个四个for循环真的很绕绕绕人。写完程序天已经亮了。
书上内容:
光盘所给程序:
程序开始符~
import java.io.*;
/**
* Description:
* <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
* <br/>Copyright (C), 2001-2016, Yeeku.H.Lee
* <br/>This program is protected by copyright laws.
* <br/>Program Name:
* <br/>Date:
* @author Yeeku.H.Lee kongyeeku@163.com
* @version 1.0
*/
public class Gobang
{
// 定义棋盘的大小
private static int BOARD_SIZE = 15;
// 定义一个二维数组来充当棋盘
private String[][] board;
public void initBoard()
{
// 初始化棋盘数组
board = new String[BOARD_SIZE][BOARD_SIZE];
// 把每个元素赋为"╋",用于在控制台画出棋盘
for (int i = 0 ; i < BOARD_SIZE ; i++)
{
for ( int j = 0 ; j < BOARD_SIZE ; j++)
{
board[i][j] = "╋";
}
}
}
// 在控制台输出棋盘的方法
public void printBoard()
{
// 打印每个数组元素
for (int i = 0 ; i < BOARD_SIZE ; i++)
{
for ( int j = 0 ; j < BOARD_SIZE ; j++)
{
// 打印数组元素后不换行
System.out.print(board[i][j]);
}
// 每打印完一行数组元素后输出一个换行符
System.out.print("\n");
}
}
public static void main(String[] args) throws Exception
{
Gobang gb = new Gobang();
gb.initBoard();
gb.printBoard();
// 这是用于获取键盘输入的方法
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String inputStr = null;
// br.readLine():每当在键盘上输入一行内容按回车,用户刚输入的内容将被br读取到。
while ((inputStr = br.readLine()) != null)
{
// 将用户输入的字符串以逗号(,)作为分隔符,分隔成2个字符串
String[] posStrArr = inputStr.split(",");
// 将2个字符串转换成用户下棋的座标
int xPos = Integer.parseInt(posStrArr[0]);
int yPos = Integer.parseInt(posStrArr[1]);
// 把对应的数组元素赋为"●"。
gb.board[yPos - 1][xPos - 1] = "●";
/*
电脑随机生成2个整数,作为电脑下棋的座标,赋给board数组。
还涉及
1.座标的有效性,只能是数字,不能超出棋盘范围
2.如果下的棋的点,不能重复下棋。
3.每次下棋后,需要扫描谁赢了
*/
gb.printBoard();
System.out.println("请输入您下棋的座标,应以x,y的格式:");
}
}
}
程序结束符~
我修改后的程序:
程序开始符~
import java.io.*;
public class P104
{
// 定义棋盘的大小
private static int BOARD_SIZE = 15;
// 定义一个二维数组来充当棋盘
private static String[][] board;
public void initBoard()
{
// 初始化棋盘数组
board = new String[BOARD_SIZE][BOARD_SIZE];
// 把每个元素赋为"╋",用于在控制台画出棋盘
for (int i = 0 ; i < BOARD_SIZE ; i++)
{
for ( int j = 0 ; j < BOARD_SIZE ; j++)
{
board[i][j] = "╋";
}
}
}
// 在控制台输出棋盘的方法
public void printBoard()
{
// 打印每个数组元素
for (int i = 0 ; i < BOARD_SIZE ; i++)
{
for ( int j = 0 ; j < BOARD_SIZE ; j++)
{
// 打印数组元素后不换行
System.out.print(board[i][j]);
}
// 每打印完一行数组元素后输出一个换行符
System.out.print("\n");
}
}
public static void main(String[] args) throws Exception
{
P104 gb = new P104();
gb.initBoard();
gb.printBoard();
// 这是用于获取键盘输入的方法
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String inputStr = null;
// br.readLine():每当在键盘上输入一行内容按回车,用户刚输入的内容将被br读取到。
//定义两个二维数组,分别用于存放用户输入的坐标值和电脑随机生成的坐标值,
int[][] man = new int[200][2];
int[][] pc = new int[200][2];
int counter = 0; //计数器
while ((inputStr = br.readLine()) != null)
{
// 将用户输入的字符串以逗号(,)作为分隔符,分隔成2个字符串
String[] posStrArr = inputStr.split(",");
// 将2个字符串转换成用户下棋的座标
counter ++;//计数器加1
int xPos = Integer.parseInt(posStrArr[0]);
int yPos = Integer.parseInt(posStrArr[1]);
man[counter][0] = xPos; //把用户输入的X坐标记录到man数组中
man[counter][1] = yPos; //把用户输入的Y坐标记录到man数组中
int ranx = 1 + (int)(Math.random()*15); //随机生成电脑的x坐标值
int rany = 1 + (int)(Math.random()*15); //随机生成电脑的y坐标值
pc[counter][0] = ranx; //把电脑随机生成的x坐标记录到pc数组中
pc[counter][1] = rany; //把电脑随机生成的y坐标记录到pc数组中
gb.board[ranx - 1][rany - 1] = "○"; //电脑下棋,把对应的数组元素赋为"○"
gb.board[xPos - 1][yPos - 1] = "●";// 把对应的数组元素赋为"●"。
int pin1 = 0; //用于控制打印"请输入您下棋的座标,应以x,y的格式:"
for (int i = 0 ;i <=14 ;i++)//横扫描 i为行
{
for (int j = 0 ;j <= 10 ;j++) //j为列
{
if ((board[i][j] == "●") && (board[i][j+1] == "●") && (board[i][j+2] == "●")
&& (board[i][j+3] == "●") && (board[i][j+4] == "●"))//用户横扫描
{
System.out.println("您赢了!");
pin1 = 1;
//赢了就不用再下了,也就不用打印"请输入您下棋的座标,应以x,y的格式:"
break;//赢了一切都结束了,for循环直接终止
}
if ((board[i][j] == "○") && (board[i][j+1] == "○") && (board[i][j+2] == "○")
&& (board[i][j+3] == "○") && (board[i][j+4] == "○"))//电脑横扫描
{
System.out.println("很遗憾,电脑赢了!");
pin1 = 1;
break;
}
}
}
for (int i = 0 ;i <= 14 ;i++)//竖扫描 i为列
{
for (int j = 0 ;j <= 10 ;j++)//用户竖扫描 j为行
{
if ((board[j][i] == "●") && (board[j+1][i] == "●") && (board[j+2][i] == "●")
&& (board[j+3][i] == "●") && (board[j+4][i] == "●"))
{
System.out.println("您赢了!");
pin1 = 1;
break;
}
if ((board[j][i] == "○") && (board[j+1][i] == "○") && (board[j+2][i] == "○")
&& (board[j+3][i] == "○") && (board[j+4][i] == "○"))
{
System.out.println("很遗憾,电脑赢了!");
pin1 = 1;
break;
}
}
}
for (int i = 0 ;i < 11 ;i++ )//左斜扫描
{
for (int j = 0 ;j < 11 ;j++ )
{
if ((board[i][j] == "●") & (board[i+1][j+1] == "●") & (board[i+2][j+2] == "●")
& (board[i+3][j+3] == "●") & (board[i+4][j+4] == "●"))//用户左斜扫描
{
System.out.println("您赢了!");
pin1 = 1;
break;
}
if ((board[i][j] == "○") & (board[i+1][j+1] == "○") & (board[i+2][j+2] == "○")
& (board[i+3][j+3] == "○") & (board[i+4][j+4] == "○"))//电脑左斜扫描
{
System.out.println("很遗憾,电脑赢了!");
pin1 = 1;
break;
}
}
}
for (int i = 4 ;i < 15 ;i++ )//右斜扫描 i为行
{
for (int j = 1 ;j < 12 ;j++ ) //j为列
{
if ((board[i][j] == "●") && (board[i-1][j+1] == "●") && (board[i-2][j+2] == "●")
&& (board[i-3][j+3] == "●") && (board[i-4][j+4] == "●"))//用户右斜扫描
{
System.out.println("您赢了!");
pin1 = 1;
break;
}
if ((board[i][j] == "○") && (board[i-1][j+1] == "○") && (board[i-2][j+2] == "○")
&& (board[i-3][j+3] == "○") && (board[i-4][j+4] == "○"))//电脑右斜扫描
{
System.out.println("很遗憾,电脑赢了!");
pin1 = 1;
break;
}
}
}
if (pin1 == 0)//在没有赢的情况下打印
{
System.out.println("请输入您下棋的座标,应以x,y的格式:");
}
for (int i =0;i < counter ;i++ )
//这个for循环和里面的if循环用于判断用户是否重复下棋
{
if (xPos == man[i][0] & yPos == man[i][1])//如果现在输入的坐标和之前的坐标相等,则打印提示
{
System.out.println("提示:您已经在这个点上下过棋啦!");
gb.board[rany - 1][ranx - 1] = "╋";
//电脑“悔棋”,把下好的棋再收回去,等用户下不重复的棋,使电脑和用户节奏一致
}
}
/*
for (int i = 0;i< counter ;i++ )
这个for循环用于判断电脑随机生成的坐标是否和之前的一致,即判断电脑是否重复下棋
重新思考了一下,这个for算法有bug。不能使用。
举例:若电脑在前三步生成的坐标为(1,3)、(5,7)、(9,2),当第四次随机生成的坐标为(5,7)时,在for循环执行到第二次时,因为重复,随机生成坐标。假设坐标生成的和第一步一样,但是for循环已经循环到第二步了,所以生成的(1,3)只能和第二步的(5,7)和(9,2)比较。显而易见的是都不相同,所以不会重新生成坐标,也就是说最终生成的坐标为(1,3)但是通过了for循环的检验。
虽然感觉出现bug的概率很小,但是如果这是一个很多人在用的软件,尽管概率小,但是耐不住使用次数多。小概率的事件因为使用次数多而变成大概率的事件。所以不能使用此算法。
如果要是能用goto就行了,如果检测到坐标重复,就重新执行for语句。
可惜没有。Java中goto只作为保留字。
{
if(ranx == pc[i][0] & rany == pc[i][1])
//如果坐标重复,则重新让电脑随机生成坐标,若生成的坐标还是重复,则继续生成坐标,直到生成的坐标和之前的坐标都不重复//此算法达不到这个要求
{
ranx = 1 + (int)(Math.random()*15);
rany = 1 + (int)(Math.random()*15);
}
}
*/
for (int i = 0;i< counter ;i++ )//想到的解决bug的方法
{
if((ranx == pc[i][0] & rany == pc[i][1]) | (ranx == man[i][0] & rany == man[i][1]))
{
ranx = 1 + (int)(Math.random()*15);
rany = 1 + (int)(Math.random()*15);
i = -1;
//打了一局孤胆枪手标准模式后想到了如果坐标重合除了重新赋值随机数坐标外还要把i清零,让for循环从零重新赋值,这样上述问题就解决了。
}
}
//这个检测电脑随机生成的坐标是否重合的for循环因为工作量太大,就没有检测。算法应该没问题。
gb.printBoard();
}
}
}
程序结束符~
好巧,在EditPlus上显示的页码正好是二百。
二 明天做的事情:
完成P105的练习。最难的五六已经解决了,剩下的就是餐后沙拉了。
评论