The Development Of Five In A Row Game Based On Greedy Algorithm And Socket

Outline

This app, “FiveInARow”, lets users enjoy the famous strategy game either with their devices ( realized by greedy algorithm ) or with their friends ( realized by socket ). Also, there are two difficulty levels for the players to choose if they want to play against their devices. This is my postgraduate project from 15/04/2019 to 15/05/2019.

Demo

All app functions have been demonstrated in Demo video

App Features

Login

  1. Recognize the old users and check the password or create a new account for new users.
  1. Mode selection: The user can choose to play against either his device or his friend.
  1. Tips: Guide user on how to play

Human VS Device(stand-alone)

  1. Easy level and difficult level (Greedy algorithm).
  1. Users can view the HISTORY of all users who played this game before.
  1. Users can CLEAN all the history.
  2. Prompt information about WIN and TIE

Win: when computer wins or human wins:

Tie: when the board is full:

Human VS Human(double-player)

  1. Use SOCKET connection: server (left) VS client
  1. Every time the user places the piece on the board, they can REGRET and place the piece again.
  2. When they decide where to put ultimately, they can press the “SEND” button.

Design Summary

Human VS Device

  1. The first thing we need to do is to define some usable variables.
    private Paint paint = new Paint();
    //the width of board should be the same as its height
    private int BoardWidth;
    int[][] board = new int[LINES][LINES];
    
    /*the width of grid should be the same as its height 
    a board consists of 9*9 grids*/
    private int start_X, end_X;
    private float GridWidth;
    
    //a board has 10 lines horizontally(as well as vertically)
    static public int LINES = 10;
    
    //change the width of pieces to fit the board
    private float ratio = 4 * 1.0f / 5;
    private Bitmap white, black;
    
    //check whether the current piece is white piece
    private boolean checkIsWhite = true;
    private boolean checkIsGameOver = false;
    private boolean checkIsDraw = false;
    private boolean checkIsTie = false;
    
    //arraylist to storage white or black pieces
    private ArrayList<Point> whites = new ArrayList<>();
    private ArrayList<Point> blacks = new ArrayList<>();

    // IWin and CWin, for each group of five pieces in a line indexed by the number allocated to the Winstate to count the sores for the player and the computer.
    int[] IWin = new int[2 * LINES * LINES];
    int[] CWin = new int[2 * LINES * LINES];
    int[][][] wins = new int[LINES][LINES][2 * LINES * LINES];

    int flag;// the difficult level flag
    int u = 0, v = 0;//the position where the black piece will be put
  1. onDraw(Canvas canvas) function: When the ArrayList-- whites and blacks have elements, the board will be repainted and pieces will be located.

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawBoard(canvas);
        drawPieces(canvas);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        BoardWidth = w;
        GridWidth = BoardWidth * 1.0f / LINES;
        //eachpiece should change their width to fit the board
        int pieceWidth = (int) (GridWidth * ratio);
        white = Bitmap.createScaledBitmap(white, pieceWidth, pieceWidth, false);
        black = Bitmap.createScaledBitmap(black, pieceWidth, pieceWidth, false);

    }

    //draw Board which consists 9*9 grids
    private void drawBoard(Canvas canvas)//draw board
    {
        start_X = (int) (GridWidth / 2);
        end_X = (int) (BoardWidth - GridWidth / 2);
        for (int i = 0; i < LINES; i++) {
            int y = (int) ((0.5 + i) * GridWidth);
            //draw horizontal lines
            canvas.drawLine(start_X, y, end_X, y, paint);
            //draw vertical lines
            canvas.drawLine(y, start_X, y, end_X, paint);
        }
    }

    private void drawPieces(Canvas canvas) {
        for (int i = 0, n = whites.size(); i < n; i++) {//place white pieces on board
            Point wPoint = whites.get(i);
            float left = (wPoint.x + (1 - ratio) / 2) * GridWidth;
            float top = (wPoint.y + (1 - ratio) / 2) * GridWidth;

            canvas.drawBitmap(white, left, top, null);
        }
        for (int i = 0, n = blacks.size(); i < n; i++) {//place black pieces on the board
            Point bPoint = blacks.get(i);
            float left = (bPoint.x + (1 - ratio) / 2) * GridWidth;
            float top = (bPoint.y + (1 - ratio) / 2) * GridWidth;

            canvas.drawBitmap(black, left, top, null);
        }


    }
  1. Create a play board with 9*9 grids and initialize the winstate( will be introduced in detail )
 //Broadview constructor
 public Boardview(Context context, AttributeSet attrs) {
        super(context, attrs);
        InitWinState();
        InitBoard();

    }

 //initialize Board
 private void InitBoard() {
        paint.setColor(Color.BLACK);
        //prevent some lines from being obscure
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        white = BitmapFactory.decodeResource(getResources(), R.mipmap.white);
        black = BitmapFactory.decodeResource(getResources(), R.mipmap.black);
   }
   
 public void InitWinState() {
        int num = 0;
        for (int i = 0; i < LINES; i++) { //vertical
            for (int j = 0; j <= 5; j++) { 
                for (int k = 0; k < 5; k++) {//60
                    wins[i][j + k][num] = 1;
                    /* num = 0
                    wins[0][0][0]
                    wins[0][1][0]
                    wins[0][2][0]
                    wins[0][3][0]
                    wins[0][4][0]
                    num = 1
                    wins[0][1][1]
                    wins[0][2][1]
                    wins[0][3][1]
                    wins[0][4][1]
                    wins[0][5][1]*/
                }
                num++;
            }
        }
        for (int i = 0; i < LINES; i++) { //horizontal 60
            for (int j = 0; j <= 5; j++) {
                for (int k = 0; k < 5; k++) {
                    wins[j + k][i][num] = 1;
                }
                num++;
            }
        }

        for (int i = 0; i < 6; i++) { //left diagonal 6*6 36
            for (int j = 0; j < 6; j++) {
                for (int k = 0; k < 5; k++) {
                    wins[i + k][j + k][num] = 1;
                }
                num++;
            }
        }

        for (int i = 0; i < 6; i++) { //right diagonal 6*6 36
            for (int j = 9; j > 3; j--) {
                for (int k = 0; k < 5; k++) {
                    wins[i + k][j - k][num] = 1;
                }
                num++;
            }
        }
        total = num;//192
        for (int i = 0; i < num; i++) {
            IWin[i] = 0;
            CWin[i] = 0;
        }
    }

WinState

We need to collect all the possible win states, five pieces with the same color in one of the four orientations ( vertical, horizontal, right diagonal, and left diagonal).
Generally, I use three variables, int i, j, and k, to form a triple nested for loop to find all the possible states(WinState) in each orientation and add them to a list(wList). And in every WinState, it includes the coordinate, the number of that WinState (aka. one number of all 192 win states), and the value of the WinState.

Vertical

I fix the horizontal ordinate and find all the 6 groups of five pieces in a vertical line for that column and I do the same for all the 10 columns. In the triple nested for loop, I use the 1st for loop’s variable, int i, as horizontal ordinate so that the two for loop inside it can be used to find the vertical ordinates for the points in that column. The 2nd for loop’s variable, int j, is made to fix the start vertical ordinate for that group and the 3rd for loop’s variable, int k, is to fix the increment of the vertical ordinate and I use j+k to fix the vertical ordinates.

For example, as for i=0, j=0 and k growing from 0 to 4, I can find the ordinates of the 1st group of five pieces which are (0,0),(0,1),(0,2),(0,3),(0,4). And the number 0 and the value 1 will be allocated to the five Winstates.

And as int j grows from 0 to 5, I can get all the 6 groups of five pieces in a vertical line for this column(int i=0).
在这里插入图片描述
And with int i growing from 0 to 9, I can do the same operation as above to the all 10 columns so that I can find all the WinStates in vertical direction.

Horizontal

Similar to the Vertical one, I form a triple nested for loop but I use j+k as horizontal ordinate and i as vertical ordinate for this time (just swap the horizontal ordinate and the vertical ordinate in the vertical triple for-loop). I fix the vertical ordinate and find all the 6 groups of five pieces in a horizontal line for that row and I do the same for all the 10 rows.

For example, as for i=0, j=0 and k growing from 0 to 4 I can find the ordinates of the 1st group of five pieces in the horizontal direction which are (0,0),(1,0),(2,0),(3,0),(4,0). And a number and the value 1 will be allocated to those five Winstates.

And as int j grows from 0 to 5, I can get all the 6 groups of five pieces in a horizontal line for this row(int i=0). And with int i growing from 0 to 9, I can do the same operation as above to the all 10 rows so that I can find all the WinStates in the horizontal direction.

Right Diagonal

In this part, I want to find all the WinStates in right diagonal direction. I fix the start piece for each group and find the other 4 pieces in that group by adding the same number to the horizontal ordinate and the vertical ordinate of the start piece. And I use the 1st for loop’s variable, int i, as the original horizontal ordinate and the 2nd for loop’s variable, int j, as the original vertical ordinate so that I can find all the 6 original ordinates (the start point for a group) in one column, and I can do the same for from column 1 to column 6 (as j grows from 0 to 5). There are 6 start pieces in every column from column 1 to column 6 and I call 6 groups of 5 pieces like that as a big group.

For example, as for i=0, j=0 and k growing from 0 to 4 I can find the ordinates of the 1st group of five pieces in the right diagonal direction which are (0,0),(1,1),(2,2),(3,3),(4,4). And a number and the value 1 will be allocated to those five Winstates.

And as int j grows from 0 to 5, I can get all the 6 groups of five pieces in a right diagonal line in big group 1 ( the start pieces for all the 6 groups are in column 1 (int i=0) ).
在这里插入图片描述
And with int i growing from 1 to 5, I can do the same operation as above to the other 5 big groups of which the start pieces are in from column 2 to column 6. The last big group should be that:
在这里插入图片描述

Left Diagonal

In this part, I want to find all the WinStates in left diagonal direction. Similar to the right diagonal part, I use the 1st for loop’s variable int i as original horizontal ordinate and the 2nd for loop’s variable int j as original vertical ordinate. But this time I start from the left bottom of the board as I make the 2nd for loop starts from j=9. And to get each group of five pieces, I should add the corresponding number, int k, to the original horizontal ordinate and subtract the same number from the original vertical ordinate. There are 6 start pieces in every column from column 1 to column 6 and I call 6 groups of 5 pieces like that as a big group.

For example, as for i=0, j=9 and k growing from 0 to 4 I can find the ordinates of the 1st group of five pieces in the left diagonal direction which are (0,9),(1,8),(2,7),(3,6),(4,5). And a number and the value 1 will be allocated to those five Winstates.

And as int j reduces from 9 to 4, I can get all the 6 groups of five pieces in a left diagonal line in the big group 1 (the start pieces for all the 6 groups are in column 1(int i=0)).
在这里插入图片描述
And with int i growing from 1 to 5, I can do the same operation as above to the other 5 big groups of which the start pieces are in from column 2 to column 6, so that I can get all the WinStates in left diagonal direction.

And by using those 4 for loops, I can find all the WinStates.

  1. Override onTouchEvent function

When the user touches the valid position of the screen which means no piece has been placed before, a white piece should be painted and a black piece will be put by computer.

@Override
    public boolean onTouchEvent(MotionEvent event) {
     
        if (checkIsTie) return false;
        if (checkIsGameOver || !checkIsWhite)
        //when game is over, it will show nothing even if you touch the screen
        return false;
        
        int act = event.getAction();
        if (act == MotionEvent.ACTION_UP) {
            int x = (int) event.getX();
            int y = (int) event.getY();
            Point p = getPoint(x, y);

            if (p.y >= LINES) {
                return false;
            }
            // no action will be done if there is a piece in touch position
            if (whites.contains(p) || blacks.contains(p)) return false;

            if (checkIsWhite) {//it is the turn of the white piece player
                whites.add(p);
                invalidate();//repaint
                board[p.x][p.y] = 1;
                for (int f = 0; f < total; f++) {
                    if (wins[p.x][p.y][f] == 1) {
                        IWin[f]++;// win state f now has "IWin" pieces
                        CWin[f] = 6;
                        if (IWin[f] == 5) {
                            createAlertDiaglog("You win!");
                            writeToHistory(false);// write to txt doc
                            checkIsGameOver = true;
                        }
                    }
                }

                if (!checkIsGameOver) {
                    checkIsWhite = !checkIsWhite;
                    computerAI();
                }
            }
            invalidate();//repaint
            return true;
        }
        return true;
    }

ComputerAI

According to the difficulty level (easy & difficult), my Score and computer’s Score will be calculated in a different way

private void computerAI() {
        // TODO Auto-generated method stub
        int max = 0;

        //initialize all the scores
        int[][] myScore = new int[10][10];
        int[][] computerScore = new int[10][10];

        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10; j++) {
                myScore[i][j] = 0;
                computerScore[i][j] = 0;
            }
        }
      
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10; j++) {
                // if that position is valid
                if (board[i][j] == 0) { 
                    for (int k = 0; k < total; k++) {
                        // search all the win patterns
                        if (wins[i][j][k] == 1) { 
                        //if position(i,j) belongs to win patterns 
                            if (flag == 1) {//easy
                                switch (IWin[k]) { 
                                //k win pattern now has "IWin" black pieces
                                //when the difficulty level is easy, the 
                                //score of computer will be added less than my score
                                    case 1:
                                        myScore[i][j] += 220;
                                        break;
                                    case 2:
                                        myScore[i][j] += 420;
                                        break;
                                    case 3:
                                        myScore[i][j] += 2000;
                                        break;
                                    case 4:
                                        myScore[i][j] += 22000;
                                        break;

                                }

                                switch (CWin[k]) {
                                    case 1:
                                        myScore[i][j] += 200;
                                        break;
                                    case 2:
                                        myScore[i][j] += 400;
                                        break;
                                    case 3:
                                        myScore[i][j] += 2000;
                                        break;
                                    case 4:
                                        myScore[i][j] += 10000;
                                        break;

                                }

                            } else {  //difficult
                                switch (IWin[k]) {
                                    case 1:
                                        myScore[i][j] += 200;
                                        break;
                                    case 2:
                                        myScore[i][j] += 400;
                                        break;
                                    case 3:
                                        myScore[i][j] += 2000;
                                        break;
                                    case 4:
                                        myScore[i][j] += 10000;
                                        break;

                                }

                                switch (CWin[k]) {
                                    case 1:
                                        myScore[i][j] += 220;
                                        break;
                                    case 2:
                                        myScore[i][j] += 420;
                                        break;
                                    case 3:
                                        myScore[i][j] += 2000;
                                        break;
                                    case 4:
                                        myScore[i][j] += 22000;
                                        break;

                                }
                            }
                        }
                    }
                    //GREEDY ALGORITHM
                    // if my score in position (i,j) > max, the black 
                    // piece will be put in this position to intercept,
                    // else if my score in position (i,j) = max,
                    // but computer's score is higher,the black piece
                    // will be put in that position to get a higher score
                    if (myScore[i][j] > max) {                
                        max = myScore[i][j];
                        u = i;
                        v = j;
                    } else if (myScore[i][j] == max) {    
                        if (computerScore[i][j] >= computerScore[u][v]) {//more black piece positions will be found 
                            u = i;
                            v = j;
                        }
                    }
                    // if computer's score in position (i,j) > max, the black 
                    // piece will be put in this position to get a higher score,
                    // else if computer's score in position (i,j) = max,
                    // but my score is higher,the black piece
                    // will be put in that position to intercept
                    if (computerScore[i][j] > max) {
                        max = computerScore[i][j];
                        u = i;
                        v = j;
                    } else if (computerScore[i][j] == max) {
                        if (myScore[i][j] > myScore[u][v]) {
                            u = i;
                            v = j;
                        }
                    }
                    
                    int exist  = 0;//black pieces shouldn't be overlapped 
                    for (int l = 0; l < bp.size(); l++) {
                        if (bp.get(l).x == u && bp.get(l).y == v)
                            exist = 1;
                    }
                    if (exist == 0) {
                        bp.add(new Point(u, v));
                        //System.out.println("u: "+u+"v: "+v);
                    }
                }
            }
        }
        int get = 0;
        for (int i = bp.size() - 1; i >= 0; i--) {
        // find the 1st blackpiece position which don't overlap with existing black pieces
            int same = 0;
            for (int j = 0; j < blacks.size(); j++) {
                if (blacks.get(j).x == bp.get(i).x && blacks.get(j).y == bp.get(i).y ) {
                   same = 1;
                }
            }
            if (same == 0 && get == 0) {
                u = bp.get(i).x;
                v = bp.get(i).y;
                get = 1;

                board[u][v] = 2;

                blacks.add(new Point(u, v));
                invalidate();
                
                if((whites.size()+blacks.size()) == 100) {
                    checkIsTie = true;
                    createAlertDialog("It is a tie!");

                }

                for (int f = 0; f < total; f++) {
                    if (wins[u][v][f] == 1) {
                        CWin[f]++;
                        IWin[f] = 6;
                        if (CWin[f] == 5) {
                            createAlertDialog("Computer Wins!");
                            writeToHistory(true);
                            checkIsGameOver = true;
                        }
                    }
                }

                if (!checkIsGameOver) {
                    checkIsWhite = !checkIsWhite;
                }

            }else break;
        }
    }
  1. Start function
public void start() {
        u = 0;
        v = 0;
        total = 0;

        whites.clear();
        blacks.clear();

        checkIsWhite = true;
        checkIsGameOver = false;
        checkIsTie = false;

        wins = new int[10][10][200];
        board = new int[10][10];
        IWin = new int[200];
        CWin = new int[200];

        InitWinState();
        invalidate();
    }

Human VS Human

BoardView for Server & Client

CheckGameOver: Detect win pattern in 4 directions.

    final static int Horizontal_Tag = 0, Vertical_Tag = 1, Left_diagonal_Tag = 2, Right_diagonal_Tag = 3;
    final static int[] Tags = {Horizontal_Tag, Vertical_Tag, Left_diagonal_Tag, Right_diagonal_Tag};
    Point point1, point2;

    public void checkGameOver() {
        boolean whiteWin = checkWinner(whites);
        boolean blackWin = checkWinner(blacks);

        if (whiteWin || blackWin) {
            checkIsGameOver = true;
            String text = whiteWin ? "you win!" : "you lose!";
            if(getBoardViewListener()!=null){
                getBoardViewListener().BvTouch(whites,blacks,true);
            }
            createAlertDiaglog(text,whiteWin);
        }
    }

CheckWinner: Check winner by detecting whether there exists five pieces with the same color, in one of these four orientations (horizontal, vertical, left diagonal and right diagonal)

    public boolean checkWinner(List<Point> points) {
        for (Point point : points) {
            int x = point.x;
            int y = point.y;
            for (int i = 0; i < Tags.length; i++) {
                if (check(x, y, points, Tags[i])) {
                    return true;
                }
            }
        }
        return false;
    }

Check the pieces in current piece’s left side or right side whatever orientation we check. For each current point, we will create point 1 and point 2 for four times virtually. Then every time we find point1 or point2 exists in pieces Arraylist actually, and we will make count++, if count = 5 ultimately, which means 5 pieces in a line. Let me illustrate this by using graph: (Note: point1 denoted by 1, point2 denoted by 2, current point denoted by C)

 a.horizontal check:
 1 1 1 1 C 2 2 2 2

 b.vertical check:             c.left_diagonal check:      d.right_diagonal_tag check:
       1                                 1                          *********2
       1                                 *1                         ********2
       1                                 **1					    *******2
       1                                 ***1                       ******2
       C                                 ****C                      *****C
       2                                 *****2                     ****1
       2                                 ******2                    ***1
       2                                 *******2                   **1
       2                                 ********2                  *1
    private boolean check(int x, int y, List<Point> PList, int tag) {
        int count = 1;
        for (int i = 1; i < 5; i++) {
            if (tag == Horizontal_Tag) {
                point1 = new Point(x - i, y);//horizontal
                point2 = new Point(x + i, y);
            } else if (tag == Vertical_Tag) {
                point1 = new Point(x, y - i);//vertical
                point2 = new Point(x, y + i);
            } else if (tag == Left_diagonal_Tag) {
                point1 = new Point(x - i, y + i);//left diagonal
                point2 = new Point(x + i, y - i);
            } else if (tag == Right_diagonal_Tag) {
                point1 = new Point(x + i, y + i);//right diagonal
                point2 = new Point(x - i, y - i);
            }

            if ((PList.contains(point1) && !PList.contains(point2)) || (!PList.contains(point1) && PList.contains(point2))) {
                count++;
            } else if ((PList.contains(point1) && PList.contains(point2))) {
                count += 2;
            } else break;
        }

        if (count == 5) {
            return true;
        }
        return false;
    }

Socket

I use Java Socket to realize the two-way real-time communication between client and server.

Server
  1. Instantiate a ServerSocket object with the specified port through which the server can listen for connection requests from the client;
  2. Call the accept() method to listen for requests from the connection port, which is blocked.
 public void receiveData(){//establish the connection with the client
 
        Thread thread = new Thread(){
            @Override
            public void run() {
                super.run();
                try {
                    serverSocket = new ServerSocket(8090);//port
                } catch (IOException e) {
                    e.printStackTrace();
                }
                //1. get IP address
                GetIpAddress.getLocalIpAddress(serverSocket);

                Message message_1 = handler.obtainMessage();
                message_1.what = 1;// handler case 1 will process on it
                message_1.obj = "IP:" + GetIpAddress.getIP() + " PORT: " + GetIpAddress.getPort();
                handler.sendMessage(message_1);
                //2.accept the request of socket connection from client
                while (true){
                    try {
                        socket = serverSocket.accept();
                        inputStream  = socket.getInputStream();
                        StringBuffer stringBuffer = H2HServer.this.stringBuffer;
                        int len;
                        byte[] bytes = new byte[20];
                        boolean isString = false;
                        //When the input stream is closed, it will be equal to -1,
                        // which is not the case that after reading the data, it will be equal to -1 
                        //after reading the data.
                        while ((len = inputStream.read(bytes)) != -1) {
                                for (int i = 0; i < len; i++) {
                                    if (bytes[i] != '\0') {
                                        stringBuffer.append((char) bytes[i]);
                                    } else {
                                        isString = true;
                                        break;
                                    }
                                }
                                if (isString) {
                                    Message message_2 = handler.obtainMessage();
                                    message_2.what = 2;// handler case 2 will process on it
                                    message_2.obj = stringBuffer;
                                    handler.sendMessage(message_2);
                                    //send data to handler, handler will process on it
                                    isString = false;
                                }

                            }
                            //When this exception occurs, the connection on the client side has been disconnected

                    } catch (IOException e) {

                        e.printStackTrace();
                    }

                }
            }
        };
        thread.start();

    }
 
  1. Do the read and write operations (IO) using the client socket object returned by this method ;

  2. Close the Socket.

Handler:


    public Handler handler = new Handler(){

        @Override
        public void handleMessage(Message msg) {

            switch (msg.what){
                case 1:
                    Text1.setText(msg.obj.toString());//show IP address
                    break;
                case 2:
                    editText_2.setText(msg.obj.toString());
                    String tmp = msg.obj.toString();
                    //receive and parse data(tmp) from the client and repaint the board               
                    int flag1= 0;
                    for(int i = 0;i < tmp.length();i++)
                    {
                        if(tmp.charAt(i) =='(')
                        {
                            if(tmp.substring(i+1,i+2).equals("-"))
                            {
                                flag1 = i;
                            }
                        }
                    }
                    for(int i = 0;i < tmp.length();i++)
                    {
                        if(tmp.charAt(i) ==  '(')
                        { 
                            if(!tmp.substring(i+1,i+2).equals("-"))
                            {
                                if(i < flag1) {                                   
                                   apw.add(new Point(tmp.charAt(i + 1)-'0',tmp.charAt(i + 3)-'0'));// add new white piece to the board
                                }
                                else{
                                    apb.add(new Point(tmp.charAt(i + 1)-'0',tmp.charAt(i + 3)-'0'));// add new black piece to the board
                                }
                            }

                        }
                    }
                    bv.blacks = apb;// refresh the board
                    bv.whites = apw;
                    bv.count = 0;
                    bv.invalidate();
                    stringBuffer.setLength(0);
                    break;
            }
        }
    };
bt.setOnClickListener(new View.OnClickListener() {//send data to the client
            @Override
            public void onClick(View v) {
                try {
                    bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    bw.write(editText_2.getText().toString()+"\n");                   
                } catch (IOException e) {
                    e.printStackTrace();
                }

                try {
                    bw.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

Data format:( whites.get(i).x , whites.get(i).y )(-,-)( blacks.get(i).x , blacks.get(i).y )

 String str = "";
                for(int i = 0;i < whites.size();i++)
                {
                    str += "("+whites.get(i).x + ","+whites.get(i).y+"),";
                }
                str += "(-,-),";
                for(int i = 0;i < blacks.size();i++)
                {
                    str += "("+blacks.get(i).x + ","+blacks.get(i).y+"),";
                }
               
                editText_2.setText(str);
Client
  1. Do the instantiating with the IP address and port provided by the server side
**getIPAddress:** get server's IP address
```java
public class GetIpAddress {

    public static String IP;
    public static int PORT;

    public static String getIP(){
        return IP;
    }
    public static int getPort(){
        return PORT;
    }
    public static void getLocalIpAddress(ServerSocket serverSocket){
        try {
            for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();){
                NetworkInterface intf = en.nextElement();
                for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses();enumIpAddr.hasMoreElements();){
                    InetAddress inetAddress = enumIpAddr.nextElement();
                    String mIP = inetAddress.getHostAddress().substring(0, 3);
                    if(mIP.equals("192")){
                        IP = inetAddress.getHostAddress();    //get the local IP
                        PORT = serverSocket.getLocalPort();   //get the local PORT
                        Log.e("IP",""+IP);
                        Log.e("PORT",""+PORT);
                    }
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
        }

    }
}
  1. Call the connect() method to connect to the server
connect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ip = editText_ip.getText().toString();
                if (ip.equals("")) {
                    Toast.makeText(H2HClient.this, "please input Server IP", Toast.LENGTH_SHORT).show();
                }

                Thread thread =  new Thread() {
                    @Override
                    public void run() {
                        super.run();
                        if (!socketStatus) {
                            try {
                                socket = new Socket(ip, 8090);
                            } catch (Exception e) {
                                System.out.println("cannot create socket!!!since e" + e);
                            }
                            if (socket == null)
                                System.out.println("connect fail!");
                            else {
                                socketStatus = true;
                            }
                        }
                    }
                };
                thread.start();
            }
        });
  1. Obtain the flow on the Socket and encapsulate that into the BufferedReader/PrintWriter instance, for reading and writing;
  2. Realize the interacting with the server using getInputStream and getOutputStream provided by Socket;

Send data to the server(the data format is the same as the data sent by server)

    public void send(View view) {

        data = editText_data.getText().toString();
        if (data.equals("")) {
            Toast.makeText(H2HClient.this, "please input Sending Data", Toast.LENGTH_SHORT).show();
        } else {
            data = data + '\0';
        }

        Thread thread = new Thread() {
            @Override
            public void run() {
                super.run();
                if (socketStatus) {
                    try {
                        outputStream = socket.getOutputStream();
                        outputStream.write(data.getBytes());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        thread.start();

    }

Receive data from the server

    public void receiveData() {
        Thread thread = new Thread() {
            @Override
            public void run() {
                super.run();

                if (socketStatus) {
                    BufferedReader br = null;
                    try {
                        br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                        String mess = br.readLine();
                        int flag1 = 0;
                        for (int i = 0; i < mess.length(); i++) {

                            if (mess.charAt(i) == '(') {
                                if (mess.substring(i + 1, i + 2).equals("-")) {
                                    flag1 = i;

                                }

                            }
                        }
                        for (int i = 0; i < mess.length(); i++) {

                            if (mess.charAt(i) == '(') {                               
                                if (!mess.substring(i + 1, i + 2).equals("-")) {

                                    if (i < flag1) {
                                        apw.add(new Point(mess.charAt(i + 1) - '0', mess.charAt(i + 3) - '0'));
                                    } else {
                                        apb.add(new Point(mess.charAt(i + 1) - '0', mess.charAt(i + 3) - '0'));
                                    }
                                }
                            }
                        }
                        bv.blacks = apb;
                        bv.whites = apw;
                        bv.count = 0;
                        bv.invalidate();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        };
        thread.start();

    }
  1. Close the Socket.

Conclusion

In this project, two game modes have been achieved: human VS device and human VS human. To achieve the first mode, I concluded all the possible win states both for human and device - once the white piece was placed, the corresponding pattern would have one more piece, and if there exists a pattern that has five-piece, the game is ended. To achieve another mode, the socket between the server and client was established, and after the client sent the connection request to the server and the server accepted it, the place of pieces can be transferred through the socket. At the same time, every time the user places the piece on the board, win state will be checked.

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值