// tic-tac-toe server

import java.net.*;
import java.io.*;

public class TicServ {
    // write and flush to a socket
    public static void swrite(Socket sock,int s) throws IOException {
        OutputStream str=sock.getOutputStream();
        str.write(s);
        str.flush();
    }

    public static void main(String args[]) throws Exception {
        System.out.println("Tic Tac Toe Server by Al Williams");
        ServerSocket server = new ServerSocket(9001);
        // wait for connection pair and spin off thread
        while (true) {
            Socket sockx = server.accept();  // accept new connection
            swrite(sockx,'W');  // wait      // tell player 1 to wait
            Socket socko = server.accept();  // accept player 2
            new BackgroundTask(sockx,socko).start();  // start new thread
        }
    }
}

class BackgroundTask extends Thread {
    private Socket sockx;
    private Socket socko;
    private OutputStream strx;
    private OutputStream stro;
    private InputStream istrx;
    private InputStream istro;
    private int [] game = new int[9];
    BackgroundTask(Socket sockx,Socket socko) throws IOException
    {
        // cache away sockets and create I/O streams
        this.sockx = sockx;
        this.socko=socko;
        strx=sockx.getOutputStream();
        istrx=sockx.getInputStream();
        stro=socko.getOutputStream();
        istro=socko.getInputStream();
    }

    // write to stream
    private void wflush(OutputStream os,int s) throws IOException {
        os.write(s);
        os.flush();
    }

    public void run() {
        int ct=0;
        int i;
        for (i=0;i<9;i++) game[i]=0;
        try {
            // set up both sides
            wflush(strx,'X');  // X or O
            wflush(stro,'O');
            while (true) {
                int cmd;
                ct++;   // next turn
                // if ct==10 then draw game
                if (ct==10) {
                          wflush(strx,'G');
                          wflush(stro,'G');
                          break;
                }
                wflush(ct%2==0?stro:strx,'M');   // ask player for move
                cmd= (ct%2==0?istro:istrx).read();  // wait for it
                if (cmd=='Q') break;   // quit!
                wflush(ct%2==0?strx:stro,cmd);  // pass to peer
                // store move so we can check for wins
                game[cmd-'0']=ct%2==0?'O':'X';
                // check for wins
                // X win?
                if ((game[0]=='X' && game[1]=='X' && game[2]=='X') ||
                    (game[3]=='X' && game[4]=='X' && game[5]=='X') ||
                    (game[6]=='X' && game[7]=='X' && game[8]=='X') ||
                    (game[0]=='X' && game[3]=='X' && game[6]=='X') ||
                    (game[1]=='X' && game[4]=='X' && game[7]=='X') ||
                    (game[2]=='X' && game[5]=='X' && game[8]=='X') ||
                    (game[0]=='X' && game[4]=='X' && game[8]=='X') ||
                    (game[6]=='X' && game[4]=='X' && game[2]=='X'))  {
                    // X wins
                        wflush(strx,'W');
                        wflush(stro,'L');
                        break;
                }
                // O win?
                if ((game[0]=='O' && game[1]=='O' && game[2]=='O') ||
                    (game[3]=='O' && game[4]=='O' && game[5]=='O') ||
                    (game[6]=='O' && game[7]=='O' && game[8]=='O') ||
                    (game[0]=='O' && game[3]=='O' && game[6]=='O') ||
                    (game[1]=='O' && game[4]=='O' && game[7]=='O') ||
                    (game[2]=='O' && game[5]=='O' && game[8]=='O') ||
                    (game[0]=='O' && game[4]=='O' && game[8]=='O') ||
                    (game[6]=='O' && game[4]=='O' && game[2]=='O'))  {
                        // O wins
                        wflush(stro,'W');
                        wflush(strx,'L');
                        break;
                }
            }
        } catch (Exception e) {
             e.printStackTrace();  // this shows up on server console
        }
       // somebody quit, tell everyone
       // Each is in its own exception block so that if one throws an
       // exception, the others statements still execute
       try {
            wflush(strx,'Q');
       } catch (Exception e) { };
       try {
            wflush(stro,'Q');
       } catch (Exception e) { };
       // close sockets
       try {
            sockx.close();
       } catch (Exception e) { };
       try {
            socko.close();
      } catch (Exception e) {}
   }
}
