詳細
プロトコル(1行単位) 1. 「ユーザ名の登録」 サーバ -> クライアント: プログラム名 クライアント -> サーバ: ユーザ名(ここで嘘をつくと,勝っても正しく記録されない) 2. 「出す手を伝える」 クライアント -> サーバ: 手(0,1,2) サーバ -> クライアント: 相手の手 3. 50回の勝負が終わる前は2に戻る. 4. 結果の表示 サーバ -> クライアント : 5. 切断 サーバの側から接続を切断する.ヒント
プロトコルを理解するために,
telnet 133.11.171.98 3331とやって,名前の入力,[0-2]の数字の入力をやってみるのも良い.
// Randomクラスを利用するので java.util.*をインポート import java.util.*; // 入出力関係のクラスを利用するので java.util.*をインポート import java.io.*; // ネットワーク関係のクラスを利用するので java.net.*をインポート import java.net.*; class Janken{ static void janken(BufferedReader in,PrintWriter out) throws IOException{ Random r=new Random(); String s=in.readLine(); System.out.println("対戦相手は"+s); int index=(int)(r.nextDouble()*3.0); for(int i=0;i< 50;i++){ out.println(index); // サーバからの入力をもらう if((s=in.readLine())==null){ System.exit(1); } index=(int)(r.nextDouble()*3.0); } while((s=in.readLine())!=null) System.out.println(s); } public static void main(String args[]) throws IOException{ if(args.length<2) usage(); Socket sock=new Socket(args[0],Integer.parseInt(args[1])); BufferedReader in=new BufferedReader(new InputStreamReader(sock.getInputStream())); PrintWriter out=new PrintWriter(sock.getOutputStream(),true); out.println(System.getProperty("user.name")); janken(in,out); } static void usage(){ System.err.println("使い方: java Janken ホスト名 ポート番号"); System.exit(1); } }
ktanaka@ux019> java Janken 133.11.171.98 3331 対戦相手はKodomo1 Kodomo1 22222222222222222222222222222222222222222222222222 ktanaka 21022210000012222212000221022222220120212200120220 Wed Dec 13 16:01:31 JST 2000 Kodomo1 が ktanakaに58 点で勝ちましたこのプログラムは,完全に乱数で手を出す. プロトコルが決まっているので,スレッドを使う必要はない.
// 入出力ストリームを使うので,java.io.* を import import java.io.*; // ソケットを使うので java.net.* を import import java.net.*; // randomを使う import java.util.*; class JankenGame implements Runnable{ Socket sock[]=new Socket[2]; BufferedReader[] ins=new BufferedReader[2]; PrintWriter[] outs=new PrintWriter[2]; String names[]=new String[2]; JankenServer js; JankenGame(JankenServer js,Socket sock0,Socket sock1){ this.js=js; this.sock[0]=sock0; this.sock[1]=sock1; } public void run(){ int i,j; try{ for(i=0;i<2;i++){ outs[i] = new PrintWriter(sock[i].getOutputStream(),true); ins[i] = new BufferedReader(new InputStreamReader(sock[i].getInputStream())); names[i]=ins[i].readLine(); } for(i=0;i<2;i++) outs[i].println(names[1-i]); String[] s=new String[2]; int[][] gameRec=new int[2][50]; gameLoop: for(j=0;j<50;j++){ for(i=0;i<2;i++){ if((s[i]=ins[i].readLine())==null){ break gameLoop; } gameRec[i][j]=Integer.parseInt(s[i]); } for(i=0;i<2;i++){ outs[i].println(gameRec[1-i][j]); } } if(j==50){ String str=JankenRobot.recToStr(names[0],gameRec[0])+JankenRobot.recToStr(names[1],gameRec[1]); int w; for(w=0,i=0;i<50;i++) w+=JankenRobot.win(gameRec[0][i],gameRec[1][i]); str=str+new Date()+"\n"; if(w>0){ str=str+names[0]+" が "+names[1]+"に"+(w+50)+" 点で勝ちました"; } else if(w<0){ str=str+names[1]+" が "+names[0]+"に"+(50-w)+" 点で勝ちました"; } else str=str+names[0]+" と "+names[1]+"は引き分けでした"; for(i=0;i<2;i++) outs[i].println(str); js.println(str); } else{ for(i=0;i<2;i++) outs[i].println("プログラムが途中で中断しました"); js.println("プログラムが途中で中断しました"); } sock[0].close(); sock[1].close(); } catch(IOException e){ System.err.println(e); } } } class JankenRobot implements Runnable{ Socket sock; JankenServer js; int type; PrintWriter out; BufferedReader in; String[] robotNames={"","Kodomo1","Kodomo2","Kodomo3","Otona1","Otona2"}; JankenRobot(JankenServer js,Socket sock,int type){ this.js=js; this.sock=sock; this.type=type; } // m0がm1に勝つ時は 1, 引き分けが0,敗けは -1 static int win(int m0, int m1){ if(m0-m1== -1 || m0-m1== 2) return 1; else if(m0==m1) return 0; else return -1; } static String recToStr(String name,int[] game){ String s=(name+" ").substring(0,8); int i; for(i=0;i<50;i++) s=s+game[i]; return s+"\n"; } Random r=new Random(); int ir; int robot(int i,int[][] rec){ if(i==0){ ir=(int)(r.nextDouble()*3.0); return ir; } switch(type){ case 1: /* いつも同じものを出す */ return ir; case 2: /* 削除 */ case 3: /* 削除 */ case 4:{ /* 削除 */ } case 5:{ /* 削除 */ } } return 0; } public void run(){ try{ out = new PrintWriter(sock.getOutputStream(),true); in = new BufferedReader(new InputStreamReader(sock.getInputStream())); out.println(robotNames[type]); int i; String name=in.readLine(); String s=null; int[][] gameRec=new int[2][50]; for(i=0;i<50;i++){ int a=robot(i,gameRec); if((s=in.readLine())==null) break; int b=Integer.parseInt(s); gameRec[0][i]=a; gameRec[1][i]=b; out.println(a); } if(i==50){ String str=recToStr(robotNames[type],gameRec[0])+recToStr(name,gameRec[1]); int w; for(w=0,i=0;i<50;i++) w+=win(gameRec[0][i],gameRec[1][i]); str=str+new Date()+"\n"; if(w>0){ str=str+robotNames[type]+" が "+name+"に"+(w+50)+" 点で勝ちました"; } else if(w<-10){ str=str+name+" が "+robotNames[type]+"に"+(50-w)+" 点で勝ちました. じゃんけんロボット("+type+")はクリアしました\n"; } else{ str=str+name+" が "+robotNames[type]+"に"+(50-w)+" 点で勝ちました. じゃんけんロボット("+type+")をクリアするには60点必要です\n"; } out.println(str); js.println(str); } else{ out.println("プログラムが途中で中断しました"); js.println("プログラムが途中で中断しました"); } sock.close(); } catch(IOException e){ System.err.println(e); } } } // 呼び出し方 // java JankenServer 対戦モード ポート番号 // 対戦モードは // 0 自由対戦 // 1-5 対応するプログラム class JankenServer{ // コンストラクタ public JankenServer(int type, int port){ Socket sock,waitingSock=null; try{ // ServerSocketを作成 ServerSocket servsock=new ServerSocket(port); // 無限ループ,breakが来るまで while(true){ // クライアントからのアクセスをうけつけた. sock=servsock.accept(); if(type==0){ if(waitingSock==null){ waitingSock=sock; } else{ new Thread(new JankenGame(this,waitingSock,sock)).start(); waitingSock=null; } } else if(type<=5){ new Thread(new JankenRobot(this,sock,type)).start(); waitingSock=null; } } } catch(IOException ioe){ System.out.println(ioe); } } synchronized void println(String s){ System.err.println(s); } public static void main(String args[]){ // インスタンスを1つだけ作る. new JankenServer(Integer.parseInt(args[0]),Integer.parseInt(args[1])); } }