Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
279
Task/2048/C/2048-1.c
Normal file
279
Task/2048/C/2048-1.c
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define D_INVALID -1
|
||||
#define D_UP 1
|
||||
#define D_DOWN 2
|
||||
#define D_RIGHT 3
|
||||
#define D_LEFT 4
|
||||
|
||||
const long values[] = {
|
||||
0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048
|
||||
};
|
||||
|
||||
const char *colors[] = {
|
||||
"39", "31", "32", "33", "34", "35", "36", "37", "91", "92", "93", "94"
|
||||
};
|
||||
|
||||
struct gamestate_struct__ {
|
||||
int grid[4][4];
|
||||
int have_moved;
|
||||
long total_score;
|
||||
long score_last_move;
|
||||
int blocks_in_play;
|
||||
} game;
|
||||
|
||||
struct termios oldt, newt;
|
||||
|
||||
void do_draw(void)
|
||||
{
|
||||
printf("\033[2J\033[HScore: %ld", game.total_score);
|
||||
if (game.score_last_move)
|
||||
printf(" (+%ld)", game.score_last_move);
|
||||
printf("\n");
|
||||
|
||||
for (int i = 0; i < 25; ++i)
|
||||
printf("-");
|
||||
printf("\n");
|
||||
|
||||
for (int y = 0; y < 4; ++y) {
|
||||
printf("|");
|
||||
for (int x = 0; x < 4; ++x) {
|
||||
if (game.grid[x][y])
|
||||
printf("\033[7m\033[%sm%*zd \033[0m|", colors[game.grid[x][y]],
|
||||
4, values[game.grid[x][y]]);
|
||||
else
|
||||
printf("%*s |", 4, "");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
for (int i = 0; i < 25; ++i) {
|
||||
printf("-");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void do_merge(int d)
|
||||
{
|
||||
/* These macros look pretty scary, but mainly demonstrate some space saving */
|
||||
#define MERGE_DIRECTION(_v1, _v2, _xs, _xc, _xi, _ys, _yc, _yi, _x, _y) \
|
||||
do { \
|
||||
for (int _v1 = _xs; _v1 _xc; _v1 += _xi) { \
|
||||
for (int _v2 = _ys; _v2 _yc; _v2 += _yi) { \
|
||||
if (game.grid[x][y] && (game.grid[x][y] == \
|
||||
game.grid[x + _x][y + _y])) { \
|
||||
game.grid[x][y] += (game.have_moved = 1); \
|
||||
game.grid[x + _x][y + _y] = (0 * game.blocks_in_play--);\
|
||||
game.score_last_move += values[game.grid[x][y]]; \
|
||||
game.total_score += values[game.grid[x][y]]; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
game.score_last_move = 0;
|
||||
|
||||
switch (d) {
|
||||
case D_LEFT:
|
||||
MERGE_DIRECTION(x, y, 0, < 3, 1, 0, < 4, 1, 1, 0);
|
||||
break;
|
||||
case D_RIGHT:
|
||||
MERGE_DIRECTION(x, y, 3, > 0, -1, 0, < 4, 1, -1, 0);
|
||||
break;
|
||||
case D_DOWN:
|
||||
MERGE_DIRECTION(y, x, 3, > 0, -1, 0, < 4, 1, 0, -1);
|
||||
break;
|
||||
case D_UP:
|
||||
MERGE_DIRECTION(y, x, 0, < 3, 1, 0, < 4, 1, 0, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
#undef MERGE_DIRECTION
|
||||
}
|
||||
|
||||
void do_gravity(int d)
|
||||
{
|
||||
#define GRAVITATE_DIRECTION(_v1, _v2, _xs, _xc, _xi, _ys, _yc, _yi, _x, _y) \
|
||||
do { \
|
||||
int break_cond = 0; \
|
||||
while (!break_cond) { \
|
||||
break_cond = 1; \
|
||||
for (int _v1 = _xs; _v1 _xc; _v1 += _xi) { \
|
||||
for (int _v2 = _ys; _v2 _yc; _v2 += _yi) { \
|
||||
if (!game.grid[x][y] && game.grid[x + _x][y + _y]) { \
|
||||
game.grid[x][y] = game.grid[x + _x][y + _y]; \
|
||||
game.grid[x + _x][y + _y] = break_cond = 0; \
|
||||
game.have_moved = 1; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
do_draw(); usleep(40000); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
switch (d) {
|
||||
case D_LEFT:
|
||||
GRAVITATE_DIRECTION(x, y, 0, < 3, 1, 0, < 4, 1, 1, 0);
|
||||
break;
|
||||
case D_RIGHT:
|
||||
GRAVITATE_DIRECTION(x, y, 3, > 0, -1, 0, < 4, 1, -1, 0);
|
||||
break;
|
||||
case D_DOWN:
|
||||
GRAVITATE_DIRECTION(y, x, 3, > 0, -1, 0, < 4, 1, 0, -1);
|
||||
break;
|
||||
case D_UP:
|
||||
GRAVITATE_DIRECTION(y, x, 0, < 3, 1, 0, < 4, 1, 0, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
#undef GRAVITATE_DIRECTION
|
||||
}
|
||||
|
||||
int do_check_end_condition(void)
|
||||
{
|
||||
int ret = -1;
|
||||
for (int x = 0; x < 4; ++x) {
|
||||
for (int y = 0; y < 4; ++y) {
|
||||
if (values[game.grid[x][y]] == 2048)
|
||||
return 1;
|
||||
if (!game.grid[x][y] ||
|
||||
((x + 1 < 4) && (game.grid[x][y] == game.grid[x + 1][y])) ||
|
||||
((y + 1 < 4) && (game.grid[x][y] == game.grid[x][y + 1])))
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int do_tick(int d)
|
||||
{
|
||||
game.have_moved = 0;
|
||||
do_gravity(d);
|
||||
do_merge(d);
|
||||
do_gravity(d);
|
||||
return game.have_moved;
|
||||
}
|
||||
|
||||
void do_newblock(void) {
|
||||
if (game.blocks_in_play >= 16) return;
|
||||
|
||||
int bn = rand() % (16 - game.blocks_in_play);
|
||||
int pn = 0;
|
||||
|
||||
for (int x = 0; x < 4; ++x) {
|
||||
for (int y = 0; y < 4; ++y) {
|
||||
if (game.grid[x][y])
|
||||
continue;
|
||||
|
||||
if (pn == bn){
|
||||
game.grid[x][y] = rand() % 10 ? 1 : 2;
|
||||
game.blocks_in_play += 1;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
++pn;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* Initialize terminal settings */
|
||||
tcgetattr(STDIN_FILENO, &oldt);
|
||||
newt = oldt;
|
||||
newt.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
||||
|
||||
srand(time(NULL));
|
||||
memset(&game, 0, sizeof(game));
|
||||
do_newblock();
|
||||
do_newblock();
|
||||
do_draw();
|
||||
|
||||
while (1) {
|
||||
int found_valid_key, direction, value;
|
||||
do {
|
||||
found_valid_key = 1;
|
||||
direction = D_INVALID;
|
||||
value = getchar();
|
||||
switch (value) {
|
||||
case 'h': case 'a':
|
||||
direction = D_LEFT;
|
||||
break;
|
||||
case 'l': case 'd':
|
||||
direction = D_RIGHT;
|
||||
break;
|
||||
case 'j': case 's':
|
||||
direction = D_DOWN;
|
||||
break;
|
||||
case 'k': case 'w':
|
||||
direction = D_UP;
|
||||
break;
|
||||
case 'q':
|
||||
goto game_quit;
|
||||
break;
|
||||
case 27:
|
||||
if (getchar() == 91) {
|
||||
value = getchar();
|
||||
switch (value) {
|
||||
case 65:
|
||||
direction = D_UP;
|
||||
break;
|
||||
case 66:
|
||||
direction = D_DOWN;
|
||||
break;
|
||||
case 67:
|
||||
direction = D_RIGHT;
|
||||
break;
|
||||
case 68:
|
||||
direction = D_LEFT;
|
||||
break;
|
||||
default:
|
||||
found_valid_key = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
found_valid_key = 0;
|
||||
break;
|
||||
}
|
||||
} while (!found_valid_key);
|
||||
|
||||
do_tick(direction);
|
||||
if (game.have_moved != 0){
|
||||
do_newblock();
|
||||
}
|
||||
do_draw();
|
||||
|
||||
switch (do_check_end_condition()) {
|
||||
case -1:
|
||||
goto game_lose;
|
||||
case 1:
|
||||
goto game_win;
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (0)
|
||||
game_lose:
|
||||
printf("You lose!\n");
|
||||
goto game_quit;
|
||||
if (0)
|
||||
game_win:
|
||||
printf("You win!\n");
|
||||
goto game_quit;
|
||||
if (0)
|
||||
game_quit:
|
||||
|
||||
/* Restore terminal settings */
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
||||
return 0;
|
||||
}
|
||||
340
Task/2048/C/2048-2.c
Normal file
340
Task/2048/C/2048-2.c
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#define EMPTY_TILE 0
|
||||
#define ROWS 4
|
||||
#define COLUMNS 4
|
||||
|
||||
|
||||
/*
|
||||
* GENERAL CONCEPT
|
||||
*
|
||||
* How do you add up tiles when there is whitespace between them?
|
||||
* You sort the array so that there are no empty tiles between them while stacking them all to one side
|
||||
* then the addition function always adds up from left to right or up to bottom. It does not care
|
||||
* about the left movements or the down movement. This can be achieved by reversing the array
|
||||
* whenever the player chooses to move to the right or down, when the addition is finished
|
||||
* the array gets reversed back and its like it had been added from right to left or bottom to top
|
||||
* When the addition is done, the program scans for the number of empty tiles and uses that
|
||||
* in its selection of the next tile to be filled. 10% of times a tile gets occupied with a 4
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* the remove_whitespace functions; it is pretty clear what they do.
|
||||
* they use a bubble short algorith to move the 0's or empty tiles to the end of the array
|
||||
* depending on the direction moved (without carring about going right or up
|
||||
*
|
||||
*/
|
||||
|
||||
void remove_whitespace_horizontaly(int board[ROWS][COLUMNS], int rows, int columns)
|
||||
{
|
||||
int a = columns;
|
||||
int tmp;
|
||||
|
||||
|
||||
for (; a < COLUMNS - 1; ++a) {
|
||||
tmp = board[rows][a];
|
||||
board[rows][a] = board[rows][a+1];
|
||||
board[rows][a+1] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void remove_whitespace_verticaly(int board[ROWS][COLUMNS], int columns, int rows)
|
||||
{
|
||||
int a = rows;
|
||||
int tmp;
|
||||
|
||||
for (; a < ROWS - 1; ++a) {
|
||||
tmp = board[a][columns];
|
||||
board[a][columns] = board[a+1][columns];
|
||||
board[a+1][columns] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* the add_tiles functions. those functions do the heavy work of adding the tiles and
|
||||
* taking care of special situations such as when adding two equal tiles a 0 gets generated
|
||||
* they are quite difficult to understand i think (which means not that you need to be too clever
|
||||
* but that i have done a poor job of creating them) and it took around 4 hours to get the
|
||||
* proper result
|
||||
*/
|
||||
|
||||
void add_tiles_horizontaly(int board[ROWS][COLUMNS])
|
||||
{
|
||||
int a, b, flag;
|
||||
|
||||
for (a = 0; a < ROWS; ++a) {
|
||||
for (b = 0, flag = 0; b < COLUMNS - 1 && flag != 4; ++b) {
|
||||
if (board[a][b] == EMPTY_TILE) {
|
||||
remove_whitespace_horizontaly(board, a, b);
|
||||
--b;
|
||||
++flag;
|
||||
}
|
||||
else {
|
||||
if (board[a][b+1] == EMPTY_TILE) {
|
||||
board[a][b+1] = board[a][b];
|
||||
board[a][b] = EMPTY_TILE;
|
||||
--b;
|
||||
} else if (board[a][b] == board[a][b+1]) {
|
||||
board[a][b] += board[a][b+1];
|
||||
board[a][b+1] = EMPTY_TILE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_tiles_verticaly(int board[ROWS][COLUMNS])
|
||||
{
|
||||
int a, b, flag;
|
||||
|
||||
for (a = 0; a < COLUMNS; ++a) {
|
||||
for (b = 0, flag = 0; b < ROWS-1 && flag != 4; ++b) {
|
||||
if (board[b][a] == EMPTY_TILE) {
|
||||
remove_whitespace_verticaly(board, a, b);
|
||||
--b;
|
||||
++flag;
|
||||
}
|
||||
else {
|
||||
if (board[b+1][a] == EMPTY_TILE) {
|
||||
board[b+1][a] = board[b][a];
|
||||
board[b][a] = EMPTY_TILE;
|
||||
--b;
|
||||
} else if (board[b][a] == board[b+1][a]) {
|
||||
board[b][a] += board[b+1][a];
|
||||
board[b+1][a] = EMPTY_TILE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ... print the board
|
||||
*/
|
||||
|
||||
void print_board(int board[ROWS][COLUMNS])
|
||||
{
|
||||
int a, b;
|
||||
|
||||
for (a = 0; a < ROWS; ++a) {
|
||||
printf("\n");
|
||||
for (b = 0; b < COLUMNS; ++b) {
|
||||
printf("%5i", board[a][b]);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* The reverse_board function reverses the array
|
||||
* if the movement is right or down reverse the array
|
||||
*/
|
||||
|
||||
void reverse_board(char input[], int board[ROWS][COLUMNS])
|
||||
{
|
||||
int a, b, c, tmp;
|
||||
|
||||
if (!strcmp(input, "right")) {
|
||||
for (a = 0; a < ROWS; ++a) {
|
||||
for (b = 0, c = 3; b < 2; ++b, --c) {
|
||||
tmp = board[a][b];
|
||||
board[a][b] = board[a][c];
|
||||
board[a][c] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp(input, "down")) {
|
||||
for (a = 0; a < COLUMNS; ++a) {
|
||||
for (b = 0, c = 3; b < 2; ++b, --c) {
|
||||
tmp = board[b][a];
|
||||
board[b][a] = board[c][a];
|
||||
board[c][a] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* the check_board function is the one which evaluates the win or lose condition
|
||||
* for each turn and at the same time providing the number of empty tiles for the random generator
|
||||
* function
|
||||
*/
|
||||
|
||||
int check_board (int board[ROWS][COLUMNS])
|
||||
{
|
||||
int a, b;
|
||||
|
||||
int result = 0;
|
||||
int empty_tiles = 0;
|
||||
|
||||
|
||||
for (a = 0; a < ROWS; ++a)
|
||||
for (b = 0; b < COLUMNS; ++b)
|
||||
if (board[a][b] == 2048)
|
||||
result = -1;
|
||||
else if (board[a][b] == EMPTY_TILE)
|
||||
++empty_tiles;
|
||||
|
||||
result = result == -1 ? result : empty_tiles;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* the generate_random functin generates a random number between 0 and the number of
|
||||
* empty tiles. the generated number will assign to the Nth empty tile = (random_number)
|
||||
* the new value, it also takes care of the 10% chance for producing a 4 tile
|
||||
*/
|
||||
|
||||
void generate_random(int board[ROWS][COLUMNS], int empty_tiles )
|
||||
{
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
int a, b;
|
||||
int random = 0;
|
||||
int tile = 0;
|
||||
|
||||
random = rand() % empty_tiles;
|
||||
tile = (rand() % 9 == 4) ? 4 : 2;
|
||||
|
||||
for (a = 0; a < ROWS; ++a)
|
||||
for (b = 0; b < COLUMNS; ++b)
|
||||
if (board[a][b] == EMPTY_TILE && random != 0)
|
||||
--random;
|
||||
else if (board[a][b] == EMPTY_TILE && random == 0) {
|
||||
board[a][b] = tile;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* infinite loop, get the movements or exit code and act accordingly
|
||||
*/
|
||||
|
||||
int play_game(int board[ROWS][COLUMNS])
|
||||
{
|
||||
|
||||
char movement[81];
|
||||
int tiles = 0;
|
||||
|
||||
printf("this is the 2048 game\n" \
|
||||
"The goal of this game is make a tile reach the value of 2048\n"\
|
||||
"The board starts of with only one occupied tile.\n"\
|
||||
"On each round a new tile gets added with the value of 2\n"\
|
||||
"or at 10%% of the times with the value of 4\n"\
|
||||
"If you run out of tiles you lose\n"\
|
||||
"There are 4 movements you can supply to the game\n"\
|
||||
"right, left, up, and down.\n"\
|
||||
"For each of this movements the tiles move to the direction specified\n"\
|
||||
"If two tiles have the same value the get added up just once.\n"\
|
||||
"If 2 occupied tiles share the same row or column but are seperated by empty tiles\n"\
|
||||
"then the occupied tiles travel along the empty tiles stacking in the direction\n"\
|
||||
"they were directed\n"\
|
||||
"For a more visual explanation you can check the wikipedia entry\n"
|
||||
" if you search for 2058 board game\n" \
|
||||
"Here we go\n");
|
||||
|
||||
print_board(board);
|
||||
while (1) {
|
||||
printf("(enter: left,right,up,down,exit)>> ");
|
||||
scanf("%s", movement);
|
||||
if (!strcmp(movement, "down")) {
|
||||
reverse_board(movement,board);
|
||||
add_tiles_verticaly(board);
|
||||
tiles = check_board(board);
|
||||
if (tiles == -1)
|
||||
return -1;
|
||||
else if (tiles == 0)
|
||||
return 0;
|
||||
generate_random(board,tiles);
|
||||
reverse_board(movement, board);
|
||||
}
|
||||
else if (!strcmp(movement, "up")) {
|
||||
add_tiles_verticaly(board);
|
||||
tiles = check_board(board);
|
||||
if (tiles == -1)
|
||||
return -1;
|
||||
else if (tiles == 0)
|
||||
return 0;
|
||||
generate_random(board,tiles);
|
||||
}
|
||||
else if (!strcmp(movement, "right")) {
|
||||
reverse_board(movement,board);
|
||||
add_tiles_horizontaly(board);
|
||||
tiles = check_board(board);
|
||||
if (tiles == -1)
|
||||
return -1;
|
||||
else if (tiles == 0)
|
||||
return 0;
|
||||
generate_random(board,tiles);
|
||||
reverse_board(movement, board);
|
||||
}
|
||||
else if (!strcmp(movement, "left")) {
|
||||
add_tiles_horizontaly(board);
|
||||
tiles = check_board(board);
|
||||
if (tiles == -1)
|
||||
return -1;
|
||||
else if (tiles == 0)
|
||||
return 0;
|
||||
generate_random(board,tiles);
|
||||
}
|
||||
else if (!strcmp(movement, "exit")) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
printf("Do not recognize this movement please type again\n");
|
||||
continue;
|
||||
}
|
||||
print_board(board);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int play_game(int board[ROWS][COLUMNS]);
|
||||
void generate_random(int board[ROWS][COLUMNS], int empty_tiles );
|
||||
int check_board (int board[ROWS][COLUMNS]);
|
||||
void reverse_board(char input[], int board[ROWS][COLUMNS]);
|
||||
void print_board(int board[ROWS][COLUMNS]);
|
||||
void add_tiles_verticaly(int board[ROWS][COLUMNS]);
|
||||
void add_tiles_horizontaly(int board[ROWS][COLUMNS]);
|
||||
void remove_whitespace_verticaly(int board[ROWS][COLUMNS], int columns, int rows);
|
||||
void remove_whitespace_horizontaly(int board[ROWS][COLUMNS], int rows, int columns);
|
||||
|
||||
int win_condition;
|
||||
int board[ROWS][COLUMNS] = {
|
||||
{0,0,0,0},
|
||||
{0,0,0,0},
|
||||
{0,0,0,0},
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
|
||||
generate_random(board, 16); /* initialize the board */
|
||||
|
||||
win_condition = play_game(board);
|
||||
switch (win_condition) {
|
||||
case 1:
|
||||
printf("But you are not done yet!!!\n" \
|
||||
"Fine, see you another day\n");
|
||||
break;
|
||||
case 0:
|
||||
printf("Ohh noo, you run out of tiles\n" \
|
||||
"Run me agan to play some more\n" \
|
||||
"Byyyeee\n");
|
||||
break;
|
||||
case -1:
|
||||
printf("WooooW you did it, Good job!!!\n" \
|
||||
"See ya later homie\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue