第17講 テトリス開発(ゲームオーバー設定まで)第7話 床またはブロックに着くとブロックがそのまま残るようにするコード解説

ブロックを時間とともに自動的に落としていくコード主要部分再掲
void block(){
  int i,j,l;
  y=(GetNowCount()-hajimenojikoku)/200;
  for(i=0;i<4;i++){
    //sはブロックの種類 0:長方形 1:正方形 2:L字 3:N字
    //kは回転状態 0:元の状態 1:90°回転 2:180°回転 3:270°回転
    if(chizumodosu[x+p[s][k][i]][y+q[s][k][i]]==1){
      if(y+q[s][k][i]>0)chizu[x+p[s][k][i]][y+q[s][k][i]] = 2 + s;
    }

  }
  for(i=0;i<4;i++){
    for (j = 0; j < 12; j++) {
      for (l = 0; l < 27; l++) {
        if (chizu[j][l] == 2 + i) {
          if(i==0)  DrawBox(20 * j, 20 * l, 20 * (j + 1) - 1, 20 * (l + 1) - 1, kiiro, true);
          if(i==1)  DrawBox(20 * j, 20 * l, 20 * (j + 1) - 1, 20 * (l + 1) - 1, mizuiro, true);
          if(i==2)  DrawBox(20 * j, 20 * l, 20 * (j + 1) - 1, 20 * (l + 1) - 1, aka, true);
          if(i==3)  DrawBox(20 * j, 20 * l, 20 * (j + 1) - 1, 20 * (l + 1) - 1, ao, true);
        }
      }
    }
  }
  char h=1;
  for(i=0;i<4;i++){
    if(
y+q[s][k][i]+1>0 && chizumodosu[x+p[s][k][i]][y+q[s][k][i]+1]==0){
      h=0;
      break;
    }
  }
  if(h==0){
    
for(i=0;i<4;i++)chizumodosu[x+p[s][k][i]][y+q[s][k][i]]=0;
    t=0; //0:作動 1:作動停止
    hajimenojikoku=GetNowCount();
  }

}
void chizusakusei() {
  int gazou = LoadGraph("画像/kb00.png");
  int i,j;
  for (i = 0; i < 12; i++) {
    for (j = 0; j < 27; j++) {
      if(chizumodosu[i][j]==1){
        chizu[i][j] = 0;
      }

    }
  }
  for (j = 0; j < 27; j++) {
    chizu[0][j] = 1;
    chizu[11][j] = 1;
    chizumodosu[0][j] = 0;
    chizumodosu[11][j] = 0;

  }
  for (i = 1; i < 11; i++) {
    chizu[i][0] = 1;
    chizu[i][26] = 1;
    chizumodosu[i][0] = 0;
    chizumodosu[i][26] = 0;

  }
  for (i = 0; i < 12; i++) {
    for (j = 0; j < 27; j++) {
      if (chizu[i][j] == 1) {
        DrawGraph(20 * i, 20 * j, gazou, true);
      }
    }
  }
  DeleteGraph(gazou);
}
コピペ用添付ファイル

解説
  for (j = 0; j < 27; j++) {
    chizu[0][j] = 1;
    chizu[11][j] = 1;
    chizumodosu[0][j] = 0;
    chizumodosu[11][j] = 0;

  }
  for (i = 1; i < 11; i++) {
    chizu[i][0] = 1;
    chizu[i][26] = 1;
    chizumodosu[i][0] = 0;
    chizumodosu[i][26] = 0;

  }
は解説するまでもありません。
壁の部分を0にすると1にするという無駄をなくすためです。
  for (i = 0; i < 12; i++) {
    for (j = 0; j < 27; j++) {
      if(chizumodosu[i][j]==1){
        chizu[i][j] = 0;
      }

    }
  }
から壁の部分は最初だけ0となりますが、後はずっと1のままです。

    if(chizumodosu[x+p[s][k][i]][y+q[s][k][i]]==1){
      if(y+q[s][k][i]>0)chizu[x+p[s][k][i]][y+q[s][k][i]] = 2 + s;
    }
は、床またはすでにあるブロックに着いていない限りは、ブロックを描いてよいというわけです。
  char h=1;
  for(i=0;i<4;i++){
    if(
y+q[s][k][i]+1>0 && chizumodosu[x+p[s][k][i]][y+q[s][k][i]+1]==0){
      h=0;
      break;
    }
  }
  if(h==0){
    
for(i=0;i<4;i++)chizumodosu[x+p[s][k][i]][y+q[s][k][i]]=0;
    t=0; //0:作動 1:作動停止
    hajimenojikoku=GetNowCount();
  }

は、床またはすでにあるブロックに着いたかどうかを判定しています。
y+q[s][k][i]+1>0を入れなければならない理由は、
天井の部分もchizumodosu[x+p[s][k][i]][y+q[s][k][i]+1]==0であるからです。

天井以外でchizumodosu[x+p[s][k][i]][y+q[s][k][i]+1]==0なら、
床またはすでにあるブロックにくっついていると判断できるわけです。
h==0なら着いていると判断し、h==0でないなら着いていないと判断しています。
y+q[s][k][i]+1と1つだけ増やしてあることがミソです。
自分より1個下が、0以外ということは床かすでにあるブロックにくっついていることを意味します。
brreak;はfor文を強制的に止める文です。
ブロックを構成するどれか1つの正方形の下が0でないつまり0より大きいときには、
すでに床またはブロックに着いているということです。
ブロックを構成する4つすべてについて調べなければならにのですが、
1つでもくっついていれば001それ以上調べてみても意味はありません。
赤のL字の場合for文の最初のループのときに試されている正方形は、
L字の下の正方形ですが、これが他のブロックないしは床に着いていれば、
他の3つの正方形を調べても意味がないですね。
すでにくっついているの判定が下されているのですから。
4つとも調べなければならない理由は、
002ならば、ループの最後までいかないとくっついているかどうかわからないからです。
最後までいってくっついていると判断できるわけです。
003ループの最後までいってもくっついていない場合に、
床または他のブロックに到達していないと始めて判断できるわけです。
ですから、到達していると判断できるまで、
検査を継続しなければならないのです。
このようにすべての場合について調べる場合の
  char h=1;
  for(i=0;i<4;i++){
    if(
y+q[s][k][i]+1>0 && chizumodosu[x+p[s][k][i]][y+q[s][k][i]+1]==0){
      h=0;
      break;
    }
  }
  if(h==0){
    
for(i=0;i<4;i++)chizumodosu[x+p[s][k][i]][y+q[s][k][i]]=0;
    t=0; //0:作動 1:作動停止
    hajimenojikoku=GetNowCount();
  }
という手法を是非覚えて下さい。
私がよく使う方法です。
その局面でよく使う定番の方法を、
将棋では定跡、囲碁では定石といいますが、
セオリー(理論)ともいいます。
将棋でも囲碁でもチェスでも、
さらに、受験数学でもプログラミングでもセオリーをどれだけもっているか、
引き出しをどれだけもっているかで決まります。
セオリーをたくさん蓄えることが、
プログラミング上達のコツといえるでしょう。

では次の課題です。
x座標だけは、
int x=4,y; //整数型の箱xとyを用意
とグローバル変数を宣言するときに4に初期化に初期化していますが、
xの初期化は、gamemain()で行いしかもランダムにして下さい。
ランダムといっても、ブロックが壁に食い込む位置のときには、
    if(y+q[s][k][i]+1>0 && chizumodosu[x+p[s][k][i]][y+q[s][k][i]+1]==0){
から、プログラムはうまく作動しませんし、
そもそもテトリスのルールに反しています。
ですから、壁に食い込まない範囲でランダムに選んでほしいわけです。
では、皆さん挑戦しましょう。
006




第6話へ  第8話へ
a

初心者のための excel 2016 マクロ VBA 入門講義 基礎から応用まで
vc++ c言語 c++ 入門 初心者 基礎から応用まで
eclipse c++ 入門
魔方陣 数独で学ぶ VBA 入門

数独のシンプルな解き方・簡単な解法の研究
VB講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座

初心者のための世界で一番わかりやすいVBA入門講義(基礎から応用まで)
初心者のための VC++による C言語 C++ 入門 基礎から応用まで第1部
eclipse java 入門
java 入門 サイト 基礎から応用まで
本サイトトップへ