コード:
//=====================================================================================
//=====================================================================================
#include <stdio.h> //stdio.hをインクルード
#include <stdlib.h> //stdlib.hをインクルード
#include <conio.h> //conio.hをインクルード
#include <time.h> //time.hをインクルード
#include "main.h"
//グローバル変数
int stage[21][12]= {0}; //壁と固定済みブロック用
int block[4][4] = {0}; //現在落下中のブロックを入れる
int field[21][12] ={0}; //描画するデータ。stage[][]にblock[][]を重ねたもの
//7種類のブロックのデータ
int block_list[7][4][4] =
{{{0,1,0,0},
{0,1,0,0},
{0,1,0,0},
{0,1,0,0}},
{{0,0,0,0},
{0,1,1,0},
{0,1,0,0},
{0,1,0,0}},
{{0,0,1,0},
{0,1,1,0},
{0,1,0,0},
{0,0,0,0}},
{{0,1,0,0},
{0,1,1,0},
{0,0,1,0},
{0,0,0,0}},
{{0,0,0,0},
{0,1,0,0},
{1,1,1,0},
{0,0,0,0}},
{{0,0,0,0},
{0,1,1,0},
{0,1,1,0},
{0,0,0,0}},
{{0,0,0,0},
{0,1,1,0},
{0,0,1,0},
{0,0,1,0}}};
int y = 0; //ブロックの画面上でのy座標
int x = 4; //ブロックの画面上でのx座標
int oneline, twoline, threeline, fourline; //消したラインの数
int gameover = 0; //ゲームオーバー判定。新しいブロックが初期位置に置けなければ1になる。
//関数プロトタイプ宣言
void Initialize(); //ゲーム起動直後 初期設定を行う関数。画面と壁のデータを初期化
int CreateBlock(); //新しいブロックを生成して次のブロックに発生させる
void ShowGameField(); //field[][]の中身に応じて、画面を描画する
void ControlBlock(); //キー入力に応じてブロックに移動や回転等の処理を行わせる
//=====================================================================================
// ブロック処理一覧
//=====================================================================================
int CheckOverlap(int, int); //落下中ブロックが壁や固定済みブロックに接触していないか判別
void MoveBlock(int, int); //落下中ブロックを一旦消して、任意の座標に移動させる
int TurnBlock(); //ブロックの回転を処理する
void DropBlock(); //ブロックを落下させる。下に移動できない場合ブロックをその位置に固定
void LockBlock(); //着地したブロックを固定済みブロックに加える関数
void CheckLines(); //ブロックが横一列にそろえばそこを消去後、上のブロックをそこに下ろす
#define SCREEN_CENTER_X //タイトル用
#define SCREEN_CENTER_Y //タイトル用
void SceneTitle();
static GAMEMODE eGameMode = GAMEMODE_TITLE;
static GAMEMODE ePreGameMode = eGameMode;
//=====================================================================================
// メイン関数開始
//=====================================================================================
int main()
{
int time = 0; //時間をカウント
//Initialize(); //初期化(描画実行)
//ゲームオーバーになるまでゲーム続行
while(!gameover)
{
if(ePreGameMode != eGameMode)
{
//シーンの変更が行われた
Initialize();
//プリデータ更新
ePreGameMode = eGameMode;
}
if(eGameMode == GAMEMODE_TITLE)
{
//タイトル画面処理
SceneTitle();
}
else if(eGameMode == GAMEMODE_MAIN)
{
if(kbhit())
{
ControlBlock();
}
//時間がきたらブロックを1マス落下させる。時間が来てなければ時間を1だけインクリメント。
if(time < 20000)
{
time++;
}
else{
DropBlock();
time = 0;
}
}
//キー入力があればそれに応じて操作
}
return 0;
}
//=====================================================================================
// メイン関数終了
//=====================================================================================
//ゲームの初期化
void Initialize()
{
int i, j; //for文ループ制御用変数
//画面と壁を初期設定
for(i = 0; i <= 20; i++)
{
for(j = 0; j <= 11; j++)
{
if((j == 0) || (j == 11) || (i == 20))
{
field[i][j] = stage[i][j] = 9;
}
else {
field[i][j] = stage[i][j] = 0;
}
}
}
CreateBlock(); //最初のブロック発生させる
ShowGameField(); //ゲーム直後の画面を描画
}
//ブロック作成
int CreateBlock()
{
int i, j; //forループ制御用の変数
int block_type; //ブロックの種類用。0~6の乱数を入れる
//まずブロックの座標を初期位置にリセット
y = 0;
x = 4;
//乱数を発生させ、その乱数を7で割った余り(0~6まで)でブロックの種類を決定
srand((unsigned)time(NULL));
block_type = rand() % 7;
//ブロックデータの中からblock_typeに応じた種類のブロックを読み込む
for(i = 0; i<4; i++) {
for(j = 0; j<4; j++) {
block[i][j] = 0;
block[i][j] = block_list[block_type][i][j];
}
}
//壁+ブロックをフィールドへ
for(i = 0; i<4; i++)
{
for(j = 0; j<4; j++)
{
field[i][j+4] = stage[i][j+4] + block[i][j];
//初期位置に置いたブロックが既に固定ブロックに重なっていればゲームオーバー
if(field[i][j+4] > 1)
{
gameover = 1;
return 1;
}
}
}
return 0;
}
//画面表示
void ShowGameField()
{
int i, j; //forループ制御用変数
//画面を一旦クリア
system("cls");//内部のシステムから
//データに応じてブロックや空白を画面表示
for(i = 0; i<21; i++) {
for(j = 0; j < 12; j++) {
switch(field[i][j]) {
case 0:
printf(" ");
break;
case 9:
printf("□");
break;
default:
printf("■");
break;
}
}
printf("\n");
}
//ゲームオーバーの場合はGAME OVERを表示
if(gameover){
system("cls");
printf("GAME OVER");
getchar();//キーが押されるまで待機
}
}
//キー入力に応じてブロックを処理
void ControlBlock()
{
char key; //受け付けたキーを保存する変数
key = getch(); //キーから一文字入力
//キーに応じて各方向へブロックを移動したり、回転させたりする
switch(key) {
case 's'://右キー
if(!CheckOverlap(x+1, y))
{
MoveBlock(x+1, y);
}
break;
case 'f'://左キー
if(!CheckOverlap(x-1, y))
{
MoveBlock(x-1, y);
}
break;
case 'd'://中心キー
if(!CheckOverlap(x, y+1))
{
MoveBlock(x, y+1);
}
break;
case ' ':
TurnBlock();
}
}
//重なり検査
int CheckOverlap(int x2, int y2)
{
int i, j; //forループ制御用変数
//ブロックが向かう位置に、固定ブロックもしくは壁があるかどうかを検査
for(i = 0; i<4; i++) {
for(j = 0; j<4; j++) {
if(block[i][j]) {
if(stage[y2 + i][x2 + j] != 0) {
return 1;
}
}
}
}
return 0;
}
//移動
void MoveBlock(int x2, int y2)
{
int i, j; //forループ制御用変数
//今までのブロックを消して
for(i = 0; i<4; i++) {
for(j = 0; j<4; j++) {
field[y+i][x+j] -= block[i][j];
}
}
//ブロックの座標を更新
x = x2;
y = y2;
//新しい座標にブロックを入れなおし
for(i = 0; i<4; i++) {
for(j = 0; j<4; j++) {
field[y+i][x+j] += block[i][j];
}
}
ShowGameField();
}
//ブロックを回転する処理
int TurnBlock()
{
int i, j; //forループ制御用
int temp[4][4] = {0}; //ブロックを一時保存するための配列
//ブロックを回転する前にtempにセーブ
for(i = 0; i<4; i++) {
for(j = 0; j<4; j++) {
temp[i][j] = block[i][j];
}
}
//ブロックを回転
for(i = 0; i<4; i++) {
for(j = 0; j<4; j++) {
block[i][j] = temp[3-j][i];
}
}
//重なってるブロックが出てしまったらブロックを回転前に戻して中止
if(CheckOverlap(x, y)) {
for(i = 0; i<4; i++) {
for(j = 0; j<4; j++) {
block[i][j] = temp[i][j];
}
}
return 1;
}
//一旦フィールドからブロック消して回転後のブロックを再表示
for(i = 0; i<4; i++) {
for(j = 0; j<4; j++) {
field[y+i][x+j] -= temp[i][j];
field[y+i][x+j] += block[i][j];
}
}
ShowGameField();
return 0;
}
//ブロックを落とす
void DropBlock()
{
//重なりがなければ移動
if(!CheckOverlap(x, y+1)) {
MoveBlock(x, y+1);
}
//重なりがあれば壁にする
else{
LockBlock();
CreateBlock();
ShowGameField();
}
}
//着地後のブロックを固定し、横一列がそろってるかの判定を呼び出す
void LockBlock()
{
int i, j; //forループ制御用変数
//ブロックを壁に加える
for(i = 0; i<21; i++) {
for(j = 0; j<12; j++) {
stage[i][j] = field[i][j];
}
}
CheckLines(); //横一列がそろってるか判定して処理する関数を呼ぶ
//列完成判定後の壁をフィールドへ
for(i = 0; i<21; i++) {
for(j = 0; j<12; j++) {
field[i][j] = stage[i][j];
}
}
}
//横一列が完成しているか検査。そろっていればそこを消して上のブロック群を下ろす
void CheckLines()
{
int i, j, k; //forループ制御用
int comp; //横一列がそろっていれば1、一つでも隙間があると0になる
int lines = 0; //同時に消したラインの数
while(1)
{
for(i = 0; i<20; i++)
{
comp = 1;
for(j = 1; j<11; j++)
{
if(stage[i][j] == 0)
{
comp = 0;
}
}
if(comp == 1) break;
}
if(comp == 0) break;
lines++;
// 列を消去
for(j = 1; j<11; j++)
{
stage[i][j] = 0;
}
//消えた列より上にあった固定ブロックを列の消えたところへ下ろす
for(k = i; k>0; k--) {
for(j = 1; j<11; j++) {
stage[k][j] = stage[k-1][j];
}
}
}
//同時に消したラインの数をカウント
switch(lines)
{
case 1:
oneline++;
break;
case 2:
twoline++;
break;
case 3:
threeline++;
break;
case 4:
fourline++;
break;
default:
break;
}
}
//初期タイトル画面処理
void SceneTitle(){
printf("TTTTT");
printf("T");
printf("T");
printf("T");
printf("T");
//=====================
//ここまでがTをprintf
//=====================
printf("EEEE");
printf("E");
printf("EEE");
printf("E");
printf("EEEE");
//=====================
//ここまでがEをprintf
//=====================
printf("TTTTT");
printf("T");
printf("T");
printf("T");
printf("T");
//=====================
//ここまでがTをprintf
//=====================
printf("RRR");
printf("R R");
printf("RRRR");
printf("R R ");
printf("R R");
//=====================
//ここまでがRをprintf
//=====================
printf(" III ");
printf(" I ");
printf(" I ");
printf(" I ");
printf(" III ");
//=====================
//ここまでがIをprintf
//=====================
printf(" SSS ");
printf("S ");
printf(" SSS ");
printf("S");
printf(" SSS ");
//=====================
//ここまでがSをprintf
//=====================
printf("\n\n\n\n\n\n\n\n操作方法一覧\n");
printf("\n右 移動Sキー\n下 移動Dキー\n左 移動Fキー");
while(!kbhit());//キーが入力される待機
eGameMode = GAMEMODE_MAIN;
}