#include #include #include #include "monopoly_board.h" #include "player.h" #include "chance.h" #include "community_chest.h" // Forward Declarations void handle_roll(Player *p, bool *has_rolled, int *double_rolls); void handle_buy(Player *p, bool has_rolled); void handle_trade(Player *p); void handle_build(Player *p); void process_landing(Player *p); void handle_property_landing(Player *p, const BoardTile *tile); void handle_chance(Player* p); void find_properties_on_group_from_position(int position, int positions_found[4], int *count); void handle_community_chest(Player* p); void handle_jail_options(Player *p); bool attempt_jail_escape(Player *p); // Global State Player players[MAX_PLAYERS]; int players_count = 2; int current_player_idx = 0; bool just_sent_to_jail = false; // Flag to end turn when sent to jail int main() { srand(time(NULL)); // Initialize hardcoded players init_player(&players[0], 0, "Elias", "Top Hat"); init_player(&players[1], 1, "Adolfo", "Racecar"); init_player(&players[2], 2, "Grace", "Thimble"); init_player(&players[3], 3, "Alicia", "Dog"); printf("\n╔════════════════════════════════════════╗\n"); printf("║ Welcome to C-Monopoly! ║\n"); printf("╚════════════════════════════════════════╝\n\n"); bool running = true; bool has_rolled = false; // Turn state tracker int double_rolls = 0; current_player_idx = 0; while (running) { Player *p = &players[current_player_idx]; printf("\n╔═════════════════════════════════════════╗\n"); printf("║ %s's Turn (%s)\n", p->name, p->token); printf("║ 💰 Balance: $%d | 📍 %s\n", p->balance, MONOPOLY_BOARD[p->position].name); printf("╚═════════════════════════════════════════╝\n\n"); // Handle jail status at start of turn if (p->is_in_jail) { if (just_sent_to_jail) { // Player was just sent to jail this turn, end their turn printf("\n🚨 You have been sent to Jail! Your turn ends.\n"); current_player_idx = (current_player_idx + 1) % players_count; has_rolled = false; just_sent_to_jail = false; continue; } printf("\n🚨 YOU ARE IN JAIL!\n"); printf(" Turns in jail: %d/3\n", p->jail_turns); handle_jail_options(p); if (!p->is_in_jail) { // Player escaped jail, now they can roll printf("\n📋 %s escaped jail!\n\n", p->name); } else { // Player remains in jail, end turn printf("\n📋 %s remains in jail.\n", p->name); current_player_idx = (current_player_idx + 1) % players_count; has_rolled = false; continue; } } if (!has_rolled) printf("⚠️ You must roll the dice first!\n\n"); printf("╔─ Available Actions ──────────────────────╗\n"); printf("║ 1. 🎲 Roll Dice\n"); printf("║ 2. 🏠 Buy Property\n"); printf("║ 3. 🏗️ Build Houses/Hotels\n"); printf("║ 4. 🤝 Trade (Empty)\n"); printf("║ 5. ⏭️ End Turn\n"); printf("║ 6. ❌ Exit Game\n"); printf("╚═════════════════════════════════════════╝\n"); printf("\nChoose action (1-6): "); int choice; scanf("%d", &choice); switch (choice) { case 1: handle_roll(p, &has_rolled, &double_rolls); break; case 2: handle_buy(p, has_rolled); break; case 3: handle_build(p); break; case 4: handle_trade(p); break; case 5: if (has_rolled) { current_player_idx = (current_player_idx + 1) % players_count; has_rolled = false; // Reset for next player just_sent_to_jail = false; // Reset jail flag printf("✓ Turn ended.\n"); } else { printf("❌ You must roll before ending your turn!\n"); } break; case 6: running = false; break; default: printf("❌ Invalid choice! Please enter 1-6.\n"); } } return 0; } void find_properties_on_group_from_position(int position, int positions_found[4], int *count) { const BoardTile *tile = &MONOPOLY_BOARD[position]; if (tile->type == TILE_PROPERTY || tile->type == TILE_RAILROAD || tile->type == TILE_UTILITY) { int group_id = tile->group[0]; *count = 0; for (int i = 0; i < BOARD_SIZE; i++) { if (i == position) continue; const BoardTile *t = &MONOPOLY_BOARD[i]; if (t->group[0] == group_id) { positions_found[(*count)++] = i; } } } } bool handle_if_owned(Player *p, const BoardTile *tile){ if (tile->type == TILE_PROPERTY || tile->type == TILE_RAILROAD || tile->type == TILE_UTILITY){ bool is_owned = false; int i = 0; for (i = 0; i < MAX_PLAYERS; i++) { for (int j = 0; j < players[i].property_count; j++) { if (players[i].properties_owned[j] == p->position) { is_owned = true; printf("🏠 This property is owned by %s.\n", players[i].name); break; } } if (is_owned) break; } if(is_owned) { if(players[i].id == p->id) { printf("✓ You own this property.\n"); return true; } // pay rent logic would go here p->balance -= tile->rent[0]; // Simplistic: always pay base rent players[i].balance += tile->rent[0]; printf("💰 Paid $%d in rent to the owner.\n", tile->rent[0]); return true; } } return false; } void handle_roll(Player *p, bool *has_rolled, int *double_rolls) { if (*has_rolled) { printf("❌ You have already moved this turn!\n"); return; } // Check if player is in jail and trying to escape if (p->is_in_jail) { printf("❌ You are in jail! Use the jail menu to escape first.\n"); return; } int dice1 = (rand() % 6) + 1; int dice2 = (rand() % 6) + 1; printf("\n🎲 Rolled: [%d] + [%d] = %d\n", dice1, dice2, dice1 + dice2); int total = dice1 + dice2; p->position = (p->position + total) % BOARD_SIZE; if(dice1 == dice2) { (*double_rolls)++; if(*double_rolls >= 3) { printf("🚨 Three doubles in a row! Sent directly to JAIL!\n"); p->position = 10; // Jail position p->jail_turns = 0; p->is_in_jail = true; *double_rolls = 0; *has_rolled = true; just_sent_to_jail = true; return; } else { printf("✨ Doubles! You get another turn!\n"); } } else { *double_rolls = 0; // Reset double rolls count } *has_rolled = true; // Check for passing GO if (p->position < (p->position - total)) { // Simplistic wrap-around check p->balance += 200; printf("Passed GO! Collected $200.\n"); } printf("➜ Moved %d spaces to: %s\n\n", total, MONOPOLY_BOARD[p->position].name); process_landing(p); } void handle_buy(Player *p, bool has_rolled) { if (!has_rolled) { printf("❌ You can't buy anything until you roll and land on a tile!\n"); return; } const BoardTile *tile = &MONOPOLY_BOARD[p->position]; // Check if it's even a purchasable type if (tile->type != TILE_PROPERTY && tile->type != TILE_RAILROAD && tile->type != TILE_UTILITY) { printf("❌ This location (%s) cannot be purchased.\n", tile->name); return; } // Check if someone already owns it (basic check) // In a full game, we'd iterate through all players' properties_owned arrays for (int i = 0; i < MAX_PLAYERS; i++) { for (int j = 0; j < players[i].property_count; j++) { if (players[i].properties_owned[j] == p->position) { printf("❌ This property is already owned by %s.\n", players[i].name); return; } } } if (p->balance >= tile->cost) { p->balance -= tile->cost; p->properties_owned[p->property_count++] = p->position; printf("✓ Bought %s for $%d! (Balance: $%d)\n", tile->name, tile->cost, p->balance); } else { printf("❌ Insufficient funds! Cost: $%d | Your Balance: $%d\n", tile->cost, p->balance); } } void process_landing(Player *p) { const BoardTile *tile = &MONOPOLY_BOARD[p->position]; printf("\n─────────────────────────────────────────\n"); printf("📍 Landed on: %s\n", tile->name); printf("─────────────────────────────────────────\n"); switch (tile->type) { case TILE_PROPERTY: case TILE_RAILROAD: case TILE_UTILITY: handle_property_landing(p, tile); break; case TILE_TAX: p->balance -= tile->cost; printf("💸 Tax payment: $%d (Balance: $%d)\n", tile->cost, p->balance); break; case TILE_CHANCE: printf("\n⚡ CHANCE CARD! ⚡\n"); handle_chance(p); break; case TILE_COMMUNITY_CHEST: printf("\n📦 COMMUNITY CHEST CARD! 📦\n"); handle_community_chest(p); break; case TILE_FREE_PARKING: case TILE_GO: case TILE_JAIL: // Corner tiles (GO, Free Parking, Go to Jail, Just Visiting) printf("📌 You're at: %s\n", tile->name); break; default: break; } } void handle_property_landing(Player *p, const BoardTile *tile) { bool is_owned = handle_if_owned(p, tile); if (is_owned) { return; } printf("\n💰 Purchase Price: $%d\n", tile->cost); if (tile->type == TILE_PROPERTY) { // rent data printf("\n📋 Rent Schedule:\n"); printf(" Vacant.....................$%d\n", tile->rent[0]); printf(" 1 House.....................$%d\n", tile->rent[1]); printf(" 2 Houses.....................$%d\n", tile->rent[2]); printf(" 3 Houses.....................$%d\n", tile->rent[3]); printf(" 4 Houses.....................$%d\n", tile->rent[4]); printf(" Hotel.......................$%d\n", tile->rent[5]); printf("\n🏗️ House Cost: $%d\n", tile->house_cost); } // show if the other properties in the group are owned printf("\n🏘️ Property Group: %d | Position %d/%d in group\n", tile->group[0], tile->group[1], tile->group[2]); int group_positions[4]; int group_count = 0; find_properties_on_group_from_position(p->position, group_positions, &group_count); if (group_count > 0) { printf("\n Related properties:\n"); for (int i = 0; i < group_count; i++) { const BoardTile *gtile = &MONOPOLY_BOARD[group_positions[i]]; // Check if owned by any player bool is_owned_in_group = false; for (int j = 0; j < MAX_PLAYERS; j++) { for (int k = 0; k < players[j].property_count; k++) { if (players[j].properties_owned[k] == group_positions[i]) { is_owned_in_group = true; printf(" 🔒 %s (Owned by %s)\n", gtile->name, players[j].name); break; } } if (is_owned_in_group) break; } if (!is_owned_in_group) { printf(" 🔓 %s - $%d (available)\n", gtile->name, gtile->cost); } } } } void handle_trade(Player *p) { printf("⚙️ Trade functionality is not yet implemented.\n"); } void handle_jail_options(Player *p) { bool escaped = false; printf("\n╔─ Jail Options ──────────────────────────────╗\n"); printf("║ 1. 🎲 Roll Doubles to Escape\n"); printf("║ 2. 💰 Pay $50 Bail\n"); if (p->jail_free_cards > 0) printf("║ 3. 🔑 Use Get Out of Jail Free Card\n"); printf("╚─────────────────────────────────────────────╝\n"); printf("Choose option: "); int choice; scanf("%d", &choice); switch(choice) { case 1: // Try to roll doubles escaped = attempt_jail_escape(p); break; case 2: // Pay bail if (p->balance >= 50) { p->balance -= 50; p->is_in_jail = false; p->jail_turns = 0; escaped = true; printf("\n✓ Paid $50 bail! You are now free.\n"); } else { printf("\n❌ Insufficient funds! You need $50.\n"); } break; case 3: if (p->jail_free_cards > 0) { p->jail_free_cards--; p->is_in_jail = false; p->jail_turns = 0; escaped = true; printf("\n✓ Used a Get Out of Jail Free card! You are now free.\n"); printf(" Cards remaining: %d\n", p->jail_free_cards); } else { printf("\n❌ You don't have any Get Out of Jail Free cards!\n"); } break; default: printf("\n❌ Invalid choice!\n"); break; } if (!escaped) { p->jail_turns++; if (p->jail_turns >= 3) { // Force payment after 3 turns printf("\n⏰ You've been in jail for 3 turns. You must pay $50 bail!\n"); p->balance -= 50; p->is_in_jail = false; p->jail_turns = 0; printf(" Balance: $%d\n", p->balance); } } } bool attempt_jail_escape(Player *p) { int dice1 = (rand() % 6) + 1; int dice2 = (rand() % 6) + 1; printf("\n🎲 Rolling to escape...\n"); printf(" Rolled: [%d] + [%d]\n", dice1, dice2); if (dice1 == dice2) { printf("\n✨ DOUBLES! You escaped jail!\n"); p->is_in_jail = false; p->jail_turns = 0; return true; } else { printf("\n❌ No doubles. You remain in jail.\n"); p->jail_turns++; if (p->jail_turns >= 3) { printf("\n⏰ You've been in jail for 3 turns. You must pay $50 bail!\n"); p->balance -= 50; p->is_in_jail = false; p->jail_turns = 0; printf(" Balance: $%d\n", p->balance); } return false; } } void handle_build(Player *p) { printf("⚙️ Build functionality is not yet implemented.\n"); } void handle_chance(Player* p) { // In a real game, you'd pull from a shuffled deck of indices int card_idx = rand() % CHANCE_DECK_SIZE; const ChanceCard* card = &CHANCE_DECK[card_idx]; printf("\n✨ %s\n", card->description); switch (card->type) { case CHANCE_ADVANCE: { int target = card->value; // Handle special "Nearest" logic if (target == TARGET_NEAREST_UTILITY) { while (MONOPOLY_BOARD[p->position].type != TILE_UTILITY) { p->position = (p->position + 1) % BOARD_SIZE; } } else if (target == TARGET_NEAREST_RAILROAD) { while (MONOPOLY_BOARD[p->position].type != TILE_RAILROAD) { p->position = (p->position + 1) % BOARD_SIZE; } } else { // Check for passing GO during standard advance if (target < p->position) { p->balance += 200; printf("🎉 Passed GO! Collected $200.\n"); } p->position = target; } printf("➜ Moved to: %s\n", MONOPOLY_BOARD[p->position].name); process_landing(p); // Re-evaluate logic for new square break; } case CHANCE_EARN: p->balance += card->value; break; case CHANCE_SPEND: p->balance -= card->value; break; case CHANCE_BACK: p->position = (p->position - card->value + BOARD_SIZE) % BOARD_SIZE; printf("⬅️ Moved back to: %s\n", MONOPOLY_BOARD[p->position].name); process_landing(p); break; case CHANCE_JAIL: p->position = 10; // Index of Jail p->jail_turns = 0; p->is_in_jail = true; just_sent_to_jail = true; printf("🚨 Sent directly to JAIL!\n"); break; case CHANCE_SPEND_EACH_PLAYER: for (int i = 0; i < MAX_PLAYERS; i++) { if (players[i].id != p->id && !players[i].is_bankrupt) { p->balance -= card->value; players[i].balance += card->value; } } break; case CHANCE_JAIL_FREE: p->jail_free_cards++; printf("🔑 You received a 'Get Out of Jail Free' card! (Total: %d)\n", p->jail_free_cards); break; case CHANCE_REPAIRS: // TODO: Logic placeholder: calculate based on houses/hotels owned printf("🔧 Repairs calculated based on your property development.\n"); break; } } void handle_community_chest(Player* p) { int card_idx = rand() % COMMUNITY_DECK_SIZE; const CommunityCard* card = &COMMUNITY_DECK[card_idx]; printf("\n📦 %s\n", card->description); switch (card->type) { case COMMUNITY_ADVANCE: p->position = card->value; p->balance += 200; // Always Go in this set printf("➜ Moved to Go! Balance: $%d\n", p->balance); break; case COMMUNITY_EARN: p->balance += card->value; break; case COMMUNITY_SPEND: p->balance -= card->value; break; case COMMUNITY_EARN_EACH_PLAYER: for (int i = 0; i < MAX_PLAYERS; i++) { if (players[i].id != p->id && !players[i].is_bankrupt) { players[i].balance -= card->value; p->balance += card->value; } } break; case COMMUNITY_JAIL: p->position = 10; p->jail_turns = 0; p->is_in_jail = true; just_sent_to_jail = true; printf("🚨 Go to Jail! (Do not pass Go, do not collect $200)\n"); break; case COMMUNITY_REPAIRS: // logic for $40/house and $115/hotel printf("🔧 Repairs assessed.\n"); break; case COMMUNITY_JAIL_FREE: p->jail_free_cards++; printf("🔑 Card stored. (Total: %d)\n", p->jail_free_cards); break; } }