D1.0とSDLでライフゲーム作った。

久方ぶりの投稿。
更新速度こんなんでいいのかと自問中。


週末を使ってD1.0とSDLライフゲーム書いてみた。
ゲームを作るのに、どの "言語+ライブラリ" がいいのかを悩みまくった。


候補としては 「C++/Irrlicht」「C++/SDL」「D/SDL」があって、
最初に「C++/Irrlicht」を触ってた。がしかし。
サンプルコードがコンパイルできず、原因も解決できないという
へたれっぷりを全開にしてしまい、挫折。
それと"ノード"を管理するっていうスタンスがイマイチしっくり来ない。
しかも目指すは2Dゲームなのに・・・って事で、
3D技術的なのはやっぱり全部後回しにすることに。


で、残った2つの選択肢があって
実際どっちでも良かった気はするけど、何となくで「D/SDL」を選択。
(ちなみにD1.0とD2.0のどっちを使うかも迷ったが、安定性を考えてD1.0を選択。)


そっからはDとSDLのリファレンス&サンプルを読みながらゴリゴリと。


以下成果物。
変数名とかエラーメッセージとかが恥ずかしい事になってるのは、
目を瞑ってくださいお願いします><
もし、バイナリ欲しいとかいう変態さんがいらっしゃいましたら言ってください。

//lifegame2.d
import std.stdio;
import std.conv;
import std.random;
import std.date;
import std.string;
import SDL;

SDL_Surface* g_Surface;
Uint32       g_White;
Uint32       g_Black;

struct inhabitant {
  SDL_Rect field;
  bool     living;
}

class island {
private:
  inhabitant[][] m_Fields;
  const int m_Width;
  const int m_Height;
public:

  this( int p_Width, int p_Height ) {

    m_Width       = p_Width;
    m_Height      = p_Height;	
		
    //全フィールドの初期化
    m_Fields.length = m_Height;
    for( int y = 0; y < m_Height; y++ ) {		
      m_Fields[y].length = m_Width;
      for( int x = 0; x < m_Width; x++ ) {			
        m_Fields[y][x].field.x = x;
        m_Fields[y][x].field.y = y;
        m_Fields[y][x].field.w = 1;
        m_Fields[y][x].field.h = 1;
        m_Fields[y][x].living  = false;				
      }
    }
  }
	
  bool opIndex( int p_x, int p_y ) {
    return m_Fields[p_y][p_x].living;
  }
	
  void opIndexAssign( bool p_Value, int p_x, int p_y ) {
    return m_Fields[p_y][p_x].living = p_Value;
  }
	
  void randomize( int p_Probability ) {
    //引数の誕生確率を使ってフィールドのランダム設定
    for( int y = 0; y < m_Height; y++ ) {
      for( int x = 0; x < m_Width; x++ ) {			
        this[x,y] = ( rand()%100 <= p_Probability );				
      }
    }		
  }
	
  void print() {

    for( int y = 0; y < m_Height; y++ ) {
      for( int x = 0;  x < m_Width; x++ ) {			
        if( m_Fields[y][x].living ) {
          SDL_FillRect( g_Surface, &(m_Fields[y][x].field), g_White );
        } else {
          SDL_FillRect( g_Surface, &(m_Fields[y][x].field), g_Black );
        }				
      }
    }		
  }
	
  island next() {
	
    int l = 0, r = 0, u = 0, d = 0, i = 0;
		
    island l_Island = new island( m_Width, m_Height );
		
    for( int y = 0; y < m_Height; y++ ) {
      for( int x = 0; x < m_Width; x++ ) {
			
        i = 0;
				
        l = (x + m_Width - 1) % m_Width;
        r = (x + 1) % m_Width;
        u = (y + m_Height - 1) % m_Height;
        d = (y + 1) % m_Height;
				
        if(this[l,u]) i++; if(this[x,u]) i++; if(this[r,u]) i++;
        if(this[l,y]) i++;                    if(this[r,y]) i++;				
        if(this[l,d]) i++; if(this[x,d]) i++; if(this[r,d]) i++;
				
        if( ( (this[x,y]) && (i==2) ) ||(i==3) ) {
          l_Island[x,y] = true;
        } else {
          l_Island[x,y] = false;
        }
				
      }		
    }		
    return l_Island;		
  }
	
};



int main(string[] args) {

  int l_Width = 0, l_Height = 0, l_Probability = 0;
  rand_seed( getUTCtime(), 0 );
	
	
  //引数チェック
  if( !PropertysCheck( args, l_Width, l_Height, l_Probability ) ) return -1;
	
  //SDL初期化
  if( !Init( l_Width, l_Height )) return -1;
	
  //ライフゲーム第一世代作成	
  island l_Island = new island( l_Width, l_Height );	
  l_Island.randomize( l_Probability );
	
  while( true ) {
	
    l_Island.print();
    l_Island = l_Island.next();

    if( !PollEvent( l_Island ) ) break;

    SDL_Flip( g_Surface );
  }

  End();

  return 0;

}

bool PropertysCheck( string[] p_args, out int p_Width, out int p_Height, out int p_Probability ) {

  if( p_args.length <> 4 ) {
    writefln("Parameters Disposition Failed.\n1:Width, 2:Height, 3:Probability.");
    return false;		
  }
	
  p_Width         = toInt(p_args[1]);
  p_Height        = toInt(p_args[2]);
  p_Probability   = toInt(p_args[3]);
	
  if( (p_Width < 100) || (p_Width > 500) ) {
    writefln("Please Width length between 150 and 1000.");
    return false;
  }
	
  if( (p_Height < 100) || (p_Height > 500) ) {
    writefln("Please Height length between 150 and 1000.");
    return false;
  }
	
  if( (p_Probability <= 0) || (p_Probability >= 100) ) {
    writefln("Please Probability Value between 1 and 99.");
    return false;
  }
	
  return true;

}

bool Init( int p_Width, int p_Height ) {

  writefln("SDL Initialize.");

  if( SDL_Init( SDL_INIT_VIDEO|SDL_INIT_JOYSTICK ) < 0 ) {
    writefln("SDL Initialize Failed. : %s.", SDL_GetError());
    return false;
  }

  SDL_WM_SetCaption( "lifegame", null);

  g_Surface = SDL_SetVideoMode( p_Width, p_Height, 32, 
                                SDL_SWSURFACE //|SDL_FULLSCREEN );

  //SDL_ShowCursor( SDL_DISABLE );

  g_White = SDL_MapRGB( g_Surface.format, 255,255,255);
  g_Black = SDL_MapRGB( g_Surface.format,   0,  0,  0);
	
  return true;

}

void End() {

  writefln("SDL Finalize.");

  SDL_Quit();

}

bool PollEvent( ref island p_Island ) {

  SDL_Event l_Event;
  SDLKey*   l_Key;

  while( SDL_PollEvent(&l_Event) ) {

    switch( l_Event.type ) {
		
      case SDL_MOUSEBUTTONDOWN: {
			
        switch (l_Event.button.button) {
				
          case SDL_BUTTON_LEFT: {
            writefln("push Left x:%d y:%d", l_Event.button.x, l_Event.button.y );
            p_Island[l_Event.button.x, l_Event.button.y] = true;
          }break;
					
          case SDL_BUTTON_RIGHT: {
            writefln("push Right x:%d y:%d", l_Event.button.x, l_Event.button.y );
            p_Island[l_Event.button.x, l_Event.button.y] = false;
          }break;
					
          default: {
          }break;
        }				
      }break;

      case SDL_QUIT:{
        return false;
      }break;

      case SDL_KEYDOWN:{
        l_Key = &(l_Event.key.keysym.sym);
        if(*l_Key == 27) return false;
      }break;
			
      default:{
      }break;

    }

  }
  SDL_Delay(1000/30);

  return true;
}

久しぶりに目で動きが分かるプログラムを組んだ。
ライフゲームも初めて実装したから、なかなか楽しめてよかったー。


本当はもっとDっぽいテクニックが使えればよいのだけど、とりあえずって形で落ち着いた。
これで少しは道が広がったかしら。



何かありましたらご指摘お願いします><