はじめに
2048 は、同じ数字を持つ隣接するタイルをマージして、2048 のタイルを達成することを目標とする人気の数字パズルゲームです。このプロジェクトでは、C 言語でシンプルな 2048 ゲームを作成する方法を学びます。ボードの初期化からゲームロジックの実装、ゲームの実行まで、ゲームを構築するためのステップバイステップの手順を提供します。
👀 プレビュー

🎯 タスク
このプロジェクトでは、以下のことを学びます。
- プロジェクトファイルを作成する方法
- ゲームの定数を定義する方法
- ゲームループを実行する
main()関数を実装する方法 - ゲームボードを初期化する方法
- ゲーム状態をチェックする関数を実装する方法
- タイルを移動させるロジックを作成する方法
- ゲームボードを表示する方法
- ゲームをコンパイルしてテストする方法
🏆 達成目標
このプロジェクトを完了した後、以下のことができるようになります。
- ゲーム用の C プログラムを作成する
- 配列を使用してゲームボードを表現する
- タイルをマージするゲームロジックを実装する
- ゲームボードを表示する
- プレイヤーの入力を処理する
- ゲームオーバーと勝利条件をチェックする
プロジェクトファイルを作成する
まず、2048.c という名前の新しいファイルを作成し、好みのコードエディタで開きます。
cd ~/project
touch 2048.c
定数を定義する
まず、C 言語のコードを書く必要があります。最初のステップは、ヘッダーファイルをインクルードすることです。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
main() 関数を書く前に、いくつかの定数を定義するための基本的なタスクを完了しましょう。
#define SIZE 4
#define WIN_SCORE 2048
int board[SIZE][SIZE];
int score = 0;
main 関数
int main() {
srand(time(NULL));
init_board();
print_board();
while (1) {
if (is_won()) {
printf("You won!\n");
break;
}
if (is_full() &&!can_move()) {
printf("Game over!\n");
break;
}
int direction;
printf("Enter the move direction (0-Up, 1-Down, 2-Left, 3-Right): ");
scanf("%d", &direction);
if (move(direction)) {
// Print the board after the move
print_board();
}
}
return 0;
}
init_board(): この関数呼び出しは、ゲームボードを初期化し、ゲームボードのすべてのセルを 0 に設定し、その後、ランダムな位置に 2 つの初期乱数(2 または 4)を生成します。print_board(): この関数は、ゲームボードの現在の状態を表示するために使用されます。現在のスコアと各セルの数字が含まれます。while (1): これは無限ループで、ゲーム終了条件が満たされるまでゲームを実行し続けます。
ここでは、2048 ゲームの主要な流れが実装されています。ゲームボードの初期化、数字ブロックの移動、ゲームの勝敗判定、およびプレイヤーの入力を待ってゲームの進行を制御することが含まれます。
ゲームボードを初期化する
ゲームボードを初期化するために、ボードをセットアップして 2 つの初期乱数を生成する init_board 関数を作成します。
void init_board() {
// Initialize the board by setting all cells to 0
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
board[i][j] = 0;
}
}
// Generate two initial random numbers
for (int k = 0; k < 2; k++) {
int i = rand() % SIZE;
int j = rand() % SIZE;
int value = (rand() % 2 + 1) * 2; // Generate 2 or 4 randomly
board[i][j] = value;
}
}
この関数の役割は、ゲーム開始時にゲームボード上のすべてのセルを空にし、ランダムな位置に 2 つの初期乱数ブロックを生成し、プレイヤーに初期のゲーム状態を提供することです。
ゲーム状態をチェックする関数を実装する
プレイヤーが勝利したか、ボードが満杯か、有効な移動が残っているかをチェックする関数が必要です。以下がそれらの関数です。
int is_full() {
// Check if the board is full
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
if (board[i][j] == 0) {
return 0; // Board is not full
}
}
}
return 1; // Board is full
}
int is_won() {
// Check if the player has won
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
if (board[i][j] == WIN_SCORE) {
return 1; // Player has won
}
}
}
return 0; // Player has not won
}
int can_move() {
// Check if there are any valid moves left
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
if (board[i][j] == 0) {
return 1; // There are still empty cells to move
}
if (j > 0 && board[i][j] == board[i][j - 1]) {
return 1; // Can move left
}
if (j < SIZE - 1 && board[i][j] == board[i][j + 1]) {
return 1; // Can move right
}
if (i > 0 && board[i][j] == board[i - 1][j]) {
return 1; // Can move up
}
if (i < SIZE - 1 && board[i][j] == board[i + 1][j]) {
return 1; // Can move down
}
}
}
return 0; // No valid moves left
}
int is_full(): この関数は、ボードが満杯か、つまりすべてのセルが占有されているかをチェックするために使用されます。int is_won(): この関数は、プレイヤーが勝利したか、つまりゲームで勝利条件であるWIN_SCORE(通常は 2048)の値を持つセルがあるかをチェックします。int can_move(): この関数は、まだ有効な移動ステップが残っているかをチェックし、ゲームが続行できることを保証するために使用されます。
タイルを移動させるロジックを作成する
move 関数でタイルを移動するロジックを実装します。この関数は、プレイヤーの上、下、左、右の 4 方向の移動を処理します。また、移動が有効かどうかをチェックし、スコアを更新し、新しい乱数を生成します。
int move(int dir) {
int moved = 0;
// Store the current board state
int prev_board[SIZE][SIZE];
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
prev_board[i][j] = board[i][j];
}
}
// Move upwards
if (dir == 0) {
for (int j = 0; j < SIZE; j++) {
for (int i = 1; i < SIZE; i++) {
if (board[i][j]!= 0) {
int k = i;
while (k > 0 && board[k - 1][j] == 0) {
board[k - 1][j] = board[k][j];
board[k][j] = 0;
k--;
moved = 1;
}
if (k > 0 && board[k - 1][j] == board[k][j]) {
board[k - 1][j] *= 2;
score += board[k - 1][j];
board[k][j] = 0;
moved = 1;
}
}
}
}
}
// Move downwards
else if (dir == 1) {
for (int j = 0; j < SIZE; j++) {
for (int i = SIZE - 2; i >= 0; i--) {
if (board[i][j]!= 0) {
int k = i;
while (k < SIZE - 1 && board[k + 1][j] == 0) {
board[k + 1][j] = board[k][j];
board[k][j] = 0;
k++;
moved = 1;
}
if (k < SIZE - 1 && board[k + 1][j] == board[k][j]) {
board[k + 1][j] *= 2;
score += board[k + 1][j];
board[k][j] = 0;
moved = 1;
}
}
}
}
}
// Move left
else if (dir == 2) {
for (int i = 0; i < SIZE; i++) {
for (int j = 1; j < SIZE; j++) {
if (board[i][j]!= 0) {
int k = j;
while (k > 0 && board[i][k - 1] == 0) {
board[i][k - 1] = board[i][k];
board[i][k] = 0;
k--;
moved = 1;
}
if (k > 0 && board[i][k - 1] == board[i][k]) {
board[i][k - 1] *= 2;
score += board[i][k - 1];
board[i][k] = 0;
moved = 1;
}
}
}
}
}
// Move right
else if (dir == 3) {
for (int i = 0; i < SIZE; i++) {
for (int j = SIZE - 2; j >= 0; j--) {
if (board[i][j]!= 0) {
int k = j;
while (k < SIZE - 1 && board[i][k + 1] == 0) {
board[i][k + 1] = board[i][k];
board[i][k] = 0;
k++;
moved = 1;
}
if (k < SIZE - 1 && board[i][k + 1] == board[i][k]) {
board[i][k + 1] *= 2;
score += board[i][k + 1];
board[i][k] = 0;
moved = 1;
}
}
}
}
}
// Check if the move was successful
if (moved) {
// Generate a new random number
int i = rand() % SIZE;
int j = rand() % SIZE;
while (board[i][j]!= 0) {
i = rand() % SIZE;
j = rand() % SIZE;
}
board[i][j] = (rand() % 2 + 1) * 2; // Generate 2 or 4
// Print the board after the move
print_board();
}
// Check if the move was successful
if (moved) {
return 1;
} else {
// If the move failed, restore the previous board state
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
board[i][j] = prev_board[i][j];
}
}
return 0;
}
}
まず、
moved変数を定義して、移動が発生したかどうかをマークします。初期値は 0 で、移動が発生していないことを示します。prev_boardという一時的な 2 次元配列を作成して、ゲームボードの現在の状態を保存します。これにより、移動が失敗した場合に前の状態に戻すことができます。ゲームボードの現在の状態を
prev_boardにコピーし、移動が失敗した場合に備えてゲームボードの現在の状態を保存します。dirパラメータの値(0 は上、1 は下、2 は左、3 は右)に応じて、対応する移動操作を実行します。移動またはマージが発生した場合、
movedフラグを 1 に設定して、ゲーム状態が変更されたことを示します。移動またはマージ操作が成功した場合、新しい乱数を生成します。これは、ゲームボードの空白の場所に新しい数字のブロックを生成するために使用されます。最後に、移動が発生した場合(movedが 1)、関数は 1 を返して、移動が成功したことを示します。移動が失敗した場合(移動またはマージ操作がない)、ゲームボードを前の状態に戻し、0 を返して、移動が失敗したことを示します。
ゲームボードを表示する
ゲームボードを表示するために、ターミナルをクリアしてボードの現在の状態を表示する print_board 関数を作成します。
void print_board() {
// Clear the terminal
system("clear");
printf("Score: %d\n", score);
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
printf("%4d", board[i][j]);
}
printf("\n");
}
}
ここでの主な目的は、ターミナル画面をクリアし、画面上部に現在のスコアを表示し、その後、ゲームボードの状態を画面に表示することです。これにより、プレイヤーはゲームボード上の数字ブロックとスコアを明確に確認できます。これは、プレイヤーがゲームの現在の状態を把握できる使いやすいインターフェースを提供するのに役立ちます。
コンパイルとテスト
ターミナルで以下のコマンドを入力してコンパイルし、実行します。
cd ~/project
gcc -o 2048 2048.c
./2048

まとめ
このプロジェクトでは、C 言語で基本的な 2048 ゲームを作成する方法を学びました。ゲームボードの初期化、ゲーム状態をチェックする関数の実装、タイルを移動するロジックの作成、ゲームボードの表示、そしてゲームの実行を行いました。2048 ゲームを楽しんで、さらに改良してみてください!



