鬼ごっこゲーム
非同期通信の実験
作業環境
- Cygwinのホームディレクトリ以下に
ホーム/soc/
あるいは
ホーム/soc/tag/
のようなディレクトリを作成し、そこで作業を行う。
ソース
tag.h
/*********************************************/ /* File name: tag.h */ /* Project name: socket/tag */ /* Month/Year: Jan/2003 */ /* Author: Shuichi YUKITA */ /*********************************************/ #include <sys/types.h> #include "mylib.h" #define PORT 50001 #define HOSTNAME_LENGTH 64
session.h
/*********************************************/ /* File name: session.h */ /* Project name: socket/tag */ /* Month/Year: Jan/2003 */ /* Author: Shuichi YUKITA */ /*********************************************/ extern void session_init(int soc, char mc, int mx, int my, char pc, int px, int py); extern void session_loop();
session.c
/*********************************************/ /* File name: session.c */ /* Project name: socket/tag */ /* Month/Year: Jan/2003 */ /* Author: Shuichi YUKITA */ /*********************************************/ #include <sys/types.h> #include <curses.h> #include <signal.h> #define BUF_LEN 20 #define MIN_X 1 #define MIN_Y 1 #define MAX_X 60 #define MAX_Y 20 #define NORTH 'k' #define SOUTH 'j' #define EAST 'l' #define WEST 'h' #define QUIT 'q' static int session_soc; /* socket */ static fd_set mask; /* fd mask */ static int width; /* width of the mask */ static char my_char, peer_char; /* character */ typedef struct{ int x,y; /* current position */ char look; /* character */ } PLAYER; static PLAYER me, peer; /* 自分と相手の状態を保持する変数 */ static char buf[BUF_LEN]; /* 送受信兼用バッファ */ static WINDOW *win; /* 表示用ウィンドウ */ /* session モジュールにプライベートな関数 */ static void hide(PLAYER *who); static void show(PLAYER *who); static int update(PLAYER *who, int c); static int interpret(PLAYER *who); static void die(); /* session モジュールの初期化 */ void session_init(int soc, char mc, int mx, int my, char pc, int px, int py) { session_soc = soc; width = soc + 1; FD_ZERO(&mask); FD_SET(0, &mask); FD_SET(session_soc, &mask); me.look = mc; peer.look = pc; me.x = mx; me.y = my; peer.x = px; peer.y = py; /* curses initialization */ initscr(); signal(SIGINT, die); /* window border */ win = newwin(MAX_Y + 2, MAX_X + 2, 0, 0); box(win, '|', '-'); /* terminal settings */ cbreak(); noecho(); } /* session メインループ */ void session_loop() { int c,flag; fd_set readOk; show(&me); flag = 1; while(1){ /* select の前に毎回 readOk を初期化する。 */ readOk = mask; select(width,(fd_set *)&readOk,NULL,NULL,NULL); /* キーボードからの入力ありか? */ if ( FD_ISSET(0, &readOk ) ){ c = getchar(); hide(&me); flag = update(&me, c); show(&me); write(session_soc,buf,BUF_LEN); if(flag == 0) break; } /* ソケットにデータありか? */ if ( FD_ISSET(session_soc, &readOk ) ){ read(session_soc,buf,BUF_LEN); hide(&peer); flag = interpret(&peer); show(&peer); if(flag == 0) break; } } /* 端末属性を復旧して終わる */ die(); } static void show(PLAYER *who) { wmove(win, who->y, who->x); waddch(win, who->look); wmove(win, who->y, who->x); wrefresh(win); } static void hide(PLAYER *who) { wmove(win, who->y, who->x); waddch(win, ' '); } static int update(PLAYER *who, int c) { switch(c){ case WEST: if ( who->x > MIN_X ) who->x--; break; case SOUTH: if ( who->y < MAX_Y ) who->y++; break; case NORTH: if ( who->y > MIN_X ) who->y--; break; case EAST: if ( who->x < MAX_X ) who->x++; break; case QUIT: buf[0]=QUIT; return 0; default: break; } /* 更新された位置データを送信用文字列に変換する。 */ sprintf(buf, "%d %d\n", who->x, who->y); return 1; } static int interpret(PLAYER *who) { /* もし相手が終了を希望したら */ if (buf[0] == 'q') return 0; /* 受信文字列から位置データに変換する。 */ sscanf(buf, "%d %d", &who->x, &who->y); return 1; } static void die() { endwin(); /* 端末属性の復旧 */ exit(); }
server.c
/*********************************************/ /* File name: server.c */ /* Project name: socket/tag */ /* Month/Year: Jan/2003 */ /* Author: Shuichi YUKITA */ /*********************************************/ #include "session.h" #include "tag.h" main() { int soc; /* socket */ if( (soc = setup_server(PORT) ) == -1){ exit(1); } session_init(soc, 'o', 1,1, 'x',10, 10); session_loop(); }
client.c
/*********************************************/ /* File name: client.c */ /* Project name: socket/tag */ /* Month/Year: Jan/2003 */ /* Author: Shuichi YUKITA */ /*********************************************/ #include "session.h" #include "tag.h" main() { int soc; /* socket */ char hostname[HOSTNAME_LENGTH]; printf("input server's hostname: "); fgets(hostname, HOSTNAME_LENGTH, stdin); chop_newline(hostname, HOSTNAME_LENGTH); if( (soc = setup_client(hostname,PORT) ) == -1){ exit(1); } session_init(soc, 'x', 10,10, 'o',1, 1); session_loop(); }
ビルド Makefile
#*********************************************/ #* File name: Makefile */ #* Project name: socket/tag */ #* Month/Year: Jan/2003 */ #* Author: Shuichi YUKITA */ #*********************************************/ # # "root.o" target is implicitly built by # $(COMPILE.c) -o root.o root.c MYLIBDIR=../mylib CFLAGS=-I$(MYLIBDIR) RM=rm -f all: s c s: server.o session.o $(LINK.c) -o s server.o session.o $(MYLIBDIR)/mylib.a -lcurses c: client.o session.o $(LINK.c) -o c client.o session.o $(MYLIBDIR)/mylib.a -lcurses server.o: server.c tag.h session.h client.o: client.c tag.h session.h clean: $(RM) s c *.o *~
実行
初めの一歩 と同じ。