詳細
プロトコル(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]));
}
}