見出し画像

コマンド(32)

Print helpコマンド('?')

Print helpコマンド('?')は、キーとコマンドの対応表を画面へプリントさせるための操作です。

次のソースコードは、Print helpコマンドの実装部分です。関数helpを呼び出しています。

--- command.c ---
162: when '?' : after = FALSE; help();

関数help

関数helpは、指定されたコマンド1つのヘルプ項目を表示するか、あるいはすべてのヘルプ項目を表示します。

次のソースコードは関数helpの実装部分です。処理の大まかな流れはキー入力を行い、ヘルプを表示しています。

'*'を入力された場合はすべてのヘルプ項目を、それ以外の文字が入力された場合は、入力されたキーに対応するコマンドのヘルプ項目を1つだけを表示します。

すべてのヘルプ項目を表示する場合は画面クリアしますが、コマンド1つのヘルプ項目を表示する場合は、画面をクリアせず、最上段にヘルプ項目を表示します。

--- command.c ---
387: /*
388:  * help:
389:  *    Give single character help, or the whole mess if he wants it
390:  */
391: 
392: help()
393: {
394:     register struct h_list *strp = helpstr;
395:     register char helpch;
396:     register int cnt;
397: 
398:     msg("Character you want help for (* for all): ");
399:     helpch = readchar();
400:     mpos = 0;
401:     /*
402:      * If its not a *, print the right help string
403:      * or an error if he typed a funny character.
404:      */
405:     if (helpch != '*')
406:     {
407:         wmove(cw, 0, 0);
408:         while (strp->h_ch)
409:         {
410:             if (strp->h_ch == helpch)
411:             {
412:                 msg("%s%s", unctrl(strp->h_ch), strp->h_desc);
413:                 break;
414:             }
415:             strp++;
416:         }
417:         if (strp->h_ch != helpch)
418:             msg("Unknown character '%s'", unctrl(helpch));
419:         return;
420:     }
421:     /*
422:      * Here we print help for everything.
423:      * Then wait before we return to command mode
424:      */
425:     wclear(hw);
426:     cnt = 0;
427:     while (strp->h_ch)
428:     {
429:         mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrl(strp->h_ch));
430:         waddstr(hw, strp->h_desc);
431:         cnt++;
432:         strp++;
433:     }
434:     wmove(hw, LINES-1, 0);
435:     wprintw(hw, "--Press space to continue--");
436:     draw(hw);
437:     wait_for(' ');
438:     wclear(hw);
439:     draw(hw);
440:     wmove(cw, 0, 0);
441:     wclrtoeol(cw);
442:     status();
443:     touchwin(cw);
444: }

構造体h_list

394行目で参照している配列helpstrにヘルプ項目の内容が定義されています。

ヘルプ項目は構造体h_listで管理されていて、コマンドに対応するキーとコマンドのナメを対応づけています。現代的な呼び方をするのであれば、ディクショナリです。

次のソースコードは構造体h_listを定義いている部分です。

--- rogue.h ---
263: /*
264:  * Help list
265:  */
266:
267: struct h_list {
268:     char h_ch;
269:     char *h_desc;
270: } helpstr[];

次のソースコードはヘルプ項目を定義している部分です。

--- init.c ---
469: struct h_list helpstr[] = {
470:     '?',       "	prints help",
471:     '/',       "	identify object",
472:     'h',       "	left",
473:     'j',       "	down",
474:     'k',       "	up",
475:     'l',       "	right",
476:     'y',       "	up & left",
477:     'u',       "	up & right",
478:     'b',       "	down & left",
479:     'n',       "	down & right",
480:     'H',       "	run left",
481:     'J',       "	run down",
482:     'K',       "	run up",
483:     'L',       "	run right",
484:     'Y',       "	run up & left",
485:     'U',       "	run up & right",
486:     'B',       "	run down & left",
487:     'N',       "	run down & right",
488:     't',       "<dir>	throw something",
489:     'f',       "<dir>	forward until find something",
490:     'p',       "<dir>	zap a wand in a direction",
491:     'z',       "	zap a wand or staff",
492:     '>',       "	go down a staircase",
493:     's',       "	search for trap/secret door",
494:     ' ',       "	(space) rest for a while",
495:     'i',       "	inventory",
496:     'I',       "	inventory single item",
497:     'q',       "	quaff potion",
498:     'r',       "	read paper",
499:     'e',       "	eat food",
500:     'w',       "	wield a weapon",
501:     'W',       "	wear armor",
502:     'T',       "	take armor off",
503:     'P',       "	put on ring",
504:     'R',       "	remove ring",
505:     'd',       "	drop object",
506:     'c',       "	call object",
507:     'o',       "	examine/set options",
508:     CTRL(L),   "	redraw screen",
509:     CTRL(R),   "	repeat last message",
510:     ESCAPE,    "	cancel command",
511:     'v',       "	print program version number",
512:     '!',       "	shell escape",
513:     'S',       "	save game",
514:     'Q',       "	quit",
515:     0, 0
516: };

これまでコマンドの説明をしてきましたが、ヘルプに記載されているものと順序が異なるうことに気づいた人もいらっしゃると思います。それはcommand.cのソースコードを参照しているためです。

Print helpコマンド('?')とソースコードcommand.c、両者のコマンド順を比較してみましょう。順序がほぼ異なっているということがわかると思います。

?/hjklyubnHJKLYUBNtfpz>s iIqrewWTPRdco^L^R^[v!SQ
f!hjklyubnHJKLYUBNtQiIdqrewWTPRoc><?/szpv^L^RS ^P^[@C^I^W^D^U^F^X^T^E^A^C^N^H

また、ソースコードcommand.cのほうがたくさんのコマンドが実装されているのもわかります。理由は後述するウィザード用のコマンドが実装されているためです。これらのコマンドには正式なコマンド名はついていませんが、
説明するにあたって、適当な名前を振っていきます。

関数helpの改良点

関数helpの429行目は、ヘルプの1行を表示するためのカーソル開始位置を算出していますが、画面サイズが80✕25であることを前提にしていることがわかります。

当時は画面サイズがおおむねそうだったのかもしれませんが、現代の端末画面のように可変サイズを考慮するのであれば、段組とページ送りを行う処理にしておくと安全です。

次のソースコードは段組とページ送りを行うサンプルです。

#include <stdio.h> #include <ncurses.h>

int main(void) {
   initscr();
   clear();

   int i = 0;
   int max_line = LINES - 3;
   int multi_column_size = COLS / 40;
   int multi_column_width = COLS / multi_column_size;
   int help_item_count = 60;
   char pages[80] = "";
   int page = 1;
   int max_page = help_item_count / (max_line * multi_column_size) + 1;

   for(i = 0; i < help_item_count; i++) {
       if ((i % (max_line * multi_column_size)) == 0) {
           if (i) {
               mvaddstr(LINES - 1, 0, "--More--");
               getch();
               clear();
               page++;
           }
           sprintf(pages, "Page %d/%d", page, max_page);
           mvaddstr(0, 0, pages);
       }
       mvaddstr((i % max_line) + 1,
       ((i / max_line) % multi_column_size) * multi_column_width,
               "help string");
   }
   refresh();

   getchar();
   endwin();
   return 0;
}

実行結果

段組するヘルプ

段組するヘルプ2

次回はIdentify objectコマンド('/')の説明をします。

この記事が気に入ったら、サポートをしてみませんか?
気軽にクリエイターの支援と、記事のオススメができます!
最後まで読んでいただき、ありがとうございました!
6
Cプログラミングの話題を中心としたマガジンを作成しています。完成したマガジンは電子書籍にまとめなおしてAmazonで販売しています。 Amazon著者ページ https://amzn.to/2IIHyv0

こちらでもピックアップされています

コードリーディング - rogue -
コードリーディング - rogue -
  • 65本

1980年代に作成されたヒットゲーム『rogue』(ローグ)。現在でも不思議なダンジョンシリーズをはじめ、色々なゲームにリメイクされています。 ローグの魅力は何回でも遊べることですが、それはダンジョンの自動生成機能があってのものです。 ダンジョンの自動生成機能では、どのようなアルゴリズムを使い、どのようなデータ構造へ落とし込むのか。これは多くのプログラマが興味を抱く部分です。 本マガジンは、ソースコードを読みながら自動生成機能を追い、アルゴリズムやデータ構造を解説していきます。 対象読者:Cプログラミング中級以上

コメントを投稿するには、 ログイン または 会員登録 をする必要があります。