古いマシン復活計画

自由に使える開発環境がなくて頻繁にイライラするので古いマシンを復活させる計画。古いといいつつ我が家で最高スペックマシン。最高=CPU:Pen4 3GHz,RAM:1GB。
復活といっても単に電源を入れるだけと思っていたけど、単に電源を入れるだけではすまなかった。
まずマシン以前にルータが動かない。ノートPC側からDHCPでアドレスが取得できない。設定で使えないようにしたような気がしたので設定をいじろうとしたところルータのアドレスがわからずハードウェアリセットをかける。それによりなにもせずDHCPが復活。
次に古いマシン側。これは3年前くらいのFreeBSDが入っている。たぶん2年間は起動してない。まず起動時に「recovering vi editor session 」と表示されたまま停止。全然動かない。しかたがないのでCTRL+Cで抜けてそのまま進む。起動した! ログイン。mailが来ていたので読んでviをrecover。カーネルの設定? みたいなものを開いていたけどもうなにしていたかわからないので:q!。reboot。普通に起動。LANケーブルをつなぐ。pingきた。続いてノートPC側からPoderosasshで接続。フリーズ。どこで止まっているか判らないのでputtyで接続。ユーザ名を入力。その後パスワードを聞いてこない。フリーズ。
本体側からssh hoge@localhost。フリーズ。そのまま置いておくと192.168.1.11(ノートPC)がタイムアウトしたみたいなメッセージ出てその後繋がった。入れたけど意味不明。ネットワークがダメなのかと思いノートPCからApacheに接続。接続できず。本体から見るとApacheが起動していないことが発覚。起動させる。起動エラー。/tmp/.s.PGSQL5432に接続できません。なんでPostgreSQLやねん。ここで自作のApacheモジュールが起動時にPostgreSQLに接続していることを思い出す。locate postmaster。起動。apachectrl start!。すでに起動しています。エラーが出つつも起動していたもよう。なんとなく気持ち悪いのでrestart。
ノートPC側からApacheに接続。懐かしいウェブページが! 『かなり適当なシューティング』という本当にカナリテキトウな自作シューティングゲームを発見。コンパイル+実行。操作できない。よくみると「たぶんLinuxでしか動かないでしょう」とか書いてある。なんやねんそれ! 過去の自分に文句を言いつつ、メッセンジャーにいたLinuxの人に、ちょっとこれ動くか見て! と頼む。動くらしい。「ちょっwww」って言われる。なんでFreeBSDで動かないんだろうと眺める。scanfでキー入力が取れない? 入力がバッファリングされていないからタイミング的に取れない? てかなんでcurses使ってないの? 俺。ハマりそうな予感がしたのであきらめる。
とりあえずお茶を飲んでみて再度ノートPCからssh接続。2分後くらいに繋がる。繋がった。繋がった後は普通にサクサク。なんでこんなに接続が遅いのだろう? 認証が遅い? NISとか設定してるわけないないよね? うー、わかんない。前は動いていたはずなのに……。
もうどうせLinux環境が欲しいというのがあるので、明日雑誌付録のLinuxでも入れることに決定。とりあえず必要そうなデータだけFTPからDL。

ということで今日のおまけは……

/*
  かなり適当なシューティング

  注意:
  - たぶんLinuxでしか動かないでしょう
  - ターミナルがECHOしなくなったらresetコマンドを実行してください
  - 全く面白くないでしょう

  操作:
  - カーソルキーで自機を移動させ、スペースで攻撃します
  - 敵に触れるとダメージを受けます

  操作上の注意:
  - カーソルキーを認識しない場合はアルファベットキーを操作用に設定してください
  - 当たり判定が適当なので当たったはずが当たってないこともよくあります

*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <termios.h>

#ifndef FILENO_STDIN
#define FILENO_STDIN 0
#endif


/* ゲーム速度 (1-10) */
/* 数値が多い程遅い  */
#define LEVEL 6

/* キー設定 */
#define LEFT  'h' 
#define RIGHT 'l' 
#define UP    'k' 
#define DOWN  'j' 
#if 0 //Linuxカーソルキー
#define LEFT  (char)0x44 /* 左移動 */
#define RIGHT (char)0x43 /* 右移動 */
#define UP    (char)0x41 /* 上移動 */
#define DOWN  (char)0x42 /* 下移動 */
#endif

#define BOMB  ' ' /* 爆弾ではないけど攻撃!! */

/* Windowのサイズ */
/* 
   X_MIN-----X_MAX/YMIN
    |                |
    ---------------Y_MAX
*/

#define X_MIN 2
#define X_MAX 30
#define Y_MIN 2
#define Y_MAX 15

/* ビーム存在スイッチ */
#define B_OFF 0 /* OFF */
#define B_ON  1 /* ON  */

/* ヒットポイント */
#define HP 10

/* 勝ったかのかー */
#define WIN 1
#define LOSE 0

#define BEEP '\a' /* アラート */

/* ターミナルの設定をいじるので元に戻すために */
static struct termios term_sv;

/* キャラクターの情報 */
struct objinfo {
  int posx;      /* 現在位置X */
  int posy;      /* 現在位置Y */
  size_t sizex;  /* キャラサイズX */
  size_t sizey;  /* キャラサイズY */
  char *obj;     /* キャラ */
};

/* ターミナルを元に戻す */
void end(int sig)
{
  tcsetattr(FILENO_STDIN, TCSANOW, &term_sv);

  if (sig == SIGINT)
    exit(EXIT_SUCCESS);
}

/* シグナル反応をセット */
int sigset(int sig, void *hdl)
{
  struct sigaction siga;

  siga.sa_handler = hdl;
  siga.sa_flags   = 0;
 
  if(sigfillset(&siga.sa_mask) == -1)
    return -1;
  if (sigaction(sig, &siga, 0) == -1)
    return -1;

  return 0;
}

/* ターミナルをROWモードECHO OFFに設定 */
int setrawterm(void)
{
  struct termios term;

  if (tcgetattr(FILENO_STDIN, &term) == -1)
    return -1;

  term_sv = term;

  term.c_lflag &= ~(ECHO | ICANON);
  term.c_cc[VMIN] = 0;  /* non block */
  term.c_cc[VTIME] = 0;

  if (tcsetattr(FILENO_STDIN, TCSANOW, &term) == -1)
    return -1;

  return 0;
}

/* カーソルを移動 */
void curmove(int x, int y)
{
  printf("\x1b[%d;%dH", y, x);
  fflush(stdout);
}

/* キャラを描画 */
void np_write(struct objinfo *obj)
{
  printf("\x1b[%d;%dH%s",
	 obj->posy,
	 obj->posx,
	 obj->obj
	 ), fflush(stdout);
}

/* 画面クリア */
void wn_clear(void)
{
  printf("\x1b[2J");
  fflush(stdout);
}

/* 1/100秒単位のwait */
int mc_sleep(int x)
{
  clock_t s = clock( );
  clock_t c;

  do {
    if ((c = clock( )) == (clock_t)-1)
      return -1;
  } while (1000UL * (c - s) / CLOCKS_PER_SEC <= x);

  return 1;
}

/* キーボード操作 */
void cntl_key(key, self, bomb, b_flag)
     char key;
     struct objinfo *self;
     struct objinfo *bomb;
     char *b_flag;
{
      if (key == LEFT && self->posx != X_MIN)
	self->posx -= 1;
      else if (key == RIGHT && self->posx != X_MAX)
	self->posx += 1;
      else if (key == UP && self->posy != Y_MIN)
	self->posy -= 1;
      else if (key == DOWN && self->posy != Y_MAX)
	self->posy += 1;
      else if (key == BOMB && *b_flag == B_OFF) {
	*b_flag = B_ON;
	bomb->posx = self->posx + strlen(self->obj) / 2;
	bomb->posy = self->posy;
	putchar(BEEP), fflush(stdout);
      }
}

/* 結末 */
void ending(int se)
{
  char *mesg;
  if (se == WIN)
    mesg = "YOU WIN!!";
  else
    mesg = "YOU LOSE..";

  wn_clear( );
  curmove(((X_MAX - X_MIN) - strlen(mesg))  / 2,
	  (Y_MAX - Y_MIN) / 2);
  printf(mesg), fflush(stdout);
  mc_sleep(200);

  curmove(1, 1);
  end(0);
  exit(EXIT_SUCCESS);
}


int main(void)
{
  /* 敵キャラ */
  struct objinfo enemy = {
    17, 6, strlen("(o_o)"), 1, "(o_o)"
  };
  /* 操作キャラ */
  struct objinfo self = {
    X_MAX/2+2, Y_MAX,  strlen("[-0-]"), 1, "[-o-]"
  };
  /* ビーム */
  struct objinfo bomb = {
    0, 0,  strlen("*"), 1, "*"
  };

  int chx = -1;
  int chy = -1;
  char key, b_flag = 0;
  int i, t_hp, s_hp;
  
  t_hp = s_hp = HP;

  if (setrawterm( ) == -1 || sigset(SIGINT, (void *)end) == -1)
    perror("error");

  while (1) { /* メインループ */

    wn_clear( );

    /* 敵の挙動 */
    if (enemy.posx == X_MIN || enemy.posx == X_MAX)
      chx *= -1;
    if (enemy.posy == Y_MIN || enemy.posy == Y_MAX)
      chy *= -1;
    enemy.posx += chx;
    enemy.posy += chy;

    /* ヒットポイントを表示 */
    curmove(2, 0);
    printf("self: %02d enemy:%02d",
	   s_hp, t_hp), fflush(stdout);
    
    /* キャラを描画 */
    np_write(&enemy);    
    np_write(&self);
    
    if (b_flag == B_ON) { /* ビー厶発射中 */
      if (--bomb.posy < Y_MIN)
	b_flag = B_OFF;
      else {
	np_write(&bomb);
	  
	/* ビームの当たり判定 */
	if (bomb.posx >= enemy.posx
	    && bomb.posx <= enemy.posx + enemy.sizex-1
	    && bomb.posy == enemy.posy)
	  {
	    b_flag = B_OFF;
	    putchar(BEEP), fflush(stdout);
	  
	    if (--t_hp == 0) 
	      ending(WIN); /* 勝利 */
	  }
      }
    }
    /* 敵の攻撃当たり判定 */
    if (self.posx + self.sizex-1 >= enemy.posx
	&& self.posx <= enemy.posx + enemy.sizex-1
	&& self.posy == enemy.posy)
      {
	putchar(BEEP), fflush(stdout);
	if (--s_hp == 0)
	  ending(LOSE);
      }

    curmove(0, 0);

    /* キー入力 */
    key = 0;
    for (i = 0; i < LEVEL; i++) {
      scanf("%c", &key);
      mc_sleep(1);
    }
    if (key != 0)
      cntl_key(key, &self, &bomb, &b_flag);
  }

  return 0;
}