aboutsummaryrefslogtreecommitdiff
path: root/src/board.c
blob: 95b873847efd1349f58f98b29d7119002ba3c0e1 (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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#include <stdio.h>
#include "board.h"

void initialize_board(BoardUnit* board) {
  for (int i = 0; i < BOARD_UNITS; i++) {
    board[i].feature = EMPTY;
    board[i].meeple = 0;
    board[i].structure_group = 0;
  }
}

int is_center_index(int index) {
  return ((index / BOARD_ROW_UNITS) % 2 == 1) && ((index % BOARD_ROW_UNITS) % 2 == 1);
}

int is_allowed_placement(Tile tile, int index, BoardUnit* board) {
  if (board[index].feature != EMPTY) return 0;

  int neighbor_count = 0;

  for (int i = 0; i < 4; i++) {
    char neighbor = board[index + NEIGHBOR_INCREMENTS[i]].feature;
    if (neighbor != EMPTY) {
      if (neighbor != tile.edges[i]) return 0;
      neighbor_count++;
    }
  }

  return neighbor_count > 0;
}

int place_tile(Tile tile, int index, BoardUnit* board, int force) {
  if (!is_center_index(index)) return 0;
  if (!force && !is_allowed_placement(tile, index, board)) return 0;

  board[index].feature = tile.center;
  for (int i = 0; i < 4; i++) {
    board[index + NEIGHBOR_INCREMENTS[i]].feature = tile.edges[i];
  }

  return 1;
}

void rotate_tile(Tile* tile, int increment) {
  char buffer[8];
  for (int i = 0; i < 8; i++) {
    buffer[i] = tile->edges[i % 4];
  }

  for (int i = 0; i < 4; i++) {
    tile->edges[i] = buffer[i + (increment % 4)];
  }
}

void traverse_structure(int group, int index, BoardUnit* board) {
  board[index].structure_group = group;
  for (int i = 0; i < 4; i++) {
    int new_unit = index + NEIGHBOR_INCREMENTS[i];
    if (board[new_unit].feature == board[index].feature && board[new_unit].structure_group == 0) {
      traverse_structure(group, new_unit, board);
    } else if (board[new_unit].feature == ANY && board[new_unit].structure_group != board[index].structure_group) {
      board[new_unit].feature = board[index].feature;
      traverse_structure(group, new_unit, board);
      board[new_unit].feature = ANY;
    }
  }
}

void refresh_structure_groups(BoardUnit* board) {
  for (int i = 0; i < BOARD_UNITS; i++) board[i].structure_group = 0;

  int structure_group = 1;
  for (int i = 0; i < BOARD_UNITS; i++) {
    if (
      board[i].structure_group == 0
      && board[i].feature != EMPTY
      && board[i].feature != SEPARATOR
      && board[i].feature != 'F'
    ) {
      traverse_structure(structure_group, i, board);
      structure_group += 1;
    }
  }
}

int translate_coordinate(int center_index) {
  return (2 * (center_index / BOARD_WIDTH) + 1) *
         (2 * BOARD_WIDTH + 1) +
         (2 * (center_index % BOARD_WIDTH) + 1);
}

int evaluate_structure(int index, BoardUnit* board) {
  int value = 0;

  char feature = board[index].feature;
  int structure_group = board[index].structure_group;

  for (int i = 0; i < BOARD_WIDTH; i++) {
    for (int j = 0; j < BOARD_WIDTH; j++) {
      int index = translate_coordinate(i * BOARD_WIDTH + j);
      if (board[index].feature != EMPTY) { // Empty tiles doesn't count
        for (int k = 0; k < 4; k++) {
          if (board[index + NEIGHBOR_INCREMENTS[k]].structure_group == structure_group) {
            value++;
            break;
          }
        }
      }
    }
  }

  return value;
}

void refresh_meeple_map(BoardUnit* board, int* meeple_map) {
  for (int i = 0; i < MAX_STRUCTURES * PLAYERS; i++) meeple_map[i] = 0;

  for (int i = 0; i < BOARD_UNITS; i++) {
    if (board[i].meeple) {
      meeple_map[board[i].structure_group * PLAYERS + (board[i].meeple - 1)]++;
    }
  }
}

int is_allowed_meeple(int meeple, int index, BoardUnit* board, int* meeple_map) {
  if (board[index].meeple
    || board[index].feature == 'F'
    || board[index].feature == ANY
    || board[index].feature == SEPARATOR
  ) return 0;

  int dominator = get_structure_dominator(board[index].structure_group, meeple_map);
  return dominator == meeple || dominator == 0;
}

int get_structure_dominator(int structure_group, int* meeple_map) {
  int dominator = 0;
  int dominator_meeples = 0;

  for (int player = 0; player < PLAYERS; player++) {
    int meeples = meeple_map[structure_group * PLAYERS + player];
    if (meeples > dominator_meeples) {
      dominator_meeples = meeples;
      dominator = player + 1;
    }
  }
  return dominator;
}