Skip to content

Instantly share code, notes, and snippets.

@tsupo
Created May 15, 2009 08:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tsupo/112112 to your computer and use it in GitHub Desktop.
Save tsupo/112112 to your computer and use it in GitHub Desktop.
quiz client for 'USAGI'
/*
* 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