A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 380 lines 11 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (c) 2006 Alexander Levin 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21 22/* 23 * Reversi. Code is heavily based on othello code by Claudio Clemens which is 24 * copyright (c) 2003-2006 Claudio Clemens <asturio at gmx dot net> and is 25 * released under the GNU General Public License as published by the Free 26 * Software Foundation; either version 2, or (at your option) any later version. 27 */ 28 29#include <stddef.h> 30#include "reversi-game.h" 31 32/* 33 * Constants for directions. The values are chosen so that 34 * they can be bit combined. 35 */ 36#define DIR_UP 1 /* UP */ 37#define DIR_DO 2 /* DOWN */ 38#define DIR_LE 4 /* LEFT */ 39#define DIR_RI 8 /* RIGHT */ 40#define DIR_UL 16 /* UP LEFT */ 41#define DIR_UR 32 /* UP RIGHT */ 42#define DIR_DL 64 /* DOWN LEFT */ 43#define DIR_DR 128 /* DOWN RIGHT */ 44 45/* Array of directions for easy iteration through all of them */ 46static int DIRECTIONS[] = 47 {DIR_UP, DIR_DO, DIR_LE, DIR_RI, DIR_UL, DIR_UR, DIR_DL, DIR_DR}; 48#define NUM_OF_DIRECTIONS 8 49 50 51/* Initializes a reversi game */ 52void reversi_init_game(reversi_board_t *game) { 53 int r, c; 54 for (r = 0; r < BOARD_SIZE; r++) { 55 for (c = 0; c < BOARD_SIZE; c++) { 56 game->board[r][c] = FREE; 57 } 58 } 59 game->board[3][3] = WHITE; 60 game->board[4][4] = WHITE; 61 game->board[3][4] = BLACK; 62 game->board[4][3] = BLACK; 63 64 /* Invalidate the history */ 65 c = sizeof(game->history) / sizeof(game->history[0]); 66 for (r = 0; r < c; r++) { 67 game->history[r] = MOVE_INVALID; 68 } 69} 70 71 72/* Returns the 'flipped' color, e.g. WHITE for BLACK and vice versa */ 73int reversi_flipped_color(const int color) { 74 switch (color) { 75 case WHITE: 76 return BLACK; 77 78 case BLACK: 79 return WHITE; 80 81 default: 82 return FREE; 83 } 84} 85 86 87/* Counts and returns the number of occupied cells on the board. 88 * If white_count and/or black_count is not null, the number of 89 * white/black stones is placed there. */ 90int reversi_count_occupied_cells(const reversi_board_t *game, 91 int *white_count, int *black_count) { 92 int w_cnt, b_cnt, r, c; 93 w_cnt = b_cnt = 0; 94 for (r = 0; r < BOARD_SIZE; r++) { 95 for (c = 0; c < BOARD_SIZE; c++) { 96 if (game->board[r][c] == WHITE) { 97 w_cnt++; 98 } else if (game->board[r][c] == BLACK) { 99 b_cnt++; 100 } 101 } 102 } 103 if (white_count != NULL) { 104 *white_count = w_cnt; 105 } 106 if (black_count != NULL) { 107 *black_count = b_cnt; 108 } 109 return w_cnt + b_cnt; 110} 111 112 113/* Returns the number of free cells on the board */ 114static int reversi_count_free_cells(const reversi_board_t *game) { 115 int cnt; 116 cnt = reversi_count_occupied_cells(game, NULL, NULL); 117 return BOARD_SIZE*BOARD_SIZE - cnt; 118} 119 120 121/* Checks whether the game is finished. That means that nobody 122 * can make a move. Note that the implementation is not correct 123 * as a game may be finished even if there are free cells 124 */ 125bool reversi_game_is_finished(const reversi_board_t *game, int player) { 126 return (reversi_count_free_cells(game) == 0) 127 || (reversi_count_passes(game,player) == 2); 128} 129 130 131/* Returns the total number of moves made so far */ 132int reversi_count_moves(const reversi_board_t *game) { 133 int cnt; 134 cnt = reversi_count_occupied_cells(game, NULL, NULL); 135 return cnt - INIT_STONES; 136} 137 138 139/* Returns the number of moves made by the specified 140 * player (WHITE or BLACK) so far 141 */ 142static int reversi_count_player_moves(const reversi_board_t *game, 143 const int player) { 144 int moves, cnt, i; 145 moves = reversi_count_moves(game); 146 cnt = 0; 147 for (i = 0; i < moves; i++) { 148 if (MOVE_PLAYER(game->history[i]) == player) { 149 cnt++; 150 } 151 } 152 return cnt; 153} 154 155/* Returns the number of moves available for the specified player */ 156int reversi_count_player_available_moves(const reversi_board_t *game, 157 const int player) { 158 int cnt = 0, row, col; 159 for(row=0;row<BOARD_SIZE;row++) { 160 for(col=0;col<BOARD_SIZE;col++) { 161 if(reversi_is_valid_move(game, row, col, player)) cnt++; 162 } 163 } 164 return cnt; 165} 166 167/* Returns the number of players who HAVE to pass (2 == game is stuck) */ 168int reversi_count_passes(const reversi_board_t *game, const int player) { 169 if(reversi_count_player_available_moves(game,player)==0) { 170 if(reversi_count_player_available_moves(game, 171 reversi_flipped_color(player))==0) { 172 return 2; 173 } 174 return 1; 175 } 176 return 0; 177} 178 179/* Returns the number of moves made by WHITE so far */ 180int reversi_count_white_moves(const reversi_board_t *game) { 181 return reversi_count_player_moves(game, WHITE); 182} 183 184 185/* Returns the number of moves made by BLACK so far */ 186int reversi_count_black_moves(const reversi_board_t *game) { 187 return reversi_count_player_moves(game, BLACK); 188} 189 190 191/* Checks whether the specified position is on the board 192 * (and not beyond) 193 */ 194static bool reversi_is_position_on_board(const int row, const int col) { 195 return (row >= 0) && (row < BOARD_SIZE) && 196 (col >= 0) && (col < BOARD_SIZE); 197} 198 199 200/* Returns the delta for row to move in the specified direction */ 201static int reversi_row_delta(const int direction) { 202 switch (direction) { 203 case DIR_UP: 204 case DIR_UL: 205 case DIR_UR: 206 return -1; 207 208 case DIR_DO: 209 case DIR_DL: 210 case DIR_DR: 211 return 1; 212 213 default: 214 return 0; 215 } 216} 217 218 219/* Returns the delta for column to move in the specified direction */ 220static int reversi_column_delta(const int direction) { 221 switch (direction) { 222 case DIR_LE: 223 case DIR_UL: 224 case DIR_DL: 225 return -1; 226 227 case DIR_RI: 228 case DIR_UR: 229 case DIR_DR: 230 return 1; 231 232 default: 233 return 0; 234 } 235} 236 237 238/* Checks if some stones would be captured in the specified direction 239 * if a stone were placed in the specified cell by the specified player. 240 * 241 * Returns 0 if no stones would be captured or 'direction' otherwise 242 */ 243static int reversi_is_valid_direction(const reversi_board_t *game, 244 const int row, const int col, const int player, const int direction) { 245 int row_delta, col_delta, r, c; 246 int other_color; 247 int flip_cnt; /* Number of stones that would be flipped */ 248 249 row_delta = reversi_row_delta(direction); 250 col_delta = reversi_column_delta(direction); 251 other_color = reversi_flipped_color(player); 252 253 r = row + row_delta; 254 c = col + col_delta; 255 256 flip_cnt = 0; 257 while (reversi_is_position_on_board(r, c) && 258 (game->board[r][c] == other_color)) { 259 r += row_delta; 260 c += col_delta; 261 flip_cnt++; 262 } 263 264 if ((flip_cnt > 0) && reversi_is_position_on_board(r, c) && 265 (game->board[r][c] == player)) { 266 return direction; 267 } else { 268 return 0; 269 } 270} 271 272 273/* Checks whether the move at the specified position would be valid. 274 * Params: 275 * - game: current state of the game 276 * - row: 0-based row number of the move in question 277 * - col: 0-based column number of the move in question 278 * - player: who is about to make the move (WHITE/BLACK) 279 * 280 * Checks if the place is empty, the coordinates are legal, 281 * and some stones can be captured. 282 * 283 * Returns 0 if the move is not valid or, otherwise, the or'd 284 * directions in which stones would be captured. 285 */ 286int reversi_is_valid_move(const reversi_board_t *game, 287 const int row, const int col, const int player) { 288 int dirs, i; 289 dirs = 0; 290 291 /* Check if coordinates are legal */ 292 if (!reversi_is_position_on_board(row, col)) { 293 return dirs; 294 } 295 296 /* Check if the place is free */ 297 if (game->board[row][col] != FREE) { 298 return dirs; 299 } 300 301 /* Check the directions of capture */ 302 for (i = 0; i < NUM_OF_DIRECTIONS; i++) { 303 dirs |= reversi_is_valid_direction(game, row, col, player, DIRECTIONS[i]); 304 } 305 306 return dirs; 307} 308 309 310/* Flips the stones in the specified direction after the specified 311 * player has placed a stone in the specified cell. The move is 312 * assumed to be valid. 313 * 314 * Returns the number of flipped stones in that direction 315 */ 316static int reversi_flip_stones(reversi_board_t *game, 317 const int row, const int col, const int player, const int direction) { 318 int row_delta, col_delta, r, c; 319 int other_color; 320 int flip_cnt; /* Number of stones flipped */ 321 322 row_delta = reversi_row_delta(direction); 323 col_delta = reversi_column_delta(direction); 324 other_color = reversi_flipped_color(player); 325 326 r = row + row_delta; 327 c = col + col_delta; 328 329 flip_cnt = 0; 330 while (reversi_is_position_on_board(r, c) && 331 (game->board[r][c] == other_color)) { 332 game->board[r][c] = player; 333 r += row_delta; 334 c += col_delta; 335 flip_cnt++; 336 } 337 338 return flip_cnt; 339} 340 341 342/* Tries to make a move (place a stone) at the specified position. 343 * If the move is valid the board is changed. Otherwise nothing happens. 344 * 345 * Params: 346 * - game: current state of the game 347 * - row: 0-based row number of the move to make 348 * - col: 0-based column number of the move to make 349 * - player: who makes the move (WHITE/BLACK) 350 * 351 * Returns the number of flipped (captured) stones (>0) iff the move 352 * was valid or 0 if the move was not valid. Note that in the case of 353 * a valid move, the stone itself is not counted. 354 */ 355int reversi_make_move(reversi_board_t *game, 356 const int row, const int col, const int player) { 357 int dirs, cnt, i; 358 359 dirs = reversi_is_valid_move(game, row, col, player); 360 if (dirs == 0) { 361 return 0; 362 } 363 364 /* Place the stone into the cell */ 365 game->board[row][col] = player; 366 367 /* Capture stones in all possible directions */ 368 cnt = 0; 369 for (i = 0; i < NUM_OF_DIRECTIONS; i++) { 370 if (dirs & DIRECTIONS[i]) { 371 cnt += reversi_flip_stones(game, row, col, player, DIRECTIONS[i]); 372 } 373 } 374 375 /* Remember the move */ 376 i = reversi_count_moves(game); 377 game->history[i-1] = MAKE_MOVE(row, col, player); 378 379 return cnt; 380}