特攻隊

RPGツクール、パズル、プログラミング等々。

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
よなべしてしまった…ぷよぷよの消すアルゴリズムって、複雑なんですね。
再帰関数の学習教材として、ぷよぷよは最適。
落ちゲーは他にも色々作れそう。

(4/21追記)main()関数を改造(clock()による時間制御に変更)。
(5/22追記)連鎖ウエイト追加。


#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#include <windows.h>

#define HT 14
#define WD 6
#define CB 4

int field[WD + 2][HT + 1], check[WD + 2][HT + 1], combine[WD + 2][HT + 1];
int gameover = 0;
double timer = 0;
clock_t start, end;

typedef struct _TAG_STATUS {
int x;
int y;
int rotate;
int center;
int satellite;
} STATUS;

STATUS current, next;

bool putblock(STATUS, bool);
bool deleteblock(STATUS);
bool pushkey(char);
void blockdown(void);
void checkcombine(void);
bool deletecheck(int, int);
void closeup(void);
void showfield(void);

int main(void) {
for(int x = 0; x < WD + 2; x++) {
for(int y = 0; y < HT + 1; y++) {
if(x == 0 || x == WD + 1 || y == 0) {
field[x][y] = 6;
}
else {
field[x][y] = 0;
}
}
}
current.x = WD / 2 + WD % 2;
current.y = HT;
current.rotate = 0;
srand((unsigned)time(NULL));
current.center = rand() % 5 + 1;
current.satellite = rand() % 5 + 1;
putblock(current, true);
start = clock();
showfield();
while(!gameover) {
while(timer < 1) {
if(kbhit()) {
if(pushkey(getch())) {
timer = 1;
}
} else {
end = clock();
timer = (double)(end - start) / CLOCKS_PER_SEC;
}
}
blockdown();
timer = 0;
start = end = clock();
}
return 0;
}

bool putblock(STATUS s, bool action = false) {
if(field[s.x][s.y]) {
return false;
}
if(action) {
field[s.x][s.y] = current.center;
}
int r = s.rotate % 4;
int dx = 0;
int dy = -1;
for(int i = 0; i < r; i++) {
int nx = dx, ny = dy;
dx = ny;
dy = -nx;
}
if(field[s.x + dx][s.y + dy]) {
return false;
}
if(action) {
field[s.x + dx][s.y + dy] = current.satellite;
}
if(!action) {
putblock(s, true);
}
showfield();
return true;
}

bool deleteblock(STATUS s) {
field[s.x][s.y] = 0;
int dx = 0;
int dy = -1;
int r = s.rotate % 4;
for(int i = 0; i < r; i++) {
int nx = dx, ny = dy;
dx = ny;
dy = -nx;
}
field[s.x + dx][s.y + dy] = 0;
return true;
}

bool pushkey(char key) {
bool ret = false;
STATUS n = current;
if(key == 'a') {
n.x--;
} else if(key == 'd') {
n.x++;
} else if(key == ' ') {
n.rotate++;
} else if(key == 's') {
ret = true;
}
if(n.x != current.x || n.y != current.y || n.rotate != current.rotate) {
deleteblock(current);
if(putblock(n)) {
current = n;
} else {
putblock(current);
}
}
return ret;
}

void blockdown(void) {
deleteblock(current);
current.y--;
if(!putblock(current)) {
current.y++;
putblock(current);

showfield();
closeup();
checkcombine();

current.x = WD / 2 + WD % 2;
current.y = HT;
current.rotate = 0;
srand((unsigned)time(NULL));
current.center = rand() % 5 + 1;
current.satellite = rand() % 5 + 1;
if(!putblock(current)) {
gameover = 1;
}
}
}

void checkcombine(void) {
bool ret = false;
for(int y = 1; y <= HT; y++) {
for(int x = 1; x <= WD; x++) {
if(!check[x][y]) {
if(deletecheck(x, y)) {
ret = true;
}
for(int y = 1; y <= HT; y++) {
for(int x = 1; x <= WD; x++) {
combine[x][y] = 0;
}
}
}
}
}
closeup();
for(int y = 1; y <= HT; y++) {
for(int x = 1; x <= WD; x++) {
check[x][y] = 0;
}
}
if(ret) {
showfield();
checkcombine();
}
}

bool deletecheck(int x, int y) {
int n = 0;
int type = field[x][y];
check[x][y]++;
combine[x][y]++;
if(!type) {
return false;
}
if(1 <= x - 1 && field[x - 1][y] == type && check[x - 1][y] == 0) {
deletecheck(x - 1, y);
}
if(x + 1 <= WD && field[x + 1][y] == type && check[x + 1][y] == 0) {
deletecheck(x + 1, y);
}
if(1 <= y - 1 && field[x][y - 1] == type && check[x][y - 1] == 0) {
deletecheck(x, y - 1);
}
if(y + 1 <= HT && field[x][y + 1] == type && check[x][y + 1] == 0) {
deletecheck(x, y + 1);
}
for(int y = 1; y <= HT; y++) {
for(int x = 1; x <= WD; x++) {
n += combine[x][y];
}
}
if(CB <= n) {
for(int y = 1; y <= HT; y++) {
for(int x = 1; x <= WD; x++) {
if(combine[x][y]) {
field[x][y] = 0;
}
}
}
Sleep(50);
showfield();
return true;
}
return false;
}

void closeup(void) {
bool ret = false;
for(int y = 1; y <= HT - 1; y++) {
for(int x = 1; x <= WD; x++) {
if(field[x][y] == 0 && field[x][y+1] != 0) {
field[x][y] = field[x][y+1];
field[x][y+1] = 0;
ret = true;
}
}
}
if(ret) {
closeup();
}
}

void showfield(void) {
system("cls");
for(int y = HT - 1; y >= 0; y--) {
for(int x = 0; x <= WD + 1; x++) {
switch(field[x][y]) {

case 0:
printf(" ");
break;
case 1:
printf("▽");
break;
case 2:
printf("○");
break;
case 3:
printf("□");
break;
case 4:
printf("◇");
break;
case 5:
printf("△");
break;
case 6:
printf("■");
break;
}
}
printf("\n");
}
}
自作ゲーム用アプロダに、窓プログラミング版テトリスをアップしました。

操作方法:←→↓でブロック移動、↑でブロック回転

レベルつけてないけど、まあこんなもんで良いかな。
これでとりあえず、当初の目標達成ってことで、一区切りついた感じ。
ニコニコプログラミングの人のやり方を大いにパク…参考にしているので、
ソースコードは非公開にします。
windowstetris.jpg

窓プログラミングで作ったテトリス試作品のスクリーンショット。
背景の色(茶色)は変えた方がいいだろうか。
右側に、NEXT、SCORE、LEVELをつけたら、とりあえず完成かな。

ソースコードは、公開するかどうか微妙です。
(ニコニコプログラミングの人のコードと酷似している為)
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。