From 222d0166f962e440037e8ca94b7ed2326f82e1a6 Mon Sep 17 00:00:00 2001 From: powergold1 Date: Mon, 19 Sep 2016 02:50:27 +0200 Subject: [PATCH] initial commit --- README | 4 + main.c | 554 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.h | 38 ++++ 3 files changed, 596 insertions(+) create mode 100644 README create mode 100644 main.c create mode 100644 main.h diff --git a/README b/README new file mode 100644 index 0000000..a50c5f1 --- /dev/null +++ b/README @@ -0,0 +1,4 @@ +My own toy implementation of 2048 on the command line. + +It supports hjkl for movements and q for quit. + diff --git a/main.c b/main.c new file mode 100644 index 0000000..b72a531 --- /dev/null +++ b/main.c @@ -0,0 +1,554 @@ +#include "main.h" + +#define DBG 0 + +bool move_possible_north(board *b); +bool move_possible_south(board *b); +bool move_possible_east(board *b); +bool move_possible_west(board *b); + +void move_north(board *b); +void move_south(board *b); +void move_east(board *b); +void move_west(board *b); +void merge(board *b, const int d); +void merge_north(board *b); +void merge_south(board *b); +void merge_east(board *b); +void merge_west(board *b); + +void place_new_piece(board *b); +void game_loop(board *b); + +board* new_board() { + board *tmp = malloc(sizeof(board)); + init_board(tmp); + return tmp; +} + +void init_board(board *b) { + for(int i = 0; i < 4; ++i) { + for(int j = 0; j < 4; ++j) + b->x[i][j] = 0; + } + b->points = 0; + b->num_p = 0; + srand((uint)time(NULL)); + place_new_piece(b); + // second piece will be placed in game_loop +} + +void game_start() { + board *b = new_board(); + game_loop(b); + print_score(b); + free_board(b); +} + +void game_loop(board *b) { + char c[16]; + int d; + bool r = true; + while(move_possible_any(b)) { + place_new_piece(b); + print_board(b); + INPUT: + printf("Make a move:\n"); + fgets(c, sizeof(c), stdin); + switch(c[0]) { + case 'h': + d = west; + break; + case 'j': + d = south; + break; + case 'k': + d = north; + break; + case 'l': + d = east; + break; + case 'q': + r = false; + break; + default: + printf("Invalid move: %c\n", c[0]); + goto INPUT; + } + if(!r) + return; + if(!move_possible(b, d)) { + printf("Move not possible: %c\n", c[0]); + goto INPUT; + } + make_move(b, d); + } +} + +void place_new_piece(board *b) { + int prob = rand() % 100; + int possibs[32]; + uint val = 0; + int cnt = 0; + int pair = 0; + int rx = 0, ry = 0; + for(int i = 0; i < 4; ++i) { + for(int j = 0; j < 4; ++j) { + if(b->x[i][j] == 0) { + possibs[2*cnt] = i; + possibs[2*cnt+1] = j; + cnt++; + } + } + } + assert(cnt > 0); + pair = rand() % cnt; + rx = possibs[2*pair]; + ry = possibs[2*pair+1]; + assert(b->x[rx][ry] == 0); + if(prob > 9) + val = 2; + else + val = 4; + b->x[rx][ry] = val; + b->num_p++; +} + +void free_board(board *b) { + free(b); +} + +void make_move(board *b, const int d) { + bool ok = (d == south) || + (d == east) || + (d == north) || + (d == west); + assert(ok); + /* + * checked before already + * if(!move_possible(b, d)) + * return; + */ + move(b, d); + merge(b, d); + move(b, d); +} + +bool move_possible_any(board *b) { + if(b->num_p < 16) + return true; + if(move_possible_south(b)) + return true; + if(move_possible_east(b)) + return true; + if(move_possible_north(b)) + return true; + if(move_possible_west(b)) + return true; + return false; +} + +bool move_possible(board *b, const int d) { + bool ok = (d == south) || + (d == east) || + (d == north) || + (d == west); + assert(ok); + switch(d) { + case north: + return move_possible_north(b); + case south: + return move_possible_south(b); + case east: + return move_possible_east(b); + case west: + return move_possible_west(b); + default: // will never execute anyway + return false; + } +} + +void move(board *b, const int d) { + bool ok = (d == south) || + (d == east) || + (d == north) || + (d == west); + assert(ok); + switch(d) { + case north: + move_north(b); + break; + case south: + move_south(b); + break; + case east: + move_east(b); + break; + case west: + move_west(b); + break; + default: // will never execute anyway + return; + } +} + +void merge(board *b, const int d) { + bool ok = (d == south) || + (d == east) || + (d == north) || + (d == west); + assert(ok); + switch(d) { + case north: + merge_north(b); + break; + case south: + merge_south(b); + break; + case east: + merge_east(b); + break; + case west: + merge_west(b); + break; + default: // will never execute anyway + return; + } +} + +bool move_possible_south(board *b) { + for(int i = 0; i < 4; ++i) { + for(int j = 0; j < 3; ++j) { + if(b->x[i][j] != 0) { + if(b->x[i][j+1] == 0) + return true; + if(b->x[i][j] == b->x[i][j+1]) + return true; + } + } + } + return false; +} + +bool move_possible_north(board *b) { + for(int i = 0; i < 4; ++i) { + for(int j = 1; j < 4; ++j) { + if(b->x[i][j] != 0) { + if(b->x[i][j-1] == 0) + return true; + if(b->x[i][j] == b->x[i][j-1]) + return true; + } + } + } + return false; +} + +bool move_possible_east(board *b) { + for(int i = 0; i < 3; ++i) { + for(int j = 0; j < 4; ++j) { + if(b->x[i][j] != 0) { + if(b->x[i+1][j] == 0) + return true; + if(b->x[i+1][j] == b->x[i][j]) + return true; + } + } + } + return false; +} + +bool move_possible_west(board *b) { + for(int i = 1; i < 4; ++i) { + for(int j = 0; j < 4; ++j) { + if(b->x[i][j] != 0) { + if(b->x[i-1][j] == 0) + return true; + if(b->x[i-1][j] == b->x[i][j]) + return true; + } + } + } + return false; +} + +void move_north(board *b) { + int k; + for(int i = 0; i < 4; ++i) { + for(int j = 1; j < 4; ++j) { + if(b->x[i][j] != 0) { + k = j; + while(b->x[i][k-1] == 0) { + b->x[i][k-1] = b->x[i][k]; + b->x[i][k] = 0; + k--; + if(k < 1) + break; + } + } + } + } +} + +void move_south(board *b) { + int k; + for(int i = 0; i < 4; ++i) { + for(int j = 2; j >= 0; --j) { + if(b->x[i][j] != 0) { + k = j; + while(b->x[i][k+1] == 0) { + b->x[i][k+1] = b->x[i][k]; + b->x[i][k] = 0; + k++; + if(k > 2) + break; + } + } + } + } +} + +void move_east(board *b) { + int k; + for(int i = 2; i >= 0; --i) { + for(int j = 0; j < 4; ++j) { + if(b->x[i][j] != 0) { + k = i; + while(b->x[k+1][j] == 0) { + b->x[k+1][j] = b->x[k][j]; + b->x[k][j] = 0; + k++; + if(k > 2) + break; + } + } + } + } +} + +void move_west(board *b) { + int k; + for(int i = 1; i < 4; ++i) { + for(int j = 0; j < 4; ++j) { + if(b->x[i][j] != 0) { + k = i; + while(b->x[k-1][j] == 0) { + b->x[k-1][j] = b->x[k][j]; + b->x[k][j] = 0; + k--; + if(k < 1) + break; + } + } + } + } +} + +void merge_north(board *b) { + for(int i = 0; i < 4; ++i) { + for(int j = 1; j < 4; ++j) { + if(b->x[i][j] != 0 && b->x[i][j] == b->x[i][j-1]) { + b->x[i][j-1] *= 2; + b->x[i][j] = 0; + b->num_p--; + b->points += b->x[i][j-1]; + } + } + } +} + +void merge_south(board *b) { + for(int i = 0; i < 4; ++i) { + for(int j = 2; j >= 0; --j) { + if(b->x[i][j] != 0 && b->x[i][j] == b->x[i][j+1]) { + b->x[i][j+1] *= 2; + b->x[i][j] = 0; + b->num_p--; + b->points += b->x[i][j+1]; + } + } + } +} + +void merge_east(board *b) { + for(int i = 2; i >= 0; --i) { + for(int j = 0; j < 4; ++j) { + if(b->x[i][j] != 0 && b->x[i+1][j] == b->x[i][j]) { + b->x[i+1][j] *= 2; + b->points += b->x[i+1][j]; + b->num_p--; + b->x[i][j] = 0; + } + } + } +} + +void merge_west(board *b) { + for(int i = 1; i < 4; ++i) { + for(int j = 0; j < 4; ++j) { + if(b->x[i][j] != 0 && b->x[i-1][j] == b->x[i][j]) { + b->x[i-1][j] *= 2; + b->points += b->x[i-1][j]; + b->num_p--; + b->x[i][j] = 0; + } + } + } +} + +void print_sep() { + printf("||--------------------------------------------------------------||\n"); +} + +void print_board_line(board *b, int l) { + printf("||\t%u\t|\t%u\t|\t%u\t|\t%u\t||\n", b->x[0][l], b->x[1][l], b->x[2][l], b->x[3][l]); + print_sep(); +} + +void print_board(board *b) { + printf("Score: %u\n", b->points); + print_sep(); + for(int i = 0; i < 4; ++i) { + print_board_line(b, i); + } + printf("\n"); +} + +void print_score(board *b) { + printf("Game Over\nScore:%u\n", b->points); +} + +void merge_test1() { + board *b = new_board(); + b->x[2][0] = 2; + b->x[3][0] = 2; + merge_east(b); + assert(b->x[3][0] == 4); +} + +void merge_test2() { + board *b = new_board(); + b->x[2][0] = 2; + b->x[3][0] = 2; + print_board(b); + move_west(b); + print_board(b); + merge_west(b); + print_board(b); + assert(b->x[0][0] == 4); +} + +void merge_test3() { + board *b = new_board(); + b->x[0][0] = 2; + b->x[0][1] = 2; + print_board(b); + merge_north(b); + print_board(b); + assert(b->x[0][0] == 4); +} + +void merge_test4() { + board *b = new_board(); + b->x[0][2] = 2; + b->x[0][3] = 2; + print_board(b); + merge_south(b); + print_board(b); + assert(b->x[0][3] == 4); +} + +void move_merge_test1() { + board *b = new_board(); + b->x[2][0] = 4; + b->x[3][0] = 2; + b->x[3][2] = 2; + print_board(b); + move_south(b); + print_board(b); + merge_south(b); + print_board(b); + assert(b->x[3][3] == 4); +} + +void move_north_test() { + board *b = new_board(); + b->x[2][3] = 8; + b->x[2][2] = 0; + b->x[2][1] = 0; + b->x[2][0] = 0; + b->x[0][1] = 2; + b->x[0][0] = 0; + b->x[3][0] = 4; + b->x[3][1] = 2; + b->x[3][2] = 3; + b->x[3][3] = 16; + print_board(b); + move_north(b); + merge_north(b); + move_north(b); + print_board(b); + assert(b->x[2][0] == 8); + assert(b->x[0][0] == 2); +} + +void move_merge_test2() { + board *b = new_board(); + b->x[3][0] = 2; + b->x[3][1] = 2; + b->x[3][2] = 4; + b->x[3][3] = 32; + print_board(b); + move_south(b); + merge_south(b); + move_south(b); + print_board(b); + assert(b->x[3][1] == 4); +} + +void move_merge_test3() { + board *b = new_board(); + b->x[0][0] = 0; + b->x[0][1] = 0; + b->x[0][2] = 0; + b->x[0][3] = 2; + b->x[1][0] = 0; + b->x[1][1] = 0; + b->x[1][2] = 0; + b->x[1][3] = 8; + b->x[2][0] = 0; + b->x[2][1] = 0; + b->x[2][2] = 0; + b->x[2][3] = 4; + b->x[3][0] = 2; + b->x[3][1] = 2; + b->x[3][2] = 4; + b->x[3][3] = 16; + print_board(b); + move_south(b); + merge_south(b); + move_south(b); + print_board(b); + assert(b->x[3][1] == 4); +} + +void run_tests() { + /* + merge_test1(); + merge_test2(); + merge_test3(); + merge_test4(); + move_merge_test1(); + move_north_test(); + */ + move_merge_test2(); + move_merge_test3(); +} + +int main() { +#if DBG + run_tests(); +#else + game_start(); +#endif +} diff --git a/main.h b/main.h new file mode 100644 index 0000000..76a50d7 --- /dev/null +++ b/main.h @@ -0,0 +1,38 @@ +#ifndef BOARD_H_ +#define BOARD_H_ + +#include +#include +#include +#include +#include + +typedef struct board board; +typedef unsigned int uint; +typedef unsigned long ulong; + +enum direction { + north, + south, + west, + east, +}; + +struct board { + uint x[4][4]; + uint points; + uint num_p; +}; + +board *new_board(); +void init_board(board*); +void free_board(board*); +bool move_possible_any(board*); +bool move_possible(board*, const int d); +void make_move(board*, const int d); +void move(board*, const int d); + +void print_board(board*); +void print_score(board*); + +#endif -- 2.44.0