summaryrefslogtreecommitdiff
path: root/pieces.c
blob: 3b7100375e9c8da24f483661f2def11dfd25caef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "pieces.h"
#include "util.h"

const int N_SHAPES = 17;
const struct piece SHAPES[] = {
    {1, 1, 1, "+"},
    {1, 2, 2, "++"},
    {1, 3, 3, "+++"},
    {1, 4, 4, "++++"},
    {1, 5, 5, "+++++"},
    {2, 2, 2, "+  +"},         // 2x2 diagonal
    {2, 2, 4, "++++"},         // 2x2 square
    {2, 3, 4, "++++  "},       // L shape
    {2, 3, 4, "++  ++"},       // Z shape
    {2, 3, 4, "+++ + "},       // T shape
    {2, 3, 6, "++++++"},       // 2x3 rectangle
    {2, 4, 5, "+++++   "},     // long L shape
    {2, 4, 8, "++++++++"},     // 2x4 rectangle
    {3, 3, 5, "++++  +  "},    // large L shape
    {3, 3, 5, "+++ +  + "},    // large T shape
    {3, 3, 3, "+   +   +"},    // 3x3 diagonal
    {3, 3, 9, "+++++++++"},    // 3x3 square
};

void transpose(struct piece* pc) {
    // transpose blocks
    char* old = malloc(strlen(pc->blocks) + 1);
    if (old == NULL)
        mallocfail();

    strcpy(old, pc->blocks); // before transposition
    for (int r = 0; r < pc->h; r++) {
        for (int c = 0; c < pc->w; c++) {
            pc->blocks[c * (pc->h) + r] = old[r * (pc->w) + c];
        }
    }
    free(old);
    // swap dimensions
    int h = pc->h;
    pc->h = pc->w;
    pc->w = h;
}

void rotate(struct piece* pc) {
    // rotate `pc` ccw by 90 degrees
    // transpose blocks
    char* old = malloc(strlen(pc->blocks) + 1);
    if (old == NULL)
        mallocfail();

    strcpy(old, pc->blocks); // before transposition
    for (int r = 0; r < pc->h; r++) {
        for (int c = 0; c < pc->w; c++) {
            pc->blocks[(pc->w - c - 1) * (pc->h) + r] = old[r * (pc->w) + c];
        }
    }
    free(old);
    // swap dimensions
    int h = pc->h;
    pc->h = pc->w;
    pc->w = h;
}

struct piece* randpiece() {
    // select a random shape from `SHAPES`, make a copy where memory for `.blocks` is manually managed,
    // then do random transformations to the copy
    struct piece shape = SHAPES[rand() % N_SHAPES];
    char* blocks = malloc(strlen(shape.blocks) + 1);
    if (blocks == NULL)
        mallocfail();

    strcpy(blocks, shape.blocks);
    struct piece* pc = malloc(sizeof(struct piece));
    if (pc == NULL)
        mallocfail();

    pc->h = shape.h;
    pc->w = shape.w;
    pc->points = shape.points;
    pc->blocks = blocks;
    if (rand() % 2) transpose(pc);
    for (int i = rand() % 4; i > 0; i--) // 0 to 3 times
        rotate(pc);
    return pc;
}

void refillpieces(struct piece** hand, int nhand) {
    // randomly select `nhand` pieces to `hand`
    for (int i = 0; i < nhand; i++) {
        hand[i] = randpiece();
    }
}

bool placeable(char** map, struct piece* pc, int row, int col, int mapH, int mapW) {
    // boundary check
    if (row < 0 || row + (pc->h) > mapH || col < 0 || col + (pc->w) > mapW)
        return false;

    // check if blocks to be taken by `pc` are vacant
    for (int r = 0; r < pc->h; r++) {
        for (int c = 0; c < pc->w; c++) {
            if (map[row + r][col + c] == '+' && pc->blocks[r * pc->w + c] == '+')
                return false;
        }
    }

    return true;
}

void place(char** map, struct piece* pc, int row, int col) {
    for (int r = 0; r < pc->h; r++) {
        for (int c = 0; c < pc->w; c++) {
            if (pc->blocks[r * (pc->w) + c] == '+')
                map[row + r][col + c] = '+';
        }
    }
}

void freepiece(struct piece* pc) {
    free(pc->blocks);
    free(pc);
}