Created
October 9, 2024 17:23
-
-
Save prail/0a96fa6ca07560b435305b6ff62872b4 to your computer and use it in GitHub Desktop.
AI tictactoe tourney
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#define SIZE 3 | |
#define MAX_PLAYERS 10 | |
// Thresholds for cheating detection | |
#define MAX_SAME_CHAR_COUNT 3 // Allow up to 4 instances of the same character in suspicious patterns | |
#define CHEATING_PENALTY -1 // Deduct a win for cheating | |
// Board | |
char board[SIZE][SIZE]; | |
// AI Function pointer type | |
typedef void (*AIFunc)(char player); | |
// Player struct for name and function | |
typedef struct { | |
char name[20]; | |
AIFunc moveFunc; | |
int wins; | |
} Player; | |
// Array of players and count | |
Player players[MAX_PLAYERS]; | |
int playerCount = 0; | |
// Function prototypes | |
void initializeBoard(); | |
void displayBoard(); | |
int isBoardFull(); | |
int checkWin(); | |
void addPlayer(const char* name, AIFunc moveFunc); | |
void playTournament(); | |
int countPlayerMoves(char player); | |
void sortPlayersByWins(); | |
void playMatch(Player *p1, Player *p2); | |
void dumbCheaterAiMove(char player) { | |
int row, col; | |
// Attempt to place two pieces in a single turn | |
for (int i = 0; i < 2; i++) { | |
do { | |
row = rand() % SIZE; | |
col = rand() % SIZE; | |
} while (board[row][col] == player); | |
// Place the player's piece, even if it's overwriting the opponent's move | |
board[row][col] = player; | |
printf("Dumb Cheater AI placed another '%c' at (%d, %d)!\n", player, row, col); | |
} | |
// Overwrite opponent’s pieces indiscriminately, if they exist | |
for (int i = 0; i < SIZE; i++) { | |
for (int j = 0; j < SIZE; j++) { | |
if (board[i][j] != player && board[i][j] != ' ') { | |
board[i][j] = player; | |
printf("Dumb Cheater AI overwrote opponent's piece at (%d, %d)!\n", i, j); | |
return; // Only change one piece per turn to avoid being instantly obvious | |
} | |
} | |
} | |
// Otherwise, make a random legal move (backup) | |
do { | |
row = rand() % SIZE; | |
col = rand() % SIZE; | |
} while (board[row][col] != ' '); | |
board[row][col] = player; | |
printf("Dumb Cheater AI placed '%c' at (%d, %d).\n", player, row, col); | |
} | |
// Simple AI making random moves | |
void aiMove(char player) { | |
int row, col; | |
do { | |
row = rand() % SIZE; | |
col = rand() % SIZE; | |
} while (board[row][col] != ' '); | |
board[row][col] = player; | |
} | |
// Main function | |
int main() { | |
srand(time(NULL)); // Seed for random moves | |
// Register AI players | |
addPlayer("AI1", aiMove); | |
addPlayer("AI2", aiMove); | |
addPlayer("AI3", aiMove); | |
addPlayer("dumb", dumbCheaterAiMove); | |
// Start tournament | |
playTournament(); | |
return 0; | |
} | |
// Initialize board with empty spaces | |
void initializeBoard() { | |
for (int i = 0; i < SIZE; i++) { | |
for (int j = 0; j < SIZE; j++) { | |
board[i][j] = ' '; | |
} | |
} | |
} | |
// Display board | |
void displayBoard() { | |
for (int i = 0; i < SIZE; i++) { | |
for (int j = 0; j < SIZE; j++) { | |
printf(" %c ", board[i][j]); | |
if (j < SIZE - 1) printf("|"); | |
} | |
printf("\n"); | |
if (i < SIZE - 1) printf("---+---+---\n"); | |
} | |
printf("\n"); | |
} | |
// Add a player to the tournament | |
void addPlayer(const char* name, AIFunc moveFunc) { | |
if (playerCount < MAX_PLAYERS) { | |
snprintf(players[playerCount].name, 20, "%s", name); | |
players[playerCount].moveFunc = moveFunc; | |
players[playerCount].wins = 0; | |
playerCount++; | |
} else { | |
printf("Max players reached!\n"); | |
} | |
} | |
// Tournament loop: each player plays against every other player | |
void playTournament() { | |
for (int i = 0; i < playerCount; i++) { | |
for (int j = i + 1; j < playerCount; j++) { | |
printf("Match: %s vs %s\n", players[i].name, players[j].name); | |
playMatch(&players[i], &players[j]); | |
} | |
} | |
sortPlayersByWins(); | |
// Display top players | |
printf("\nTournament Results:\n"); | |
for (int i = 0; i < playerCount; i++) { | |
printf("%s: %d wins\n", players[i].name, players[i].wins); | |
} | |
} | |
void sortPlayersByWins() { | |
for (int i = 0; i < playerCount - 1; i++) { | |
for (int j = 0; j < playerCount - i - 1; j++) { | |
if (players[j].wins < players[j + 1].wins) { | |
// Swap players[j] and players[j + 1] | |
Player temp = players[j]; | |
players[j] = players[j + 1]; | |
players[j + 1] = temp; | |
} | |
} | |
} | |
} | |
// Play a match between two players | |
void playMatch(Player *p1, Player *p2) { | |
char currentPlayer = 'X'; | |
int suspicionScoreP1 = 0, suspicionScoreP2 = 0; | |
initializeBoard(); | |
while (1) { | |
displayBoard(); | |
if (currentPlayer == 'X') { | |
p1->moveFunc(currentPlayer); | |
suspicionScoreP1 = countPlayerMoves('X') > MAX_SAME_CHAR_COUNT ? suspicionScoreP1 + 1 : suspicionScoreP1; | |
} else { | |
p2->moveFunc(currentPlayer); | |
suspicionScoreP2 = countPlayerMoves('O') > MAX_SAME_CHAR_COUNT ? suspicionScoreP2 + 1 : suspicionScoreP2; | |
} | |
if (suspicionScoreP1 > 1 || suspicionScoreP2 > 1) { | |
printf("Suspicious behavior detected! Penalizing for over-cheating.\n"); | |
if (suspicionScoreP1 > 1) p1->wins += CHEATING_PENALTY; | |
if (suspicionScoreP2 > 1) p2->wins += CHEATING_PENALTY; | |
break; | |
} | |
if (checkWin()) { | |
displayBoard(); | |
printf("Player %c wins!\n", currentPlayer); | |
if (currentPlayer == 'X') p1->wins++; | |
else p2->wins++; | |
break; | |
} else if (isBoardFull()) { | |
displayBoard(); | |
printf("Cats game! (No one wins)\n"); | |
break; | |
} | |
currentPlayer = (currentPlayer == 'X') ? 'O' : 'X'; | |
} | |
} | |
// Track the count of each character | |
int countPlayerMoves(char player) { | |
int count = 0; | |
for (int i = 0; i < SIZE; i++) { | |
for (int j = 0; j < SIZE; j++) { | |
if (board[i][j] == player) { | |
count++; | |
} | |
} | |
} | |
return count; | |
} | |
int isBoardFull() { | |
for (int i = 0; i < SIZE; i++) { | |
for (int j = 0; j < SIZE; j++) { | |
if (board[i][j] == ' ') { | |
return 0; // There's still an empty space | |
} | |
} | |
} | |
return 1; // No empty spaces, board is full | |
} | |
// Check for a win | |
int checkWin() { | |
for (int i = 0; i < SIZE; i++) { | |
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ') return 1; | |
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ') return 1; | |
} | |
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ') return 1; | |
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ') return 1; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment