Created
May 15, 2009 08:14
-
-
Save tsupo/112112 to your computer and use it in GitHub Desktop.
quiz client for 'USAGI'
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* usagi.c | |
* by H.Tsujimura 17 Sep 1993 | |
* | |
* このusagi.cは、 | |
* 加藤研児(http://www.vector.co.jp/vpack/browse/person/an003664.html)氏 | |
* 作成のクイズ出題プログラムusagi.el(NEmacs上で動作するelispプログラム)用 | |
* のクイズデータフォーマットのファイルを読み込み、クイズを出題、採点する | |
* ためのCプログラムである。 | |
* NEmacsの動いていない環境でもusagi(うさぎ)を楽しみたいというのが、この | |
* プログラムの作成動機である。MS-DOS上でも動作するはずであるが、未確認 | |
* である(クイズの階層が深過ぎると、stack overflowするかもしれない)。 | |
* | |
* なお、このプログラムの配布、利用に関しては、usagi.elの取り扱いと同様 | |
* とする。 | |
* | |
* 遊び方: | |
* (1) うさぎデータ(sailor.tar.Zなど)を用意、インストールする | |
* (2) usagi.cをコンパイルする (例: cc -o usagi usagi.c) | |
* (3) 以下の方法のいづれかを実行する。 | |
* (3-1) トップメニューを記述したUSAGIファイルのあるディレクトリに | |
* カレントディレクトリを移動後 | |
* usagi | |
* を実行する。 | |
* (3-2) usagi directory を実行する。ただし、derectoryは、トップメ | |
* ニューを記述したUSAGIファイルのあるディレクトリである。 | |
* | |
* 2009年5月15日 追記: | |
* 当時の「うさぎ」プロジェクトの痕跡としては | |
* うさぎ(るなお版) | |
* http://www.vector.co.jp/soft/dos/game/se009124.html | |
* があります。当時の話題を追いかけたい人は、1993年夏から冬にかけての | |
* ネットニュース fj.rec.animation 等の過去ログ (今となっては入手困難?) | |
* を参照してみてください。 | |
*/ | |
#include <stdio.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#ifdef MSDOS | |
#define BSIZ 80 | |
#else | |
#define BSIZ BUFSIZ | |
#endif | |
int | |
quiz( fp ) | |
FILE *fp; | |
{ | |
int ret = 'q', opflag = 0, edflag = 0, opnum = 0, ednum = 0, i, num; | |
int qflag = 0, slflag = 0, aflag = 0, slnum, ans, c; | |
int full = 0, point = 10, total = 0, cnt = 0; | |
char *p, buf[BSIZ]; | |
char theme[BSIZ]; | |
char opening[5][BSIZ]; | |
char ending[5][BSIZ]; | |
theme[0] = NULL; | |
while ( ( p = fgets( buf, BSIZ - 1, fp ) ) != NULL ) { | |
if ( !strncmp( p, "@theme{", 7 ) ) { | |
*(p + strlen(p) - 2 ) = NULL; | |
strcpy( theme, p + 7 ); | |
continue; | |
} | |
if ( !opflag && !strcmp( p, "@begin{opening}\n" ) ) { | |
opflag = 1; opnum = 0; | |
continue; | |
} | |
if ( opflag ) { | |
if ( !strcmp( p, "@end{opening}\n" ) ) { | |
opflag = 0; | |
continue; | |
} | |
if ( opnum < 5 ) | |
strcpy( opening[opnum++], p ); | |
continue; | |
} | |
if ( !edflag && !strcmp( p, "@begin{ending}\n" ) ) { | |
edflag = 1; ednum = 0; | |
continue; | |
} | |
if ( edflag ) { | |
if ( !strcmp( p, "@end{ending}\n" ) ) { | |
edflag = 0; | |
continue; | |
} | |
if ( ednum < 5 ) | |
strcpy( ending[ednum++], p ); | |
continue; | |
} | |
if ( !strcmp( p, "@begin{problem}\n" ) ) | |
break; | |
} | |
if ( theme[0] == NULL ) | |
printf( "\n【問題】\n\n" ); | |
else | |
printf( "\n【%s】\n\n", theme ); | |
for ( i = 0; i < opnum; i++ ) | |
fputs( opening[i], stdout ); | |
printf( "\n\n" ); | |
num = 1; qflag = 0; slflag = 0; | |
while ( ( p = fgets( buf, BSIZ - 1, fp ) ) != NULL ) { | |
if ( !strncmp( p, "@rank{", 6 ) ) { | |
*(p + strlen(p) - 2) = NULL; | |
printf("難易度: %s\n", p + 6 ); | |
continue; | |
} | |
if ( !strncmp( p, "@points{", 8 ) ) { | |
*(p + strlen(p) - 2) = NULL; | |
if ( *( p + 8 ) ) { | |
if ( ( point = atoi( p + 8 ) ) <= 0 ) | |
point = 10; | |
} | |
else | |
point = 10; | |
printf("配点: %d\n", point ); | |
continue; | |
} | |
if ( !strncmp( p, "@author{", 8 ) ) { | |
*(p + strlen(p) - 2) = NULL; | |
printf("出題者: %s\n", p + 8 ); | |
continue; | |
} | |
if ( !qflag && !strcmp( p, "@begin{question}\n" ) ) { | |
qflag = 1; | |
printf( "第%2d問\n", num++ ); | |
continue; | |
} | |
if ( qflag ) { | |
if ( !strcmp( p, "@end{question}\n" ) ) | |
qflag = 0; | |
else | |
fputs( p, stdout ); | |
continue; | |
} | |
if ( !slflag && !strcmp( p, "@begin{select}\n" ) ) { | |
slflag = 1; | |
slnum = 1; | |
printf( "\n選択肢:\n" ); | |
continue; | |
} | |
if ( slflag ) { | |
if ( !strcmp( p, "@end{select}\n" ) ) { | |
printf( "\n答えは? " ); | |
do { | |
do { | |
c = getchar(); | |
if ( c == EOF ) { | |
c = '\n'; | |
clearerr( stdin ); | |
} | |
} while ( c == '\n' ); | |
} while ( !(( c >= '1' ) && ( c <= '0' + slnum )) ); | |
if ( c - '0' == ans ) { | |
printf( "\n○ 正解\n\n" ); | |
total += point; | |
cnt++; | |
} | |
else | |
printf( "\n× 不正解\n\n" ); | |
slflag = 0; | |
full += point; | |
continue; | |
} | |
while ( ( *p == ' ' ) || ( *p == '\t' ) ) | |
p++; | |
if ( *p == '@' ) { | |
if ( *(p+1) == '!' ) | |
p += 2; | |
else if ( *(p+1) == '$' ) { | |
p += 2; | |
ans = slnum; | |
} | |
else | |
continue; | |
while ( ( *p == ' ' ) || ( *p == '\t' ) ) | |
p++; | |
printf( " %2d) %s", slnum++, p ); | |
} | |
continue; | |
} | |
if ( !aflag && !strcmp( p, "@begin{answer}\n" ) ) { | |
aflag = 1; | |
printf( "解説:\n" ); | |
continue; | |
} | |
if ( aflag ) { | |
if ( !strcmp( p, "@end{answer}\n" ) ) { | |
aflag = 0; | |
printf( "\n\n" ); | |
continue; | |
} | |
fputs( p, stdout ); | |
continue; | |
} | |
} | |
printf( "\n\n" ); | |
printf("結果: %d問中%d問正解 %d点(%d点満点)\n\n",num-1,cnt,total,full); | |
for ( i = 0; i < ednum; i++ ) | |
fputs( ending[i], stdout ); | |
printf( "\n\nもう一度挑戦しますか? (y/n) : " ); | |
do { | |
c = getchar(); | |
if ( c == EOF ) { | |
clearerr( stdin ); | |
c = ' '; | |
} | |
} while ( ( c != 'y' ) && ( c != 'n' ) ); | |
if ( c == 'y' ) | |
ret = 'r'; | |
return ( ret ); | |
} | |
void | |
challenge( fname ) | |
char *fname; | |
{ | |
FILE *fp; | |
char *p, buf[BSIZ]; | |
int flag, num1, num2, i, c; | |
char topmenu[BSIZ]; | |
char table[20][BSIZ]; | |
char menu[20][BSIZ]; | |
struct stat s; | |
if ( stat( fname, &s ) ) { | |
fprintf( stderr, "usagi: cannot find <%s>.\n", fname ); | |
return; | |
} | |
if ( s.st_mode & S_IFDIR ) { | |
chdir( fname ); | |
if ( ( fp = fopen( "USAGI", "r" ) ) == NULL ) { | |
fprintf( stderr, "usagi: cannot find data file.\n" ); | |
if ( strcmp( fname, "." ) ) | |
chdir( ".." ); | |
return; | |
} | |
while ( ( p = fgets( buf, BSIZ - 1, fp ) ) != NULL ) { | |
if ( !strncmp( p, "@theme{", 7 ) ) { | |
*(p + strlen(p) - 2) = NULL; | |
strcpy( topmenu, p + 7 ); | |
break; | |
} | |
} | |
flag = num1 = 0; | |
while ( ( p = fgets( buf, BSIZ - 1, fp ) ) != NULL ) { | |
if ( !strcmp( p, "@begin{table}\n" ) ) { | |
flag = 1; | |
continue; | |
} | |
if ( flag == 1 ) { | |
if ( !strcmp( p, "@end{table}\n" ) ) | |
break; | |
while ( ( *p >= '0' ) && ( *p <= '9' ) ) | |
p++; | |
if ( *p == '.' ) | |
p++; | |
while ( ( *p == ' ' ) || ( *p == '\t' ) ) | |
p++; | |
*(p + strlen(p) - 1) = NULL; | |
strcpy( table[num1++], p ); | |
} | |
} | |
flag = num2 = 0; | |
while ( ( p = fgets( buf, BSIZ - 1, fp ) ) != NULL ) { | |
if ( !strcmp( p, "@begin{menu}\n" ) ) { | |
flag = 1; | |
continue; | |
} | |
if ( flag == 1 ) { | |
if ( !strcmp( p, "@end{menu}\n" ) ) | |
break; | |
while ( ( *p >= '0' ) && ( *p <= '9' ) ) | |
p++; | |
if ( *p == '.' ) | |
p++; | |
while ( ( *p == ' ' ) || ( *p == '\t' ) ) | |
p++; | |
*(p + strlen(p) - 1) = NULL; | |
strcpy( menu[num2++], p ); | |
} | |
} | |
fclose( fp ); | |
if ( ( num1 == 0 ) || ( num2 == 0 ) || ( num1 != num2 ) ) { | |
printf( "\n【%s】\n\n", topmenu ); | |
printf( " ここには何もありません。\n\n\n" ); | |
if ( strcmp( fname, "." ) ) | |
chdir( ".." ); | |
return; | |
} | |
retry: | |
printf( "\n【%s】\n\n", topmenu ); | |
for ( i = 0; i < num2; i++ ) { | |
printf( "%2d) %s\n", i + 1, menu[i] ); | |
} | |
do { | |
printf( "\nどれに挑戦しますか? (q=終了) : " ); | |
do { | |
c = getchar(); | |
} while ( c == '\n' ); | |
if ( c == EOF ) { | |
clearerr( stdin ); | |
c = '-'; | |
} | |
else if ( (c != 'q') && (c != 'Q') && | |
!((c - '0' >= 1) && (c - '0' <= num1)) ) | |
c = '-'; | |
} while ( c == '-' ); | |
if ( ( c == 'q' ) || ( c == 'Q' ) ) { | |
if ( strcmp( fname, "." ) ) | |
chdir( ".." ); | |
return; | |
} | |
challenge( table[c - '0' - 1] ); | |
goto retry; | |
} | |
else { | |
replay: | |
if ( ( fp = fopen( fname, "r" ) ) == NULL ) { | |
fprintf( stderr, "usagi: cannot find data file.\n" ); | |
return; | |
} | |
c = quiz( fp ); | |
fclose( fp ); | |
if ( ( c == 'q' ) || ( c == 'Q' ) ) | |
return; | |
goto replay; | |
} | |
} | |
void | |
main( argc, argv ) | |
int argc; | |
char *argv[]; | |
{ | |
if ( argc <= 1 ) | |
challenge( "." ); | |
else | |
challenge( argv[1] ); /* コマンドインジェクションに注意 (手抜き) */ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment