/* * ブロックスデュオの手を記録する */ #include #include #include #include #define MAX_SIZE 5 /* ペントミノまで */ #define MAX_PIECE 21 #define MAX_X 14 /* ボードは14x14 */ #define MAX_Y 14 char const piece_name[MAX_PIECE]="abcdefghijklmnopqrstu"; struct Piece { int size; int x[MAX_SIZE-1],y[MAX_SIZE-1]; } const piece[MAX_PIECE]={ { 1 }, /* a */ { 2, 0, 0, 0, 0, 1, 0, 0, 0 }, /* b */ { 3, 0, 0, 0, 0, -1, 1, 0, 0 }, /* c */ { 3, 0, 1, 0, 0, -1, 0, 0, 0 }, /* d */ { 4, 0, 0, 0, 0, -1, 1, 2, 0 }, /* e */ { 4, 0, 0,-1, 0, -1, 1, 1, 0 }, /* f */ { 4, 0, 0, 1, 0, -1, 1, 0, 0 }, /* g */ { 4, 1, 0, 1, 0, 0, 1, 1, 0 }, /* h */ { 4, -1, 0, 1, 0, 0, 1, 1, 0 }, /* i */ { 5, 0, 0, 0, 0, -2,-1, 1, 2 }, /* j */ { 5, 0, 0, 0,-1, -2,-1, 1, 1 }, /* k */ { 5, 0, 0,-1,-1, -2,-1, 0, 1 }, /* l */ { 5, 0, 0,-1,-1, -1, 1, 0, 1 }, /* m */ { 5, 0, 0,-1,-1, -1, 1,-1, 1 }, /* n */ { 5, 0, 0, 0, 1, -1, 1, 2, 0 }, /* o */ { 5, 0, 0,-1, 1, -1, 1, 1, 1 }, /* p */ { 5, 0, 0, 1, 2, -2,-1, 0, 0 }, /* q */ { 5, -1, 0, 1, 1, -1,-1, 0, 1 }, /* r */ { 5, -1,-1, 1, 1, -1, 0, 0, 1 }, /* s */ { 5, -1,-1, 1, 0, -1, 0, 0, 1 }, /* t */ { 5, 0,-1, 1, 0, -1, 0, 0, 1 }, /* u */ }; /* ボードは1次元配列で、壁2列、最初の列、…、最後の列、壁2列の順に並べる */ /* 各列は桁数+1の長さで、最後の桁は壁とする */ #define FENCE_LEN (MAX_X*2+2) /* 壁2列の長さ */ #define X 1 /* X方向の添字は1ずつ進む */ #define Y (MAX_X+1) /* Y方向の添字は桁数+1ずつ進む */ int const dir_x[]={ X,-X, Y, Y,-X, X,-Y,-Y }; int const dir_y[]={ Y, Y,-X, X,-Y,-Y, X,-X }; unsigned char board[FENCE_LEN+MAX_Y*Y+FENCE_LEN]; /* ボード(0で初期化) */ #define PASS 0 /* 位置0はパスを表す */ #define START_P1 (FENCE_LEN+4*X+4*Y) /* 先手のスタートポイント */ #define START_P2 (FENCE_LEN+9*X+9*Y) /* 後手のスタートポイント */ /* 0は空、1,2は先手と後手のピース */ #define FENCE 255 /* 壁 */ unsigned char used[2][MAX_PIECE]; /* ピースを使ったか */ struct Move { int p; unsigned char n,d; } history[MAX_PIECE*2]; int history_len=0,history_max=0; /* ボードに壁を設置する */ void init_board(void) { int i; for(i=0;ip==PASS) return "----"; else { static char code[5]; int p=h->p-FENCE_LEN; sprintf(code,"%X%X%c%d",p%Y+1,p/Y+1,piece_name[h->n],h->d); return code; } } /* 4文字コードを表示する */ void print_code(struct Move const *h) { puts(string_code(h)); } /* 置けるか調べる(使ったピースかはチェックしない) */ /* tに手番、pに場所、nに種類、dに向き */ int check(int t,int p,int n,int d) { struct Piece const *q=&piece[n]; int dx=dir_x[d],dy=dir_y[d]; int i; int f; if(t==1 && board[START_P1]==0) { if(p==START_P1) return 1; for(i=0;isize-1;i++) if(p+q->x[i]*dx+q->y[i]*dy==START_P1) return 1; return 0; } if(t==2 && board[START_P2]==0) { if(p==START_P2) return 1; for(i=0;isize-1;i++) if(p+q->x[i]*dx+q->y[i]*dy==START_P2) return 1; return 0; } if(board[p]!=0) return 0; for(i=0;isize-1;i++) if(board[p+q->x[i]*dx+q->y[i]*dy]!=0) return 0; if(board[p-X]==t || board[p+X]==t || board[p-Y]==t || board[p+Y]==t) return 0; f=board[p-X-Y]==t || board[p+X-Y]==t || board[p-X+Y]==t || board[p+X+Y]==t; for(i=0;isize-1;i++) { int p1=p+q->x[i]*dx+q->y[i]*dy; if(board[p1-X]==t || board[p1+X]==t || board[p1-Y]==t || board[p1+Y]==t) return 0; f|=board[p1-X-Y]==t || board[p1+X-Y]==t || board[p1-X+Y]==t || board[p1+X+Y]==t; } return f; } /* パスかどうか調べる */ int nomove(int t) { int x,y,n,d; int p=FENCE_LEN; for(y=0;ysize-1;i++) { int p1=p+q->x[i]*dx+q->y[i]*dy; pa[i+1]=p1; board[p1]=t; } for(d=0;;d++) { int dx=dir_x[d],dy=dir_y[d]; for(i=0;isize;i++) { p=pa[i]; if(board[p]!=t) goto next; for(j=0;jsize-1;j++) if(board[p+q->x[j]*dx+q->y[j]*dy]!=t) goto next; goto found; next:; } } found: used[t-1][n]=1; } h->p=p; h->n=n; h->d=d; if(history_len>history_max) history_max=history_len; print_code(h); } /* ピースを取り除く */ void undo(int t) { struct Move const *h=&history[--history_len]; int p=h->p,n=h->n,d=h->d; if(p!=PASS) { struct Piece const *q=&piece[n]; int dx=dir_x[d],dy=dir_y[d]; int i; board[p]=0; for(i=0;isize-1;i++) board[p+q->x[i]*dx+q->y[i]*dy]=0; used[t-1][n]=0; } } /* 文字を36進数までの桁と見たときの数値を返す。 */ /* 桁になれない文字のときは0を返す。 */ /* 英字はコード順に並んでいるとは限らないので、まじめに変換する。 */ int ctoi(char c) { char buf[2]; buf[0]=c; buf[1]=0; return (int)strtol(buf,NULL,36); } /* 4文字コードを読んでピースを置く */ int input_move(int t) { char buf[6]; int c; int x,y,p,n,d; int f=nomove(t) ? nomove(3-t) ? 2 : 1 : 0; retry: if(f<2) printf("%d-P%d %s ",history_len+1,t,f==0 ? "4文字コード:置く" : "----:パス" ); printf("E:記録終了 "); if(history_len>0) printf("B:一手戻る "); if(history_lenp; n=h->n; d=h->d; } putchar('?'); if(fgets(buf,sizeof buf,stdin)==NULL) exit(1); if(buf[0]==0 || buf[0]=='\n') goto retry; if(buf[1]=='\n') { c=toupper((unsigned char)buf[0]); if(c=='E') return 1; if(history_len>0 && c=='B') { undo(3-t); return 0; } if(history_len=MAX_X) goto bad; y=ctoi(buf[1])-1; if(y<0 || y>=MAX_Y) goto bad; n=ctoi(buf[2])-10; if(n<0 || n>=MAX_PIECE) goto bad; d=ctoi(buf[3]); if(d<0 || d>=8) goto bad; if(buf[4]!='\n') goto bad; p=FENCE_LEN+x*X+y*Y; put: if(used[t-1][n]) { puts("使用済み"); goto retry; } if(!check(t,p,n,d)) { puts("置けません"); goto retry; } put(t,p,n,d); return 0; bad: puts("入力誤り"); if(strchr(buf,'\n')==NULL) { while((c=getchar())!='\n') if(c==EOF) exit(1); } goto retry; } /* HTML出力の補助関数 */ static int write_beg_font(FILE *f,int t) { static char const *a[]={"sp","p1","p2"}; return fprintf(f,"",a[t])<0; } static int write_end_font(FILE *f) { return fputs("",f)==EOF; } /* ファイル名を読んでHTMLファイルを出力する */ void write_html(void) { char const *head= "\n" "\n" "\n" "\n" "\n" "\n" "
\n" "
\n"
    "先手:P1\n"
    "後手:P2\n";
  char const *middle=
    "
\n" "
\n" "
\n";
  char const *tail=
    "
\n" "
\n" "\n" "\n"; int b[MAX_Y*Y]; int i,k,p,x,y; int p1=0,p2=0; FILE *f; char buf[256]; char *bufp; int c; printf("HTMLファイル名?"); if(fgets(buf,sizeof buf,stdin)==NULL) exit(1); if(buf[0]==0 || buf[0]=='\n') return; if((bufp=strchr(buf,'\n'))==NULL) { puts("長過ぎます"); while((c=getchar())!='\n') if(c==EOF) exit(1); return; } *bufp=0; if((f=fopen(buf,"r"))!=NULL) { char buf1[3]; fclose(f); printf("%sを上書きしてよいですか(Y/N)?",buf); if(fgets(buf1,sizeof buf1,stdin)==NULL) exit(1); if(strchr(buf1,'\n')==NULL) { while((c=getchar())!='\n') if(c==EOF) exit(1); } if(toupper((unsigned char)buf1[0])!='Y') return; } if((f=fopen(buf,"w"))==NULL) goto error0; if(fputs(head,f)==EOF) goto error; for(i=0;ip,n=h->n,d=h->d; if(p!=PASS) { struct Piece const *q=&piece[n]; int dx=dir_x[d],dy=dir_y[d]; int i; p-=FENCE_LEN; b[p]=k+1; for(i=0;isize-1;i++) b[p+q->x[i]*dx+q->y[i]*dy]=k+1; if((k&1)==0) p1+=q->size; else p2+=q->size; } } if(fputs("\n ",f)==EOF) goto error; for(x=0;x%3d\n" "P2:%3d\n",p1,p2)<0) goto error; if(fputs(middle,f)==EOF) goto error; for(k=0;k%2d:",(k&1)+1,k+1)<0) goto error; if(fputs(string_code(&history[k]),f)==EOF) goto error; if(fputc('\n',f)==EOF) goto error; } if(fputs(tail,f)==EOF) goto error; if(fclose(f)==EOF) goto error; printf("%sに出力しました\n",buf); return; error: fclose(f); error0: puts("書き込みエラーです"); } /* コマンド入力ループ */ void command_loop(void) { int t=1; char buf[3]; int c; record: for(;;) { print_board(); if(input_move(t)) break; t=3-t; } command: printf("P:4文字コード表示 H:HTML出力 R:記録再開 Q:終了 ?"); /* 4文字コードのファイル読み書き機能は未実装 */ if(fgets(buf,sizeof buf,stdin)==NULL) exit(1); c=toupper((unsigned char)buf[0]); if(c==0 || c=='\n') goto command; if(buf[1]!='\n') goto bad; if(c=='P') { int k; for(k=0;k