Skip to content

Instantly share code, notes, and snippets.

@prail
Created October 9, 2024 17:23
Show Gist options
  • Save prail/0a96fa6ca07560b435305b6ff62872b4 to your computer and use it in GitHub Desktop.
Save prail/0a96fa6ca07560b435305b6ff62872b4 to your computer and use it in GitHub Desktop.
AI tictactoe tourney
#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