/** * Mancala - an african game of stones. * @author Pinkfish * @started Mon Dec 11 08:49:30 PST 2000 */ inherit "/obj/furnitures/misc/games/multiplayer_base"; inherit "/std/room/furniture/basic"; class co_ord { int x; int y; } private int* _board; private mapping _mancala; #define LOAD_TAG "mancala" #define SIDE_LENGTH 6 void create() { multiplayer_base::create(); basic::create(); } /* create() */ void setup() { set_short("mancala board"); add_adjective("mancala"); add_alias("mancala"); set_name("board"); set_long("A small rectangular board with 6 dips on each side and two " "bigger dips at each end. There are a bunch of small multi-" "coloured stones in the dips.\n"); add_player_id_type("green", 0); add_player_id_type("red", 0); set_minimum_needed(2); add_help_file("mancala"); reset_game(); } /* setup() */ /** * This method resets the board to the start position. */ void reset_game() { _board = allocate(12, (: 4 :)); _mancala = ([ "red" : 0, "green" : 0 ]); } /* reset_game() */ /** * This method is called to start the game. */ int start_game() { randomise_player_numbers(); if (!::start_game()) { return 0; } reset_game(); return 1; } /* start_game() */ /** * The board itself. * @return the board string */ string query_board_string() { string ret; string id; int i; ret = ""; foreach (id in query_player_ids()) { ret += sprintf("%-25s %s\n", query_player_cap_name(id) + " (" + capitalize(id) + ")", (is_game_started() && query_current_player() == id?"<-- Their turn":"")); } ret += " ------->\n"; ret += "%^RED%^+--+%^RESET%^ %^GREEN%^"; for (i = 0; i < SIDE_LENGTH; i++) { ret += "+--+ "; } ret += " +--+%^RESET%^\n"; ret += "%^RED%^| |%^RESET%^ %^GREEN%^"; for (i = 0; i < SIDE_LENGTH; i++) { ret += sprintf("|%2d| ", _board[i]); } ret += " | |%^RESET%^\n"; ret += "%^RED%^| | %^GREEN%^"; for (i = 0; i < SIDE_LENGTH; i++) { ret += "+--+ "; } ret += " | |%^RESET%^\n"; ret += sprintf("%%^RED%%^|%2d|%%^RESET%%^ ", _mancala["red"]); for (i = 0; i < SIDE_LENGTH; i++) { ret += " "; } ret += sprintf(" %%^GREEN%%^|%2d|%%^RESET%%^\n", _mancala["green"]); ret += "%^RED%^| | "; for (i = 0; i < SIDE_LENGTH; i++) { ret += "+--+ "; } ret += " %^GREEN%^| |%^RESET%^\n"; ret += "%^RED%^| | "; for (i = 1; i <= SIDE_LENGTH; i++) { ret += sprintf("|%2d| ", _board[2 * SIDE_LENGTH - i]); } ret += " %^GREEN%^| |%^RESET%^\n"; ret += "%^RED%^+--+ "; for (i = 0; i < SIDE_LENGTH; i++) { ret += "+--+ "; } ret += " %^GREEN%^+--+%^RESET%^\n"; ret += " <-------\n"; ret += " "; for (i = 0; i < SIDE_LENGTH; i++) { ret += sprintf(" %c ", i + 'A'); } ret += "\n"; if (query_winner()) { ret += "The last winner was " + query_winner() + ".\n"; } return ret; } /* query_board_string() */ string long() { return ::long() + query_board_string(); } /* long() */ /** * This method checks to see if there is a 4 in a row on the board somewhere. */ int check_winner(class co_ord pos) { return 0; } /* check_winner() */ /** * This method returns the location as a string. * @param loc the location to look at * @return the string version of it */ string query_location_string(int loc) { if (loc < SIDE_LENGTH) { return sprintf("green %c", loc + 'A'); } return sprintf("red %c", 2 * SIDE_LENGTH - loc + 'A' - 1); } /* query_location_string() */ /** * The bin on the opposite side. */ int query_opposite_side(int loc) { if (loc < SIDE_LENGTH) { return 2 * SIDE_LENGTH - loc - 1; } return SIDE_LENGTH - 1 - (loc % (SIDE_LENGTH)); } /* query_opposite_side() */ /** * This method checks to see if the game has ended, and ends the game * if it has. */ int check_end() { int empty; int i; // // If all of one side is empty, sweep the other side. // empty = 1; for (i = 0; i < SIDE_LENGTH; i++) { if (_board[i]) { empty = 0; } } if (empty) { for (i = 0; i < SIDE_LENGTH; i++) { _mancala["red"] += _board[i + SIDE_LENGTH]; _board[i + SIDE_LENGTH] = 0;; } } else { empty = 1; for (i = 0; i < SIDE_LENGTH; i++) { if (_board[i + SIDE_LENGTH]) { empty = 0; } } if (empty) { for (i = 0; i < SIDE_LENGTH; i++) { _mancala["green"] += _board[i]; _board[i] = 0; } } } if (empty) { if (_mancala["red"] > _mancala["green"]) { finish_game(query_player_cap_name("red")); } else if (_mancala["red"] < _mancala["green"]) { finish_game(query_player_cap_name("green")); } else { finish_game(query_player_cap_name("green") + " and " + query_player_cap_name("red")); } } return empty; } /* check_end() */ /** * This method makes a move and chooses the next piece for the other player. * @param pos the position to play the piece * @param next the next piece to choose */ int do_move(string pos_str) { int i; int pos; int num; int loc; int my_mancala; int my_cutoff; int my_cutoff_bot; int last_mancala; if (!is_game_started()) { add_failed_mess("The game has not started.\n"); return 0; } if (!is_current_player(this_player())) { add_failed_mess("It is not your go!\n"); return 0; } pos = lower_case(pos_str)[0] - 'a'; if (pos < 0 || pos >= SIDE_LENGTH || strlen(pos_str) > 1) { add_failed_mess("The next piece reference " + pos_str + " is not valid on $D.\n"); return 0; } if (query_current_player() == "red") { pos = SIDE_LENGTH * 2 - pos - 1; my_mancala = 0; my_cutoff = 12; my_cutoff_bot = 6; } else { my_mancala = SIDE_LENGTH; my_cutoff = 6; my_cutoff_bot = 0; } if (!_board[pos]) { add_failed_mess("You can only play from a bin that has stones in it.\n"); return 0; } num = _board[pos]; _board[pos] = 0; for (i = 1; i <= num; i++) { loc = (pos + i) % (2 * SIDE_LENGTH); if (!((pos + i) % SIDE_LENGTH) && loc == my_mancala) { // // See if we stick a stone in the mancala or not. // _mancala[query_current_player()]++; num--; last_mancala = 1; } if (i <= num) { _board[loc]++; last_mancala = 0; } } if (!last_mancala && _board[loc] == 1 && loc < my_cutoff && loc >= my_cutoff_bot) { // // We might do a capture! // i = query_opposite_side(loc); if (_board[i]) { add_succeeded_mess("$N capture$s " + query_num(_board[i]) + " pieces from " + query_location_string(i) + ".\n"); _mancala[query_current_player()] += _board[i] + 1; _board[i] = 0; _board[loc] = 0; } } if (check_end()) { add_succeeded_mess("$N end$s the game and " + query_winner() + " wins " "on $D.\n"); } else { add_succeeded_mess("$N start$s from " + query_location_string(pos) + " and goes to " + query_location_string(loc) + ".\n"); if (!last_mancala) { increment_current_player(); tell_current_player("%^BOLD%^Your turn!%^RESET%^\n" + query_board_string()); } else { tell_current_player("%^BOLD%^Your turn!%^RESET%^\n" + query_board_string()); } } return 1; } /* do_move() */ /** * This method starts a new game. */ int do_start() { if (!is_playing(this_player())) { add_failed_mess("You must be playing the game to start it.\n"); return 0; } if (!start_game()) { add_failed_mess("You need two people to play Quarto.\n"); return 0; } add_succeeded_mess("$N $V a game of $D.\n"); increment_current_player(); tell_current_player("%^BOLD%^Your turn!%^RESET%^\n" + query_board_string()); tell_all_players(query_player_cap_name(query_current_player()) + " goes first!\n", ({ query_current_player() })); return 1; } /* do_start() */ void init() { ::init(); add_command("move", "<string'position'> on <direct:object>", (: do_move($4[0]) :)); add_command("start", "[new] [game] on <direct:object>", (: do_start() :)); } /* init() */ /** @ignore yes */ mapping query_dynamic_auto_load() { mapping map; map = basic::query_dynamic_auto_load(); multiplayer_base::query_dynamic_auto_load(map); add_auto_load_value(map, LOAD_TAG, "board", _board); add_auto_load_value(map, LOAD_TAG, "mancala", _mancala); return map; } /* query_dynamic_arg() */ /** @ignore yes */ void init_dynamic_arg(mapping map, object player) { basic::init_dynamic_arg(map, player); multiplayer_base::init_dynamic_arg(map, player); _board = query_auto_load_value(map, LOAD_TAG, "board"); _mancala = query_auto_load_value(map, LOAD_TAG, "mancala"); } /* init_dynamic_arg() */