// // clobber2023.cc // C++ programma dat meerpersoons Clobber speelt // compileren: g++ -Wall -Wextra -O3 -o clobber clobber2023.cc // aanroep: ./clobber [hoogte] [breedte] [playouts] [seed] [spellen] // [MC-speler 0/1/.../42/66] [printen 0/1] [spelers] // MC-speler: bij 0: 0 speelt Monte Carlo en de rest random // bij 1: 1 speelt Monte Carlo en de rest random, etcetera // bij 42: iedereen speelt MC // bij 66: iedereen speelt random // voorbeeld: ./clobber 5 6 123 878 1 66 1 2 // speel op een 5x6 bord 1 potje, met 2 random // spelers, en print alles; randomseed 878 (123 wordt hier genegeerd) // voorbeeld: ./clobber 4 9 123 999 1000 2 0 5 // speel op een 4x9 bord 1000 potjes, met 5 spelers, waarvan speler 2 // Monte Carlo speelt met 123 playouts, en de rest random, en print // alleen de einduitslagen; random (via de tijd, alleen bij 999) // let op: de functie MCzet ( ) moet hiervoor werken! // Walter Kosters, 6 februari 2023; versie 2.4 // #include #include #include using namespace std; const int MAX = 20; class clobber { private: short bord[MAX][MAX]; // het spelbord int beurt; // nummer van de beurt short passen; // hoe vaak gepast in huidige "ronde"? int m, n; // hoogte en breedte van het bord, <= MAX int playouts; // aantal playouts bij Monte Carlo (MC) bool printen; // printen we de spelletjes? (wordt bij MC soms even uitgezet) int spelers; // aantal spelers, <= MAX public: clobber ( ); clobber (int m1, int n1, int pl1, bool pr1, int sp1); void init ( ); void print ( ); int aantalzetten ( ); void doezet (int k); short randomspel ( ); short MCspel (short specialespeler); void doenulzet ( ); void MCzet ( ); void slimmezet ( ); };//clobber //default constructor clobber::clobber ( ) { }//clobber::clobber //constructor clobber::clobber (int m1, int n1, int pl1, bool pr1, int sp1) { m = m1; n = n1; playouts = pl1; printen = pr1; spelers = sp1; init ( ); }//clobber::clobber //random beginstand opzetten; speler i heeft waarde i; //waarde "spelers" betekent leeg void clobber::init ( ) { int i, j; for ( i = 0; i < m; i++ ) for ( j = 0; j < n; j++ ) bord[i][j] = rand ( ) % spelers; beurt = 0; passen = 0; }//clobber::init //hoeveel zetten zijn er mogelijk vanuit de huidige positie? int clobber::aantalzetten ( ) { int teller = 0, i, j; for ( i = 0; i < m; i++ ) for ( j = 0; j < n; j++ ) if ( bord[i][j] == beurt % spelers ) { // die is aan de beurt if ( i > 0 && bord[i-1][j] != bord[i][j] && bord[i-1][j] != spelers ) teller++; if ( j > 0 && bord[i][j-1] != bord[i][j] && bord[i][j-1] != spelers ) teller++; if ( j < n-1 && bord[i][j+1] != bord[i][j] && bord[i][j+1] != spelers ) teller++; if ( i < m-1 && bord[i+1][j] != bord[i][j] && bord[i+1][j] != spelers ) teller++; }//if return teller; }//clobber::aantalzetten //doe k-de mogelijke zet //neem aan dat 0 <= k < aantalzetten ( ) void clobber::doezet (int k) { int teller = 0, i, j; passen = 0; for ( i = 0; i < m; i++ ) for ( j = 0; j < n; j++ ) if ( bord[i][j] == beurt % spelers ) { if ( i > 0 && bord[i-1][j] != bord[i][j] && bord[i-1][j] != spelers ) { if ( teller == k ) { bord[i][j] = spelers; // leeg bord[i-1][j] = beurt % spelers; beurt++; return; }//if teller++; }//if if ( j > 0 && bord[i][j-1] != bord[i][j] && bord[i][j-1] != spelers ) { if ( teller == k ) { bord[i][j] = spelers; // leeg bord[i][j-1] = beurt % spelers;; beurt++; return; }//if teller++; }//if if ( j < n-1 && bord[i][j+1] != bord[i][j] && bord[i][j+1] != spelers ) { if ( teller == k ) { bord[i][j] = spelers; // leeg bord[i][j+1] = beurt % spelers; beurt++; return; }//if teller++; }//if if ( i < m-1 && bord[i+1][j] != bord[i][j] && bord[i+1][j] != spelers ) { if ( teller == k ) { bord[i][j] = spelers; // leeg bord[i+1][j] = beurt % spelers; beurt++; return; }//if teller++; }//if }//if }//clobber::doezet //print spelbord void clobber::print ( ) { int i, j; cout << "Toestand " << beurt << endl << " "; for ( j = 0; j < n; j++ ) cout << " " << j % 10; cout << endl; for ( i = 0; i < m; i++ ) { cout << i << " "; for ( j = 0; j < n; j++ ) if ( bord[i][j] == spelers ) cout << " ."; else if ( bord[i][j] < 10 ) cout << " " << bord[i][j]; else cout << " " << bord[i][j]; cout << endl; }//for cout << "Speler " << beurt % spelers << " is aan de beurt" << endl << endl; }//clobber::clobber //passen void clobber::doenulzet ( ) { beurt++; passen++; }//clobber::doenulzet //speel random potje vanuit de huidige positie //return de winnaar short clobber::randomspel ( ) { int aantal = aantalzetten ( ); short speleraanzet = 1000; if ( printen ) print ( ); while ( passen < spelers ) { if ( aantal > 0 ) { speleraanzet = beurt % spelers; doezet (rand ( ) % aantal); }//if else doenulzet ( ); if ( printen ) print ( ); aantal = aantalzetten ( ); }//while return speleraanzet; }//clobber::randomspel //speel een potje vanuit de huidige positie, waarbij de specialespeler //Monte Carlo speelt en de rest random //als specialespeler gelijk is aan 42: allemaal MC //als specialespeler gelijk is aan 66: allemaal random //return de winnaar //TODO toevoegen nog een "slimme" specialespeler short clobber::MCspel (short specialespeler) { int aantal = aantalzetten ( ); short speleraanzet = 1000; bool oldprinten = printen; if ( printen ) print ( ); while ( passen < spelers ) { if ( aantal > 0 ) { speleraanzet = beurt % spelers; if ( speleraanzet == specialespeler || specialespeler == 42 ) { printen = false; MCzet ( ); printen = oldprinten; }//if else doezet (rand ( ) % aantal); }//if else doenulzet ( ); if ( printen ) print ( ); aantal = aantalzetten ( ); }//while return speleraanzet; }//clobber::MCspel //bepaal Monte Carlo zet void clobber::MCzet ( ) { //TODO cout << "Hier komt code voor een Monte Carlo zet" << endl; }//clobber::MCzet //bepaal slimme zet void clobber::slimmezet ( ) { //TODO cout << "Hier komt code voor een slimme zet" << endl; }//clobber::slimmezet int main (int argc, char* argv[ ]) { int gewonnen[MAX] = {0}; //voor de statistieken if ( argc != 9 ) { cout << "Aanroepen met: " << endl << argv[0] << " [hoogte] [breedte] [playouts] [seed] [spellen] " << "[MC-speler 0/1/.../spelers-1/42/66] [printen 0/1] [spelers]" << endl; return 1; }//if int m = atoi (argv[1]); int n = atoi (argv[2]); if ( m > MAX || n > MAX ) { cout << "Bord te groot!" << endl; return 1; }//if int playouts = atoi (argv[3]); int theseed = atoi (argv[4]); if ( theseed == 999 ) { srand (time (NULL)); }//if else { srand (atoi (argv[4])); }//else int spellen = atoi (argv[5]); short speler = atoi (argv[6]); short result; bool printen = ( argv[7][0] == '1' ); int spelers = atoi (argv[8]); if ( spelers < 2 || spelers > MAX ) { cout << "Te weinig of te veel spelers!" << endl; return 1; }//if clobber clob (m,n,playouts,printen,spelers); for ( int i = 0; i < spellen; i++ ) { clob.init ( ); result = clob.MCspel (speler); if ( result == 1000 ) cout << "REMISE (raar beginbord)" << endl; else gewonnen[result]++; }//for cout << "Einduitslag: ["; for ( int i = 0; i < spelers - 1; i++ ) cout << gewonnen[i] << ","; cout << gewonnen[spelers-1] << "] / " << spellen << " (totaal)" << endl; return 0; }//main