<?xml version="1.0" encoding="UTF-8" ?> <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>アルゴリズム</title><link>http://blogs.wankuma.com/izmktr/category/1787.aspx</link><description>アルゴリズム</description><managingEditor>出水 洸太郎</managingEditor><dc:language>ja-JP</dc:language><generator>.Text Version 0.95.2004.102</generator><item><dc:creator>出水 洸太郎</dc:creator><title>[アルゴリズム]移動の探索</title><link>http://blogs.wankuma.com/izmktr/archive/2011/01/25/196647.aspx</link><pubDate>Tue, 25 Jan 2011 09:36:00 GMT</pubDate><guid>http://blogs.wankuma.com/izmktr/archive/2011/01/25/196647.aspx</guid><wfw:comment>http://blogs.wankuma.com/izmktr/comments/196647.aspx</wfw:comment><comments>http://blogs.wankuma.com/izmktr/archive/2011/01/25/196647.aspx#Feedback</comments><slash:comments>581</slash:comments><wfw:commentRss>http://blogs.wankuma.com/izmktr/comments/commentRss/196647.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/izmktr/services/trackbacks/196647.aspx</trackback:ping><description>&lt;p&gt;移動力にしたがってマップを移動していくタイプの&lt;br&gt;戦略シミュレーションゲームがあります。&lt;/p&gt; &lt;p&gt;昔だと大戦略といえば通用したのでしょうが、&lt;br&gt;最近だとスーパーロボット大戦とかファイアーエムブレムとか言えばいいんでしょうかね？&lt;/p&gt; &lt;p&gt;その移動アルゴリズムについて作成してみました。&lt;br&gt;普通に書くとこんな感じですかね？&lt;/p&gt; &lt;div class="wlWriterEditableSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:810ecd65-26bf-45bb-aee8-42e595902783" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c"&gt;class Board{
public:
  int mx, my;
  int *bd;

  Board(int mx, int my):mx(mx), my(my){
    bd = new int [mx * my];
  }
  ~Board(){
    delete [] bd;
  }

  int &amp;amp; operator()(int x, int y){return bd[mx * y + x];}
  int size()const{return mx * my;}

  void fill(int a){
    for(int i = 0; i &amp;lt; size(); i++){bd[i] = a;}
  }
};

bool range(int x, int y, Board &amp;amp;board){
  if (x &amp;lt; 0 || y &amp;lt; 0) return false;
  if (board.mx &amp;lt;= x || board.my &amp;lt;= y) return false;
  return true;
}
void check(Board &amp;amp;map, Board &amp;amp;out, int x, int y, int now = 0){
  // ボード範囲内かのチェック
  if (range(x, y, map) == false) return;

  int move = map(x, y);
  // 空白か移動力が大きい(遠回りしている)なら探索する
  if (out(x, y) == 0 || move + now &amp;lt; out(x, y)){
    out(x, y) = move + now;
    count++;
    check(map, out, x + 1, y, now + move);
    check(map, out, x - 1, y, now + move);
    check(map, out, x, y + 1, now + move);
    check(map, out, x, y - 1, now + move);
  }
}

int main(void){
  Board board(10, 10);
  Board idou(10, 10);

  board.fill(1);
  idou.fill(0);

  check(map, out, 7, 5);
}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Boardクラスは単なる二次元配列を作るためのクラスです。&lt;br&gt;boardがそのマスの地形(必要移動力)が入った変数、&lt;br&gt;idouがそのマスに移動するために必要な移動力を計算する変数となっています。&lt;br&gt;check関数を実行すると、idouに計算結果が帰ってきます。&lt;/p&gt;
&lt;p&gt;さて、これは余り効率が良い方法とは言えません。&lt;/p&gt;
&lt;p&gt;再帰を使っていますので、まず今回の場合は右、左、下、上の順で探索しています。&lt;br&gt;最初に右に移動した場合を全て探索した後、次は左、下、上、というふうに探索するわけです。&lt;br&gt;すると、以下のような状態が起こります。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://izmktr.wankuma.com/201101/tansa01.jpg"&gt; &lt;/p&gt;
&lt;p&gt;A地点からB地点に行く場合、明らかに遠回りしています。&lt;br&gt;しかし、再帰を使った場合は、下→左というルートを探索する前に&lt;br&gt;右→下→左→左というルートを確認します。&lt;br&gt;実際は、これ以上の更なる無駄なルートを探索しています。&lt;/p&gt;
&lt;p&gt;そこで、まずは１歩で移動できるマスすべてを探索した後、&lt;br&gt;２歩で移動できるマス、３歩で移動できるマス、という風に探索するとよいでしょう。&lt;/p&gt;
&lt;p&gt;この方法を使うためにキューを使います。&lt;br&gt;check関数は以下のように変更します。&lt;/p&gt;
&lt;div class="wlWriterEditableSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:91b70b3e-eaa8-4143-86c3-55b6c1013cc8" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c"&gt;struct Data{
  int x, y, move;
  Data(int x, int y, int move):x(x), y(y), move(move){}
};

void check(Board &amp;amp;map, Board &amp;amp;out, int x, int y){
  std::deque&amp;lt;Data&amp;gt; queue;
  queue.push_back(Data(x, y, 0));

  while(!queue.empty()){
    Data &amp;amp;dat = queue.front();

    if (range(dat.x, dat.y, map)){
      int move = map(dat.x, dat.y);
      if (out(dat.x, dat.y) == 0 || move + dat.move &amp;lt; out(dat.x, dat.y)){
        out(dat.x, dat.y) = move + dat.move;
        count++;
        queue.push_back(Data(dat.x + 1, dat.y, dat.move + move));
        queue.push_back(Data(dat.x - 1, dat.y, dat.move + move));
        queue.push_back(Data(dat.x, dat.y + 1, dat.move + move));
        queue.push_back(Data(dat.x, dat.y - 1, dat.move + move));
      }
    }
    queue.pop_front();
  }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;計算したい物をキューの後ろに入れ、先頭から計算していきます。&lt;br&gt;まず、スタート地点を登録して、その後１歩で移動できる４箇所がキューに入ります。&lt;br&gt;それらを順に計算し、２歩で移動できる場所が後ろに追加されます。&lt;br&gt;キューなので、１歩で移動できる場所がすべて探索された後、２歩目の探索が始まります。&lt;/p&gt;
&lt;p&gt;最初の再帰を使う方法を「深さ優先探索」、次のキューを使う方法を「幅優先探索」と言います。&lt;br&gt;どちらを使うか、というのは問題によって様々なのですが、&lt;br&gt;今回の場合は一歩目、二歩目という感じで順番に探索するほうが向いています。&lt;/p&gt;
&lt;p&gt;次回はキューの大きさについて考えてみます。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/izmktr/aggbug/196647.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>出水 洸太郎</dc:creator><title>[C++]ランダム大地に立つ</title><link>http://blogs.wankuma.com/izmktr/archive/2010/01/19/185168.aspx</link><pubDate>Tue, 19 Jan 2010 22:35:00 GMT</pubDate><guid>http://blogs.wankuma.com/izmktr/archive/2010/01/19/185168.aspx</guid><wfw:comment>http://blogs.wankuma.com/izmktr/comments/185168.aspx</wfw:comment><comments>http://blogs.wankuma.com/izmktr/archive/2010/01/19/185168.aspx#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://blogs.wankuma.com/izmktr/comments/commentRss/185168.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/izmktr/services/trackbacks/185168.aspx</trackback:ping><description>&lt;p&gt;標準のrand関数は余り使わない方がいい、というのは知っているでしょうか。&lt;br&gt;これは&lt;a href="http://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E5%90%88%E5%90%8C%E6%B3%95"&gt;線形合同法&lt;/a&gt;に起因する問題で、乱数といいつつも、結構規則正しいという特徴があります。&lt;/p&gt; &lt;p&gt;それを改良した乱数と言うとメルセンヌ・ツイスタが有名ですが、これもちょっとした問題があります。&lt;br&gt;それは、メモリの消費がかなり多い！&lt;/p&gt; &lt;p&gt;周期が2^19937 - 1 ということは、19937ビットのデータが必要なのです。&lt;br&gt;その大きさは約2.5KBですが、いくら高品質とはいえ、ちょっと量が多いですね。&lt;/p&gt; &lt;p&gt;それに、2^19937 - 1って数は6000桁以上！&lt;br&gt;宇宙の果てまで数えられる数の周期が必要な場面はそんなにないでしょう。&lt;/p&gt; &lt;p&gt;そこで、今回紹介するお手頃な乱数が、xorshift。&lt;br&gt;ソースは以下の通り。&lt;/p&gt; &lt;p&gt; &lt;div class="wlWriterEditableSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:f597b90f-68f2-4527-83bb-087f2411d4cc" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c"&gt;unsigned long xor128(){ 
  static unsigned long x=123456789,y=362436069,z=521288629,w=88675123; 
  unsigned long t; 
  t=(x^(x&amp;lt;&amp;lt;11));x=y;y=z;z=w; return( w=(w^(w&amp;gt;&amp;gt;19))^(t^(t&amp;gt;&amp;gt;8)) ); 
} 
&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;これだけのソースですが、2^128 - 1という周期をもつ乱数で、たった16バイトしか消費しません。&lt;br&gt;staticで確保しているx, y, z, wの4つの値を保存しておくだけで、前回の乱数の続きから生成できるため、&lt;br&gt;シリアライズ化するのも簡単というとてもお手軽かつ便利な乱数です。&lt;/p&gt;
&lt;p&gt;なお、乱数の種(seed)ですが、x, y, z, wのすべてが0でなければどんな数でもいいです。&lt;br&gt;これは、128ビットの数値と見なすと、周期が2^128 - 1ということで、0以外の数値であれば、&lt;br&gt;循環する数列のどれかの要素になる、というわけです。&lt;/p&gt;
&lt;p&gt;そういえば、メルセンヌ・ツイスタを改良した&lt;a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index-jp.html"&gt;SFMT&lt;/a&gt;というものもあるみたいですね。&lt;br&gt;乱数は奥が深いです。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/izmktr/aggbug/185168.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>出水 洸太郎</dc:creator><title>[アルゴリズム]とらいあんぐるはーど</title><link>http://blogs.wankuma.com/izmktr/archive/2009/06/28/176696.aspx</link><pubDate>Sun, 28 Jun 2009 02:15:00 GMT</pubDate><guid>http://blogs.wankuma.com/izmktr/archive/2009/06/28/176696.aspx</guid><wfw:comment>http://blogs.wankuma.com/izmktr/comments/176696.aspx</wfw:comment><comments>http://blogs.wankuma.com/izmktr/archive/2009/06/28/176696.aspx#Feedback</comments><slash:comments>65</slash:comments><wfw:commentRss>http://blogs.wankuma.com/izmktr/comments/commentRss/176696.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/izmktr/services/trackbacks/176696.aspx</trackback:ping><description>&lt;p&gt;&lt;a href="http://blogs.wankuma.com/izmktr/archive/2009/06/26/176657.aspx"&gt;[アルゴリズム]六角対応&lt;/a&gt; の続きです。&lt;/p&gt; &lt;p&gt;前回ヘックスマップにおけるデータ表現を書きました。&lt;br&gt;ならば次はこれだ！！&lt;/p&gt; &lt;p&gt;&lt;img src="http://izmktr.wankuma.com/200906/tri_1.png"&gt; &lt;/p&gt; &lt;p&gt;正三角形を敷き詰めた形ですね。&lt;br&gt;やっぱりこの形をそのまま使うのは難しいので、これを正方形の形に変換します。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;img src="http://izmktr.wankuma.com/200906/tri_2.png"&gt;  &lt;/p&gt; &lt;p&gt;上の形を変換したのが下の形です。&lt;br&gt;見やすさのために四隅を切り落としています。&lt;/p&gt; &lt;p&gt;赤い線が目立ちますが、これは壁です。&lt;br&gt;黄色なら下、水色なら上側が壁になり、ここは通行できません。&lt;/p&gt; &lt;p&gt;三角形と見比べてみると、この赤い線は頂点になります。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;img src="http://izmktr.wankuma.com/200906/tri_3.png"&gt; &lt;/p&gt; &lt;p&gt;1マスで移動できる領域です。&lt;br&gt;上三角と下三角の形の二種類があるので、移動できる場所が異なります。&lt;/p&gt; &lt;p&gt;前回同様、距離の図です。&lt;/p&gt; &lt;p&gt;&lt;img src="http://izmktr.wankuma.com/200906/tri_4.png"&gt; &lt;/p&gt; &lt;p&gt;これも、ややこしいですが、前回同様Xの移動量とYの移動量で分けてみます。&lt;/p&gt; &lt;p&gt;&lt;img src="http://izmktr.wankuma.com/200906/tri_5.png"&gt; &lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;紫の領域は非常に素直で、X+Yがそのまま距離となります。&lt;br&gt;しかし、橙の領域はなんだか変なことになっています。&lt;br&gt;一番下の行を見ると、76767と交互に数字が並んでいる、ってのはわかるわけですが…。&lt;/p&gt; &lt;p&gt;まず、橙のマスの中で、偶数になっているものを見ましょう。&lt;br&gt;すると、必ず市松模様上に配置され、しかもその値はYの移動量の2倍です。&lt;/p&gt; &lt;p&gt;あとは、奇数のマスは偶数マスの+1か-1で、その法則も簡単に割り出せます。&lt;br&gt;それを踏まえて作ったソースがこちら。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;div class="wlWriterEditableSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:6fc82936-8916-437c-9f73-354dc6049c63" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c"&gt;/* 上方向に移動する場合、Yはマイナスになる */
/* IsUpperは、そのマスが上三角(△) ならばtrue */
int distanct(int x, int y, int dx, int dy){
  int ax = abs(dx);
  int ay = abs(dy);
  if (ax &amp;lt; ay){
    /* Yの移動量が多い場合 */
    if (IsUpper(x, y) == (0 &amp;lt; dy))
      /* 最初の移動方向に壁なし */
      return ay * 2 - (ax + ay) % 2;
    }else{
      /* 最初の移動方向に壁あり */
      return ay * 2 + (ax + ay) % 2;
    }
  }else{
    /* Xの移動量が多い場合 */
    return ax + ay;
  }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;要は、最初の移動方向に壁があるかどうかでチェックすればいいわけです。&lt;br&gt;これで、三角形を敷き詰めるようなパターンを作りたい場合もある程度すっきりかけることになります。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/izmktr/aggbug/176696.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>出水 洸太郎</dc:creator><title>[アルゴリズム]六角対応</title><link>http://blogs.wankuma.com/izmktr/archive/2009/06/26/176657.aspx</link><pubDate>Fri, 26 Jun 2009 20:48:00 GMT</pubDate><guid>http://blogs.wankuma.com/izmktr/archive/2009/06/26/176657.aspx</guid><wfw:comment>http://blogs.wankuma.com/izmktr/comments/176657.aspx</wfw:comment><comments>http://blogs.wankuma.com/izmktr/archive/2009/06/26/176657.aspx#Feedback</comments><slash:comments>182</slash:comments><wfw:commentRss>http://blogs.wankuma.com/izmktr/comments/commentRss/176657.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/izmktr/services/trackbacks/176657.aspx</trackback:ping><description>&lt;p&gt;ウォーシミュレーションと呼ばれるジャンルで採用されるゲームでは六角形のマップを使うことが多いです。&lt;br&gt;こんなマップですね。&lt;/p&gt; &lt;p&gt;&lt;img src="http://izmktr.wankuma.com/200906/hex_1.png"&gt; &lt;/p&gt; &lt;p&gt;これをプログラムで実装するとして、どういう風にデータを持つかという問題があります。&lt;br&gt;ずれているのが厄介で、うまく表現することができません。&lt;/p&gt; &lt;p&gt;結局、この形が一番やりやすいだろうという結論に落ち着きました。&lt;/p&gt; &lt;p&gt;&lt;img src="http://izmktr.wankuma.com/200906/hex_2.png"&gt; &lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;チェスのようなマップです。&lt;br&gt;白い部分だけを使って灰色の部分は使いません。&lt;/p&gt; &lt;p&gt;無駄なメモリが増えるように見えますが、座標の管理だけは上の図で行い、&lt;br&gt;実際にチップにデータはxの値を半分にして取得すれば問題ありません。&lt;br&gt;こんな感じですね。&lt;/p&gt; &lt;p&gt; &lt;div class="wlWriterEditableSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d87f416f-4abf-43f1-bf3d-eda6a6676b63" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c"&gt;int getData(int x, int y){
  return data[x / 2][y];
}
&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;黒い部分か白い部分かの判定は、xとｙの座標を足し、奇数か偶数かでみればよいでしょう。&lt;br&gt;上の図の場合、偶数ならおける場所、奇数ならおけない場所です。&lt;/p&gt;
&lt;p&gt;また、移動する場合もxとyの移動量を足して偶数になっていることをチェックすればいいでしょう。&lt;br&gt;奇数になっている場合は、上の図の黒い部分に入ってしまうため、移動できません。&lt;/p&gt;
&lt;p&gt;さて、移動です。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://izmktr.wankuma.com/200906/hex_3.png"&gt; &lt;/p&gt;
&lt;p&gt;このように6方向に進むことができます。&lt;br&gt;実際のヘックスも6方向に動けるので一致します。&lt;/p&gt;
&lt;p&gt;そして、距離の求め方です。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://izmktr.wankuma.com/200906/hex_4.png"&gt; &lt;/p&gt;
&lt;p&gt;距離はこのような図になります。&lt;br&gt;この図では結構複雑な式になりそうですが、実はそれほど難しくありません。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://izmktr.wankuma.com/200906/hex_5.png"&gt; &lt;/p&gt;
&lt;p&gt;紫と橙の部分に分けています。&lt;br&gt;このとき、紫の領域はxとyの絶対値を足して2で割った値、&lt;br&gt;橙の部分は、単純にyの絶対値です。&lt;br&gt;ソースで書くとこうなります。&lt;/p&gt;
&lt;div class="wlWriterEditableSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:0d8f50ab-9a9d-452e-9945-97a00d349187" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c"&gt;int distance(int dx, int dy){
  int ax = abs(dx);
  int ay = abs(dy);
  if (ax &amp;lt; ay){
    /* Yの移動量が多い場合 */
    return ay;
  }else{
    /* Xの移動量が多い場合 */
    return (ax + ay) / 2;
  }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;こんな感じで、さっくり計算できます。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/izmktr/aggbug/176657.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>出水 洸太郎</dc:creator><title>[アルゴリズム]突っ込みにも負けるな</title><link>http://blogs.wankuma.com/izmktr/archive/2008/12/17/164161.aspx</link><pubDate>Wed, 17 Dec 2008 22:12:00 GMT</pubDate><guid>http://blogs.wankuma.com/izmktr/archive/2008/12/17/164161.aspx</guid><wfw:comment>http://blogs.wankuma.com/izmktr/comments/164161.aspx</wfw:comment><comments>http://blogs.wankuma.com/izmktr/archive/2008/12/17/164161.aspx#Feedback</comments><slash:comments>20</slash:comments><wfw:commentRss>http://blogs.wankuma.com/izmktr/comments/commentRss/164161.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/izmktr/services/trackbacks/164161.aspx</trackback:ping><description>&lt;P&gt;ここまで突っ込まれるとは&amp;#8230;ということで、前回の「&lt;A href="http://blogs.wankuma.com/izmktr/archive/2008/12/17/164073.aspx"&gt;処理落ちに負けるな&lt;/A&gt;」の補足です。&lt;/P&gt;
&lt;P&gt;前回のループでは17msと決め打ちで回していますが、&lt;BR&gt;vsyncに合わす、という意味ではあまり良いとは言えません。&lt;BR&gt;vsync割り込みを利用するとして書き直すと前回のソースはこうなります。&lt;/P&gt;&lt;PRE class=Cpp name="code"&gt;unsigned int vsynccount = 0;

// vsyncが発生するたびに呼ばれる関数
void callback(){ vsynccount++; }

while(1){
  while(0 &amp;lt; vsynccount){
    control();
    vsync--;
  }
  draw();
  waitvsync();
}
&lt;/PRE&gt;
&lt;P&gt;draw()の処理途中にcontrol()が呼ばれるのは良くありませんので、&lt;BR&gt;vsync割り込みの中ではカウンタだけインクリメントしてその回数だけループを回します。&lt;/P&gt;
&lt;P&gt;しかし、理想形まで行けばこんな感じでしょうか。&lt;/P&gt;&lt;PRE class=Cpp name="code"&gt;deque&amp;lt;Pad&amp;gt; queue;

// vsyncが発生するたびに呼ばれる関数
void callback(){ 
  queue.push_back(getPad());
}

while(1){
  while( !queue.empty() ){
    control( *queue.begin() );
    queue.pop_front();
  }
  draw();
  waitvsync();
}
&lt;/PRE&gt;
&lt;P&gt;vsyncの度にコントローラの状態をキューに貯めておき&lt;BR&gt;その値を使いながらcontrol()を回す方法です。&lt;BR&gt;これであれば、相手がシンクロ連射でも確実に連射状態になります。&lt;/P&gt;
&lt;P&gt;ただ、前回に17msと決め打ったのは、vsyncが1/60秒でないことを考慮したためです。&lt;BR&gt;PCならvsyncが1/60とは限りませんし、vsyncはブラウン管の名残です。&lt;BR&gt;液晶が全盛となった今にvsyncに頼るのは果たしていいのか疑問が残ります。&lt;/P&gt;
&lt;P&gt;凪瀬さんのコメントのように処理のみ120fpsで行うってのもありでしょう。&lt;BR&gt;レースゲームでは大抵0.01秒まで出ますから、10ms以下の単位で処理をしたいところです。&lt;/P&gt;
&lt;P&gt;ということで、描画と処理は必ずしも同期する必要はない、と考えた方が幅が広がるかと思います。&lt;/P&gt;&lt;img src ="http://blogs.wankuma.com/izmktr/aggbug/164161.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>出水 洸太郎</dc:creator><title>[アルゴリズム]処理落ちに負けるな</title><link>http://blogs.wankuma.com/izmktr/archive/2008/12/17/164073.aspx</link><pubDate>Wed, 17 Dec 2008 06:17:00 GMT</pubDate><guid>http://blogs.wankuma.com/izmktr/archive/2008/12/17/164073.aspx</guid><wfw:comment>http://blogs.wankuma.com/izmktr/comments/164073.aspx</wfw:comment><comments>http://blogs.wankuma.com/izmktr/archive/2008/12/17/164073.aspx#Feedback</comments><slash:comments>654</slash:comments><wfw:commentRss>http://blogs.wankuma.com/izmktr/comments/commentRss/164073.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/izmktr/services/trackbacks/164073.aspx</trackback:ping><description>&lt;P&gt;ゲームには垂直同期信号というのにしばしば悩まされます。&lt;/P&gt;
&lt;P&gt;1フレームという単位があって、約1/60秒を差します。&lt;BR&gt;大体のゲームは1秒に60回画面を書き換える事が出来ることができます。&lt;BR&gt;それ以上の速度で処理をしても基本的に無意味ですから&lt;BR&gt;これを一単位として使う事がおおいわけです。&lt;/P&gt;
&lt;P&gt;1/60秒は約17ミリ秒です。&lt;BR&gt;1回の処理に20ミリ秒かかると、次の垂直同期信号を待たないといけません。&lt;BR&gt;ちょうど電車が出た途端に駅に着く、って感じですね。&lt;/P&gt;
&lt;P&gt;つまり、17ミリ秒を超えた瞬間、いきなり速度が半分になります。&lt;BR&gt;いわゆる処理落ちです。&lt;BR&gt;一部のゲームではこの処理落ちをゲーム性に組み込んでいるものもありますが、&lt;BR&gt;望ましい結果とは言えません。&lt;/P&gt;
&lt;P&gt;そこで、処理落ちが発生した場合は描画処理を飛ばして&lt;BR&gt;なるべくゲーム速度を保つ方法を考えてみます。&lt;BR&gt;で、いろいろ考えた結果が以下のソースになります。&lt;/P&gt;
&lt;P&gt;timeGetTime()は1ミリ秒単位で現在時間を取得する関数で、&lt;BR&gt;waitvsync()が垂直同期信号を待つ関数です。&lt;/P&gt;
&lt;PRE class=Cpp name="code"&gt;
unsigned int befour t = timeGetTime();
unsigned int ctrltime = 0;
while(1){
  unsigned int now = timeGetTime();
  unsigned int dttime = befour - now;
  befour = now;

  for (ctrltime += dttime; 0 &lt; ctrltime; ctrltime -= 17){
    control();
  }
  draw();
  waitvsync();
}
&lt;/PRE&gt;
&lt;P&gt;処理と描画の完全分離です。&lt;BR&gt;control()を一度呼び出すたびに1フレームの動作をします。&lt;BR&gt;draw()は描画処理に特化し、control()を呼び出さなければ&lt;BR&gt;全く同じ画面が描画されます。&lt;/P&gt;
&lt;P&gt;XNAなんかはこの考えが浸透している感じですね。&lt;/P&gt;
&lt;P&gt;なお、draw()はボトルネックになっていても、&lt;BR&gt;control()は無視できる速度で処理が終わることを前提としています。&lt;BR&gt;どちらが足を引っ張っているのかは確認してください。&lt;/P&gt;
&lt;P&gt;あと問題は、コントローラの入力を不定期に取ってしまう事です。&lt;BR&gt;独歩頂膝がでねーぞ！！って事になりかねません。&lt;BR&gt;そんな人にはPC買い換えろとやさしい言葉をかけて解決としましょう。&lt;/P&gt;&lt;img src ="http://blogs.wankuma.com/izmktr/aggbug/164073.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>出水 洸太郎</dc:creator><title>[アルゴリズム]クイックソートの広さ</title><link>http://blogs.wankuma.com/izmktr/archive/2008/11/13/161309.aspx</link><pubDate>Thu, 13 Nov 2008 23:04:00 GMT</pubDate><guid>http://blogs.wankuma.com/izmktr/archive/2008/11/13/161309.aspx</guid><wfw:comment>http://blogs.wankuma.com/izmktr/comments/161309.aspx</wfw:comment><comments>http://blogs.wankuma.com/izmktr/archive/2008/11/13/161309.aspx#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://blogs.wankuma.com/izmktr/comments/commentRss/161309.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/izmktr/services/trackbacks/161309.aspx</trackback:ping><description>&lt;P&gt;ネタ元&amp;gt;&lt;A href="http://bbs.wankuma.com/index.cgi?mode=al2&amp;amp;namber=27535"&gt;再帰をループに変換&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;クイックソートとは以下の順序でソートを行うものです。&lt;BR&gt;(1)ある要素を取り出し、その要素より小さいグループと大きいグループで分類する&lt;BR&gt;(2)それぞれのグループに対し、要素の数が1個になるまで(1)を繰り返す&lt;BR&gt;このクイックソートが必要とするメモリ量、すなわち空間計算量を考えてみましょう。&lt;/P&gt;
&lt;P&gt;要素を2つに分割した後、両方を同時に処理することはできません。&lt;BR&gt;ですから、一方はいったん置いて他方を処理します。&lt;BR&gt;その処理中にまた2つに分割されるため、いったん置いたうえにさらに置くことになります。&lt;BR&gt;図で表現するとこんな感じですね。&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://izmktr.wankuma.com/200811/qsort1.jpg"&gt; &lt;/P&gt;
&lt;P&gt;このようにうまく二等分できれば一時領域は10段もあれば十分です。&lt;BR&gt;この一時領域をスタックサイズと呼びます。&lt;/P&gt;
&lt;P&gt;別の場合のスタックサイズを考えてみます。&lt;BR&gt;こんな場合はどうでしょうか。&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://izmktr.wankuma.com/200811/qsort2.jpg"&gt; &lt;/P&gt;
&lt;P&gt;先ほどと違い、うまく分割することが出ていません。&lt;BR&gt;そして、このペースだとスタックサイズは500段必要です。&lt;/P&gt;
&lt;P&gt;一体スタックサイズは何段用意しておけばいいのでしょうか。&lt;BR&gt;出来るだけスタックサイズを小さくする方法を考えてみます。&lt;/P&gt;
&lt;P&gt;このスタックは処理中のものが終了するまで積まれ続けるわけです。&lt;BR&gt;いつ終了するんでしょうか。&lt;BR&gt;それは、処理中の要素数が2個以下になるまでです。&lt;/P&gt;
&lt;P&gt;それならば、早く処理中の要素数を減らせばよいわけです。&lt;BR&gt;2つに分割したとき、どちらをスタックに積み、どちらを処理中にするかは&lt;BR&gt;自由に決められるため、要素が多い方をスタックに積んでしまえばいいのです。&lt;/P&gt;
&lt;P&gt;それを図示しました。&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://izmktr.wankuma.com/200811/qsort3.jpg"&gt; &lt;/P&gt;
&lt;P&gt;いずれも4:1のグループに分かれていますが、左の方はもうすぐ処理が終わりそうです。&lt;BR&gt;このように、アンバランスに別れた方がスタックに積む量が減るため、&lt;BR&gt;最もスタックが必要なパターンは二等分されるパターンです。&lt;BR&gt;そして、二等分された場合、スタックサイズはlog2(N)必要です。&lt;/P&gt;
&lt;P&gt;よって、クイックソートの空間計算量は最悪の場合でもO(logN)です。&lt;/P&gt;
&lt;P&gt;なお、ピボットに使われた要素は処理済みにするのが好ましいため、&lt;BR&gt;1000個は499個＋1個＋500個のように3つに分けられますが&lt;BR&gt;今回は分かりやすくするため、それを無視しています。&lt;/P&gt;&lt;img src ="http://blogs.wankuma.com/izmktr/aggbug/161309.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>出水 洸太郎</dc:creator><title>[アルゴリズム]マルチコア</title><link>http://blogs.wankuma.com/izmktr/archive/2008/10/30/160132.aspx</link><pubDate>Thu, 30 Oct 2008 06:33:00 GMT</pubDate><guid>http://blogs.wankuma.com/izmktr/archive/2008/10/30/160132.aspx</guid><wfw:comment>http://blogs.wankuma.com/izmktr/comments/160132.aspx</wfw:comment><comments>http://blogs.wankuma.com/izmktr/archive/2008/10/30/160132.aspx#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://blogs.wankuma.com/izmktr/comments/commentRss/160132.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/izmktr/services/trackbacks/160132.aspx</trackback:ping><description>&lt;P&gt;ネタ元＞&lt;A href="http://msdn.microsoft.com/ja-jp/magazine/cc850829.aspx"&gt;WindowsとC++：高性能アルゴリズムについて調べる&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;上記の記事を読むと、マルチコアで動作する時、&lt;BR&gt;同じコアで実行するメモリは近くに配置し、&lt;BR&gt;違うコアで実行するメモリは遠くに配置するべき、と書いています。&lt;/P&gt;
&lt;P&gt;さて、以前書いたシェアソートの並列動作なのですが、&lt;BR&gt;横ソートにおいては上記のマルチコア動作に向くメモリ配置になっています。&lt;/P&gt;
&lt;P&gt;しかし、縦ソートに至っては並列動作に向かないパターンです。&lt;BR&gt;良くないパターンとして紹介されている物と全く同じです。&lt;/P&gt;
&lt;P&gt;今回の場合は&amp;#8221;#pragma omp parallel for&amp;#8221;を使ったものなので&lt;BR&gt;自分でカリカリ内部動作を書いた場合とは違うのかもしれません。&lt;BR&gt;ただ、キャッシュの読み直しという単語がちらほら見えるので、&lt;BR&gt;ハードウェアの仕様のような感じで、ソフトウェア側でどうにかならない気がします。&lt;/P&gt;
&lt;P&gt;シェアソートの縦ソートが遅いとなるといよいよ出番もないですね&amp;#8230;。&lt;/P&gt;
&lt;P&gt;#ということで、教えて詳しい人！&lt;/P&gt;&lt;img src ="http://blogs.wankuma.com/izmktr/aggbug/160132.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>出水 洸太郎</dc:creator><title>[アルゴリズム]等号は続くよ どこまでも</title><link>http://blogs.wankuma.com/izmktr/archive/2008/10/23/159627.aspx</link><pubDate>Thu, 23 Oct 2008 01:02:00 GMT</pubDate><guid>http://blogs.wankuma.com/izmktr/archive/2008/10/23/159627.aspx</guid><wfw:comment>http://blogs.wankuma.com/izmktr/comments/159627.aspx</wfw:comment><comments>http://blogs.wankuma.com/izmktr/archive/2008/10/23/159627.aspx#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://blogs.wankuma.com/izmktr/comments/commentRss/159627.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/izmktr/services/trackbacks/159627.aspx</trackback:ping><description>&lt;P&gt;ネタ元：&lt;A href="http://blogs.wankuma.com/rti/archive/2008/10/22/159620.aspx"&gt;同じ値であること（その２）&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;aとbとcがすべて等しいという条件式を作ろうとして&lt;BR&gt;数学のようにa=b=cと書いてしまう人はよくいます。&lt;/P&gt;
&lt;P&gt;昔のBASICだと、if文の外でこのように書くとaに-1が代入されたりします。&lt;BR&gt;a=(b=c)と解釈され、(b=c)がtrueを意味する-1になるからです。&lt;/P&gt;
&lt;P&gt;そして、こんな書式も生まれました。&lt;/P&gt;
&lt;P&gt;I$=INKEY$&lt;BR&gt;x=x+(I$="4")-(I$="6")&lt;BR&gt;y=y+(I$="8")-(I$="2")&lt;/P&gt;
&lt;P&gt;I$は変数名で、INKEY$とは入力された文字を取得する関数です。&lt;BR&gt;つまり、4が入力されればxは-1され、6が入っていればxは+1されます。&lt;BR&gt;要はキャラクターやカーソルを動かす部分です。&lt;/P&gt;
&lt;P&gt;さらに、a=b=c=dはどうなるでしょうか。&lt;BR&gt;普通に解釈されるならa=(b=(c=d))ですね。&lt;/P&gt;
&lt;P&gt;しかし、(a=b)=(c=d)と捕えてみましょう。&lt;/P&gt;
&lt;P&gt;a=bがtrue 、c=dがtrue で全体がtrue&lt;BR&gt;a=bがtrue 、c=dがfalseで全体がfalse&lt;BR&gt;a=bがfalse、c=dがtrue で全体がfalse&lt;BR&gt;a=bがfalse、c=dがfalseで全体がtrue&lt;/P&gt;
&lt;P&gt;これは、排他的論理和(XOR)の否定を意味します。&lt;/P&gt;
&lt;P&gt;排他的論理和の演算子を用意していない言語でも、&lt;BR&gt;中央の等号をnot equalの記号にすれば排他的論理和を使うことができます。&lt;/P&gt;&lt;img src ="http://blogs.wankuma.com/izmktr/aggbug/159627.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>出水 洸太郎</dc:creator><title>[アルゴリズム]はみだしシェアソート6</title><link>http://blogs.wankuma.com/izmktr/archive/2008/09/28/157678.aspx</link><pubDate>Sun, 28 Sep 2008 20:03:00 GMT</pubDate><guid>http://blogs.wankuma.com/izmktr/archive/2008/09/28/157678.aspx</guid><wfw:comment>http://blogs.wankuma.com/izmktr/comments/157678.aspx</wfw:comment><comments>http://blogs.wankuma.com/izmktr/archive/2008/09/28/157678.aspx#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://blogs.wankuma.com/izmktr/comments/commentRss/157678.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/izmktr/services/trackbacks/157678.aspx</trackback:ping><description>&lt;P&gt;前回で終わりのような気がしていたが別にそんなことはなかったぜ！&lt;/P&gt;
&lt;P&gt;今まで紹介したシェアソートは要素の数が平方数でした。&lt;BR&gt;サンプルなので奇麗に正方形に並べられる個数ばかり選んでたわけです。&lt;/P&gt;
&lt;P&gt;シェアソートは矩形(長方形)に並べられれば良いのですが、&lt;BR&gt;要素の数が素数だった場合はそれすら適いません。&lt;/P&gt;
&lt;P&gt;ということでそんな半端の状態のシェアソートです。&lt;/P&gt;
&lt;P&gt;39個の要素でシェアソートを行おうとすると、以下のようになります。&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://izmktr.wankuma.com/200809/hanpa1.jpg"&gt;&lt;/P&gt;
&lt;P&gt;実は、この形でも以下のように分割してシェアソートを行えば問題がありません。&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://izmktr.wankuma.com/200809/hanpa2.jpg"&gt;&lt;/P&gt;
&lt;P&gt;豆知識として、縦ソートをするときに40以上の位置を差したら終端としておくと、&lt;BR&gt;どこで数が変わったかというのを意識しないで済みます。&lt;/P&gt;
&lt;P&gt;ですが、折り返しで終わった場合はちょっと工夫が必要です。&lt;BR&gt;以下のような場合ですね。&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://izmktr.wankuma.com/200809/hanpa3.jpg"&gt;&lt;/P&gt;
&lt;P&gt;空白に最大値を入れてソートでも良いのですが、スマートではないです。&lt;BR&gt;そこで、1行6個ではなく7個で作りなおしてみます。&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://izmktr.wankuma.com/200809/hanpa4.jpg"&gt;&lt;/P&gt;
&lt;P&gt;うまく行きました。&lt;/P&gt;
&lt;P&gt;ちょうどいい一行の数の求め方ですが、今回はこうやっています。&lt;/P&gt;
&lt;P&gt;　44 &amp;#247; 6 = 7 余り 2&lt;/P&gt;
&lt;P&gt;1行6個で並べれば7行と2個と読めますが、&lt;BR&gt;逆に1行7個で並べれば6行と2個という読み方をします。&lt;BR&gt;適当な偶数で割ってやってその商を1行の個数とすれば&lt;BR&gt;必ず都合のいい配置になってくれるわけです。&lt;/P&gt;&lt;img src ="http://blogs.wankuma.com/izmktr/aggbug/157678.aspx" width = "1" height = "1" /&gt;</description></item></channel></rss>