import java.io.*;
import java.util.*;
public class Gobang{
	//定义棋盘的大小
	private static final int BOARD_SIZE = 15;
	//用二维数组充当棋盘
	private String[][] board;
	//用来画棋盘的符号("+"),此符号处代表无棋子
	private final String POINT = "+";
	//黑棋子
	private final String BLACK = "●";
	//白棋子
	private final String WHITE = "○";
	
	public static void main(String args[]) throws IOException{
		Gobang gb = new Gobang();
		gb.initBoard();
		gb.printBoard();
		gb.start();
	}
	
	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] = POINT;
			}
		}
	}
	//在控制台输出棋盘
	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 void start() throws IOException{
		System.out.println("请输入您下棋的坐标,应以x,y的格式:");
		//获取从键盘输入的方法
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
		String inputStr = "";
		//键盘输入后按回车能被bufferedReader读取到
		while((inputStr = bufferedReader.readLine()) != null){
			String[] posStrArr = inputStr.split(",");
			int x = 0;
			int y = 0;
			try{					
				x = Integer.parseInt(posStrArr[0]);
				y = Integer.parseInt(posStrArr[1]);
			}catch(NumberFormatException e){
				//装换错误说明输入格式不对,重新输入
				System.out.println("输入的格式不正确!");
				continue;
			}
			if(!pointValid(x - 1,y - 1)){
				System.out.println("您输入的棋子坐标无效,请重输!");
				//无效直接跳过后面代码
				continue;
			}
			//对应位置用●赋值,代表一枚棋子
			board[x - 1][y - 1] = BLACK;
			if(scan()){
				System.out.println("玩家胜利!游戏结束");
				printBoard();
				break;
			}
				
			/*
				电脑随机生成两个整数,作为电脑下棋的坐标,赋值给board数组
				还涉及:
					1.坐标的有效性,只能是数字,不能超出棋盘的范围
					2.下棋的点,不能重复下棋
					3.每次下棋后需要扫描谁赢了
			*/
			
			computer();//需要完善的点:可以选择谁先下而不是默认的玩家先下
			if(scan()){
				System.out.println("电脑胜利!游戏结束");
				printBoard();
				break;
			}
			printBoard();
			System.out.println("请输入您下棋的坐标,应以x,y的格式(原点为左上角,x正方向向下,y正方向向右):");	
		}
	}
	//电脑下棋的方法
	private void computer(){
		//已满足生成点的坐标在棋盘内
		Random random = new Random();
		int x = random.nextInt(BOARD_SIZE);
		int y = random.nextInt(BOARD_SIZE);
		//有效性验证
		while(!pointValid(x,y)){
			//无效坐标重新生成
			x = random.nextInt(BOARD_SIZE);
			y = random.nextInt(BOARD_SIZE);
		}
		board[x][y] = WHITE;//需要完善的点:可以让玩家选择棋子,而不是默认玩家黑,电脑白
	}
	
	/**
	*
	*	验证下棋点的有效性
	*		1.验证下棋点是否超出棋盘范围(玩家下棋时需要验证,电脑这一步其实可以不验证)
	*		2.验证下棋的点是否已存在棋子
	*	@param x 横坐标(索引 0开始)
	*	@param y 纵坐标(索引 0开始)
	*	@return 坐标的有效性 有效:true,无效:false
	*
	*	java语法: javadoc只处理public protected修饰的类、接口、方法、成员变量、
	*			   构造函数、和内部类之前的文档注释(此处private,所以不会处理)
	*/
	private boolean pointValid(int x,int y){
		//验证下棋点是否超出棋盘范围(玩家下棋时需要验证,电脑这一步其实可以不验证,因为它生成的位置就在范围内)
		if(x >= BOARD_SIZE || y >= BOARD_SIZE || x < 0 || y < 0)
			return false;
		//验证下棋的点是否已存在棋子
		if(board[x][y] != POINT){
			//已存在棋子
			return false;
		}
		return true;
	} 
	/**
		难点:扫描算法(自己写的比较蠢的办法...智商不够用..哈哈)
		扫描是否有五个相同棋子连成一条线(—|\/)
		
		分析:
			一条线有四种情况—|\/:
			原点为左上角,x正方向向下,y正方向向右
			-: x相等  y从左到右依次加1
			|: y相等  x从上到下依次加1
			\:  从左上到右下,xy都依次加1
			/:  从右上到左下,x从上到下依次加1,y从右到左依次减1
			
			
		@return 有返回true,没有返回false
	*/
	private boolean scan(){
		for(int i = 0; i < BOARD_SIZE; i ++){
			for(int j = 0; j < BOARD_SIZE; j ++){
				if(board[i][j] != POINT){
					//有棋子
					if(board[i][j] == BLACK){
						if(getFive1(i,j,BLACK) || getFive2(i,j,BLACK) || getFive3(i,j,BLACK) || getFive4(i,j,BLACK))
							return true;
					}		
					//白棋子
					if(board[i][j] == WHITE){
						if(getFive1(i,j,WHITE) || getFive2(i,j,WHITE) || getFive3(i,j,WHITE) || getFive4(i,j,WHITE))
							return true;
					}
				}
			}
		}
		return false;
	}
	
	// "-"
	private boolean getFive1(int x,int y,String point){
		boolean flag = true;
		try{
			for(int m = 1; m <= 4 && flag; m ++){
				if(board[x][y+m]!=point){
					flag = false;
				}
			}
		}catch(ArrayIndexOutOfBoundsException e){
			flag = false;
		}
		return flag;
	}
	// "|"
	private boolean getFive2(int x,int y,String point){
		boolean flag = true;
		try{
			for(int m = 1; m <= 4 && flag; m ++){
				if(board[x+m][y]!=point){
					flag = false;
				}
			}
		}catch(ArrayIndexOutOfBoundsException e){
			flag = false;
		}
		return flag;
	}
	// "/"
	private boolean getFive3(int x,int y,String point){
		boolean flag = true;
		try{
			for(int m = 1; m <= 4 && flag; m ++){
				if(board[x+m][y-m]!=point){
					flag = false;
				}
			}
		}catch(ArrayIndexOutOfBoundsException e){
			flag = false;
		}
		return flag;
	}
	// "\"
	private boolean getFive4(int x,int y,String point){
		boolean flag = true;
		try{
			for(int m = 1; m <= 4 && flag; m ++){
				if(board[x+m][y+m]!=point){
					flag = false;
				}
			}
		}catch(ArrayIndexOutOfBoundsException e){
			flag = false;
		}
		return flag;
	}
}