三目並べ
ゲームのプロトコルは実装していない。紳士(淑女)協定によりゲームが進行することを前提にしている。とてもいい加減。だから、みなさんのやるべき課題がいっぱい用意されているということだ。
ソースは2つに分かれている。TicTacToe クラスは接続の仕事をするメインクラスだ。
package tictactoe2; import java.net.ServerSocket; import java.net.Socket; public class TicTacToe { /** * @param args */ public final static int PORT = 11000; public static void main(String[] args) { // TODO Auto-generated method stub TicTacPanel ttp=null; Socket soc; String hostname = "localhost"; try { if (args.length == 0) { System.out.println("Usage: java ticktacktoe2/TicTacToe O(Oh)"); System.out.println("or: java ticktacktoe2/TicTacToe X hostname"); System.exit(-1); } else if (args.length == 1 && args[0].equals("X")) { soc = new Socket("localhost", PORT); ttp = new TicTacPanel("X", soc); } else if (args.length == 2 && args[0].equals("X")) { soc = new Socket(args[1], PORT); ttp = new TicTacPanel("X", soc); } else { ServerSocket tempSoc = new ServerSocket(PORT); soc = tempSoc.accept(); ttp = new TicTacPanel("O", soc); } } catch (Exception e) { System.out.println("Error occured."); System.exit(-1); } new Thread(ttp).start(); } }
次はイベント処理とソケットの監視を一手に引き受ける TicTacPanel クラスだ。MVCの分離が若干醜い。
package tictactoe2; import java.awt.Font; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; import javax.swing.JFrame; import javax.swing.JButton; public class TicTacPanel implements Runnable { JFrame frame; String role; String rolePeer; JButton[][] buttons = new JButton[3][3]; MyButtonListener[][] listeners = new MyButtonListener[3][3]; Socket soc; BufferedReader reader; PrintWriter writer; public TicTacPanel(String role, Socket soc){ this.role = role; if(role=="X")rolePeer="O";else rolePeer="X"; this.soc = soc; try { reader = new BufferedReader(new InputStreamReader( soc.getInputStream())); writer = new PrintWriter(new OutputStreamWriter( soc.getOutputStream())); } catch (Exception e) { System.exit(-1); } frame = new JFrame("Tic Tac Toe "+role); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setSize(400, 400); frame.getContentPane().setLayout(new GridLayout(3, 3)); Font font = new Font("MSGothic", Font.BOLD, 120); // Font size should be adjusted when the window size is changed. for(int i=0; i<3; i++){ for(int j=0; j<3; j++){ buttons[i][j] = new JButton(""); buttons[i][j].setFont(font); listeners[i][j] = new MyButtonListener(i,j,role); buttons[i][j].addActionListener(listeners[i][j]); frame.getContentPane().add(buttons[i][j]); } } frame.setVisible(true); } @Override public void run() { // TODO Auto-generated method stub while(true){ try { String line = reader.readLine(); int i = Integer.parseInt(line.substring(0,1)); int j = Integer.parseInt(line.substring(2,3)); buttons[i][j].setText(rolePeer); } catch (IOException e) { // TODO Auto-generated catch block System.out.println(e.toString()); System.out.println("error in new thread"); System.exit(-1); } } } class MyButtonListener implements ActionListener { int i; int j; String role = ""; public MyButtonListener(int i, int j, String role){ this.i = i; this.j = j; this.role = role; } @Override public void actionPerformed(ActionEvent arg0) { // TODO Auto-generated method stub buttons[i][j].setText(role); writer.println(i+" "+j); writer.flush(); } } }