C++で書かれた2048ゲーム(http://vivi.dyndns.org/tech/games/2048.html)をC言語に書き換えたもの。
コンソールアプリで文字色を変更する処理は省略。
//---------------------------------------------------------------------- // 2048 // Copyright (C) 2048 by N.Tsuda // License: CDDL 1.0 (http://opensource.org/licenses/CDDL-1.0) //---------------------------------------------------------------------- #include <conio.h> // _getch #include <time.h> // time #include <stdio.h> #include <stdlib.h> #include <string.h> #define WALL -1 // 番人 #define BOARD_WD 4 // ボード幅 #define BOARD_HT 4 // ボード高さ #define CELL_WIDTH 8 // セル表示幅 #define KEY_ARROW 0xe0 #define KEY_UP 0x48 #define KEY_LEFT 0x4b #define KEY_RIGHT 0x4d #define KEY_DOWN 0x50 int g_score = 0; //int g_nBlank; // 空欄箇所数 int g_board[BOARD_WD+2][BOARD_HT+2]; // 番人付きボード2次元配列 #define swap(a, b) (a += b, b = a - b, a -= b) // 最上位ビットの位置(0~31)を返す // v が0ならば0, 1ならば1,2ならば2, 4ならば3, 8ならば4,... を返す // v がマイナスならば -1 を返す // int は符号付き32ビット整数と仮定する int msbPos(int v) { int n = 31; int mask; if( v == 0 ) return 0; if( v < 0 ) return -1; mask = 1 << (n-1); while( (v & mask) == 0 ) { mask >>= 1; --n; } return n; } //---------------------------------------------------------------------- void init_board() { int x, y; //g_nBlank = BOARD_WD * BOARD_HT; // 空欄箇所数 for (x = 0; x < BOARD_WD+2; ++x) { for (y = 0; y < BOARD_HT+2; ++y) { if( x == 0 || x == BOARD_WD + 1 || y == 0 || y == BOARD_HT + 1 ) { g_board[x][y] = WALL; } else { g_board[x][y] = 0; } } } } void print_line(int y, int printVal) { int x, v; char str[256]; for (x = 1; x <= BOARD_WD; ++x) { str[0] = '\0'; v = g_board[x][y]; if( printVal ) { if( !v ) { strcat_s(str, sizeof(str), " . "); } else { char ss[16]; sprintf_s(ss, sizeof(ss), "%4d ", v); strcat_s(str, sizeof(str), ss); } } printf("%s", str); } printf("\n"); } void print_board() { int y; printf("SCORE: %d\n\n", g_score); for (y = 1; y <= BOARD_HT; ++y) { print_line(y, 0); print_line(y, 0); print_line(y, 1); print_line(y, 0); print_line(y, 0); } printf("\n"); } int nBlank() { int x, y; int nBlank = 0; for (y = 1; y <= BOARD_HT; ++y) { for (x = 1; x <= BOARD_WD; ++x) { if( g_board[x][y] == 0 ) ++nBlank; } } return nBlank; } // 空き箇所のどこかに 2(75%) または 4(25%) を配置する void put_number() { int pos, v, x, y; int n = nBlank(); if( n == 0 ) return; pos = rand() % n; v = (rand() % 100) < 75 ? 2 : 4; // 75% の確率で2,25%の確率で4 for (y = 1; y <= BOARD_HT; ++y) { for (x = 1; x <= BOARD_WD; ++x) { if( g_board[x][y] == 0 ) { // 空欄を探す if( !pos ) { g_board[x][y] = v; return; } --pos; } } } } // 盤面左右反転 void hrev_board() { int x, y; for (y = 1; y <= BOARD_HT; ++y) { for (x = 1; x <= BOARD_WD/2; ++x) { swap(g_board[x][y], g_board[BOARD_WD + 1 - x][y]); } } } // x, y 反転 void swapxy_board() { int x, y; for (y = 1; y < BOARD_HT; ++y) { for (x = y + 1; x <= BOARD_WD; ++x) { swap(g_board[x][y], g_board[y][x]); } } } int move_right() { int y, src, dst, v; int moved = 0; for (y = 1; y <= BOARD_HT; ++y) { dst = BOARD_WD; for(src = BOARD_WD; src >= 1; --src) { v = g_board[src][y]; if( v != 0 ) { if( src == BOARD_WD ) continue; // 右端の場合 if( g_board[dst][y] == 0 ) { // 移動先が空欄 if( dst != src ) { g_board[src][y] = 0; g_board[dst][y] = v; moved = 1; } } else if( g_board[dst][y] == v ) { // 同じ数字 g_score += v * 2; g_board[src][y] = 0; g_board[dst][y] += v; --dst; moved = 1; } else { --dst; if( dst != src ) { g_board[src][y] = 0; g_board[dst][y] = v; moved = 1; } } } } } return moved; } int move_left() { int rc; hrev_board(); rc = move_right(); hrev_board(); return rc; } int move_up() { int rc; swapxy_board(); hrev_board(); rc = move_right(); hrev_board(); swapxy_board(); return rc; } int move_down() { int rc; swapxy_board(); rc = move_right(); swapxy_board(); return rc; } int isMovable() { int x, y; for (y = 1; y <= BOARD_HT; ++y) { for (x = 1; x <= BOARD_WD; ++x) { if( g_board[x][y] == 0 || g_board[x][y] == g_board[x+1][y] || g_board[x][y] == g_board[x][y+1] ) { return 1; } } } return 0; } int g2048() { int moved, c; moved = 0; srand((int)time(0)); for (;;) { g_score = 0; init_board(); put_number(); for(moved;;) { if( moved ) put_number(); print_board(); if( !isMovable() ) break; printf("Type ←↑↓→ "); c = _getch(); if( c == 'q' ) break; if( c == KEY_ARROW ) { c = _getch(); switch( c ) { case KEY_LEFT: moved = move_left(); break; case KEY_RIGHT: moved = move_right(); break; case KEY_UP: moved = move_up(); break; case KEY_DOWN: moved = move_down(); break; } } } printf("Try again ? [y/n] "); for (;;) { c = _getch(); if( c == KEY_ARROW ) _getch(); if( c == 'y' || c == 'Y' || c == 'n' || c == 'N' ) { break; } } if( c != 'y' && c != 'Y' ) break; } return 0; }