c++でcuiのタートルグラフィックス

c++プログラミング第2版 vol.1』という本を読んでタートルグラフィックスの問題が出題されていたので面白がってやってみた。問題4.23。ところで、この本はすごくいいです。工学的な観点、効率の良いプログラムの書き方、オブジェクト指向、そして当然ながら文法が理解できる密度の高い本だと思います。
ちなみにpythonならturtleモジュールでタートルグラフィックスが使えます。

コマンド

  • 1 ペンアップ
  • 2 ペンダウン
  • 3 右に曲がる
  • 4 左に曲がる
  • 5,n n歩前進
  • 6 表示
  • 9 終了

// prob4.23.cpp
#include <iostream>
using namespace std;

enum DIRECTION {UP, RIGHT, DOWN, LEFT};
#define PENUP	(1)
#define PENDOWN (2)
#define TURNR	(3)
#define TURNL	(4)
#define STEP    (5)
#define PRINT	(6)
#define END	(9)

#define SIZE (20) // 1辺の大きさ
class Turtle {
private:
  int floor[SIZE][SIZE];
  int x; // 座標値 (配列の添字ではない)
  int y;
  DIRECTION dir;
  bool pendown;
  void drawDot(int i, int j){ // 座標(i,j)に書き込む
    int h = SIZE/2;
    floor[ h - j -1 ][ h + i -1] = 1; // 座標値を配列の添字に変換して書き込み
  };
  int step(int); // stepsマス前進する。
public:
  Turtle(): pendown(false), dir(UP), x(0), y(0){
    for (int i = 0; i < SIZE; i++)
      for (int j = 0; j < SIZE; j++)
	floor[i][j] = 0;
  }
  void mainLoop();
  void show(); // 表示
};

int Turtle::step(int steps)
{
  int backup;
  switch(dir){
  case UP:    backup = y; y += steps; break;
  case RIGHT: backup = x; x += steps; break;
  case DOWN:  backup = y; y -= steps; break;
  case LEFT:  backup = x; x -= steps; break;
  }

  if (pendown){
    switch(dir){
    case UP:
      for (int i = backup; i <= y; i++) drawDot(x, i);
      break;
    case RIGHT:
      for (int i = backup; i <= x; i++) drawDot(i, y);
      break;
    case DOWN:
      for (int i = backup; i >= y; i--) drawDot(x, i);
      break;
    case LEFT:
      for (int i = backup; i >= x; i--) drawDot(i, y);
      break;
    }
  }
}


void Turtle::mainLoop()
{
  int in;
  while (true){
    scanf("%d", &in);
    if (in == END)break;

    switch(in){
    case PENUP:   pendown = false; break;
    case PENDOWN: pendown = true;  break;
    case TURNR: dir = (DIRECTION)(((int)dir + 1) % 4); break;
    case TURNL: dir = (DIRECTION)(((int)dir + 3) % 4); break;
    case STEP:
      int steps;
      scanf(",%d", &steps);
      step(steps);
      break;
    case PRINT: show(); break;
    default:
      cout << "operation '" << in << "' is not defined." << endl;
    }
  }
}

void Turtle::show()
{
  for (int i = 0; i < SIZE; i++){
    for (int j = 0; j < SIZE; j++)
      cout << (floor[i][j] ? '*' : ' ') <<' ';
    cout << endl;
  }
}

// -------------------------
// -------------------------
int main()
{
  Turtle t;
  t.mainLoop();
  return 0;
}

実行結果

$ cat > dat
2
5,5
3
5,5
3
5,5
3
5,5
1
6
9
$ ./a.out < dat
                                        
                                        
                                        
                                        
                  * * * * * *           
                  *         *           
                  *         *           
                  *         *           
                  *         *           
                  * * * * * *