// vierGewinnt.cpp --- "Vier gewinnt" Spiel. #include #include #include #include using namespace std; // ------ Definiere Aufzaehltypen enum Farbe { SCHWARZ, ROT, GELB, BLAU, WEISS }; enum Spieler { NIEMAND, COMPUTER, MENSCH }; // ------ Definiere Konstanten const int undefiniert = -1; const int unendlich = 1000000000; const int fensterGroesse = 400; const int raster = fensterGroesse/9; const Farbe spielFarbe[3] = { SCHWARZ, ROT, GELB }; // ------ Globale Variablen Spieler spielFeld[7][6]; int hoehe[7], freieFelder; int einwurfSpalte, einwurfZeile, einwurfFarbe; int spielStaerke = 4, spielStaerkeWahl = 4; bool klappe = false; bool fertig; Spieler sieger; IfmWindow win(50, 50, fensterGroesse, fensterGroesse, "vier gewinnt"); // ------ Zeichenfunktionen void setzeFarbe(int farbe) { switch (farbe) { case SCHWARZ: win << black; break; case ROT: win << red; break; case GELB: win << yellow; break; case BLAU: win << blue; break; case WEISS: win << white; break; } } void zeichneRechteck(double links, double rechts, double unten, double oben) { win << FilledRectangle((int)(raster*(links+1)), (int)(raster*(unten+2)), (int)(raster*(rechts+1)), (int)(raster*(oben+2))); } void zeichneKreis(int links, int unten) { win << FilledCircle(raster*links+raster*3/2, raster*unten+raster*5/2, raster/3); } void zeichneAlles() { // Zeichne Hintergrund setzeFarbe(spielFarbe[sieger]); zeichneRechteck(-1., 8., -2., 7.); // Zeichne Spielfeld setzeFarbe(BLAU); zeichneRechteck(0., 7., 0., 6.); // Zeichne linken Fuss zeichneRechteck(-0.7, -.02, -1.3, 3.0); // Zeichne rechten Fuss zeichneRechteck(7.02, 7.7, -1.3, 3.0); // Zeichne Klappe if (klappe) setzeFarbe(WEISS); zeichneRechteck(2.5, 4.5, -0.3, -.02); // Zeichne Spielstaerke-Skala for (int i = 0; i < spielStaerkeWahl; i++) { setzeFarbe(WEISS); zeichneRechteck(i, i+.9, -1.8, -1.6); } // Zeichne Scheiben resp. Loecher for (int spalte = 0; spalte < 7; spalte++) { for (int zeile = 0; zeile < 6; zeile++) { setzeFarbe(spielFarbe[spielFeld[spalte][zeile]]); zeichneKreis(spalte, zeile); } } // Zeichne Einwurf-Kreis if (einwurfSpalte != undefiniert) { setzeFarbe(einwurfFarbe); zeichneKreis(einwurfSpalte, einwurfZeile); } // Mache alles sichtbar win << flush; } // ------ Spielstrategie-Funktionen int bewerteReihe(Spieler spieler, int spalte, int zeile, int spaltenSprung, int zeilenSprung) { int anzahl[3] = { 0, 0, 0}; Spieler gegenSpieler = spieler==MENSCH ? COMPUTER : MENSCH; for (int feld = 0; feld < 4; feld++) { Spieler wem = spielFeld[spalte][zeile]; anzahl[wem]++; spalte += spaltenSprung; zeile += zeilenSprung; } if (anzahl[NIEMAND] == 4) return 0; if (anzahl[gegenSpieler] == 0) { switch (anzahl[spieler]) { case 4: return 9999; case 3: return 100; case 2: return 10; case 1: return 1; } } if (anzahl[spieler] == 0) { switch (anzahl[gegenSpieler]) { case 4: return -9999; case 3: return -300; case 2: return -30; case 1: return -3; } } return 0; } int bewerteLage(Spieler spieler) { int zeile, spalte; int bewertung = 0; // Pruefe horizontale Linien for (zeile = 0; zeile < 6; zeile++) { for (spalte = 0; spalte < 4; spalte++) { bewertung += bewerteReihe(spieler, spalte, zeile, 1, 0); } } // Pruefe vertikale Linien for (zeile = 0; zeile < 3; zeile++) { for (spalte = 0; spalte < 7; spalte++) { bewertung += bewerteReihe(spieler, spalte, zeile, 0, 1); } } // Pruefe vorwaerts Diagonalen for (zeile = 0; zeile < 3; zeile++) { for (spalte = 0; spalte < 4; spalte++) { bewertung += bewerteReihe(spieler, spalte, zeile, 1, 1); } } // Pruefe rueckwaerts Diagonalen for (zeile = 0; zeile < 3; zeile++) { for (spalte = 3; spalte < 7; spalte++) { bewertung += bewerteReihe(spieler, spalte, zeile, -1, 1); } } return bewertung; } bool spielEnde(Spieler spieler) { int zeile, spalte; if (freieFelder == 0) return true; // Unentschieden // Pruefe horizontale Linien for (zeile = 0; zeile < 6; zeile++) { for (spalte = 0; spalte < 4; spalte++) { if (spielFeld[spalte ][zeile] == spieler && spielFeld[spalte+1][zeile] == spieler && spielFeld[spalte+2][zeile] == spieler && spielFeld[spalte+3][zeile] == spieler) { sieger = spieler; return true; } } } // Pruefe vertikale Linien for (zeile = 0; zeile < 3; zeile++) { for (spalte = 0; spalte < 7; spalte++) { if (spielFeld[spalte][zeile+0] == spieler && spielFeld[spalte][zeile+1] == spieler && spielFeld[spalte][zeile+2] == spieler && spielFeld[spalte][zeile+3] == spieler) { sieger = spieler; return true; } } } // Pruefe vorwaerts Diagonalen for (zeile = 0; zeile < 3; zeile++) { for (spalte = 0; spalte < 4; spalte++) { if (spielFeld[spalte+0][zeile+0] == spieler && spielFeld[spalte+1][zeile+1] == spieler && spielFeld[spalte+2][zeile+2] == spieler && spielFeld[spalte+3][zeile+3] == spieler) { sieger = spieler; return true; } } } // Pruefe rueckwaerts Diagonalen for (zeile = 0; zeile < 3; zeile++) { for (spalte = 3; spalte < 7; spalte++) { if (spielFeld[spalte-0][zeile+0] == spieler && spielFeld[spalte-1][zeile+1] == spieler && spielFeld[spalte-2][zeile+2] == spieler && spielFeld[spalte-3][zeile+3] == spieler) { sieger = spieler; return true; } } } return false; } int wuerfle(int von, int bis) { double r = (rand() + 0.) / (RAND_MAX + 1.); return (int)(von + (bis + 1. - von) * r); } int findeZug(Spieler spieler, int suchTiefe, int schranke, int& besteSpalte) { besteSpalte = -1; if (suchTiefe == 0) { // Wuerfle den Zug bool ok = false; do { besteSpalte = wuerfle(0,3) + wuerfle(0,3); ok = spielFeld[besteSpalte][5] == NIEMAND; } while (!ok); return 0; } else { // Berechne den Zug Spieler gegenSpieler = spieler==MENSCH ? COMPUTER : MENSCH; int besterWert = -unendlich; for (int spalte = 0; spalte < 7; spalte++) { if (hoehe[spalte] < 6) { // Mache provisorischen Zug spielFeld[spalte][hoehe[spalte]] = spieler; hoehe[spalte]++; // Bewerte neue Spielsituation int wert = bewerteLage(spieler); // Suche tiefer if (suchTiefe > 1 && wert < 5000) { int s; // Lasse Gegner Zug finden und negiere Bewertung wert = -findeZug(gegenSpieler, suchTiefe-1, -besterWert, s); } // Merke Zug falls besser als bisher ausgewertete if (wert > besterWert) { besterWert = wert; besteSpalte = spalte; } // Mache Zug rueckgaengig hoehe[spalte]--; spielFeld[spalte][hoehe[spalte]] = NIEMAND; if (wert >= schranke) return unendlich; } } return besterWert; } } // ------ Spielverwaltungs-Funktionen void wirfEin(int spalte, Spieler spieler) { // Stelle den Zug grafisch dar einwurfSpalte = spalte; einwurfFarbe = spielFarbe[spieler]; for (einwurfZeile = 6; einwurfZeile >= hoehe[spalte]; einwurfZeile--) { zeichneAlles(); win << flush << wait(50000); // kurze Pause } einwurfSpalte = undefiniert; // Schreibe Zug auf Logfile static ofstream logFile("vierGewinntLog.txt"); logFile << setw(3) << 42-freieFelder << ": " << spalte << "\n"; // Fuehre Zug im Spielfeld nach spielFeld[spalte][hoehe[spalte]] = spieler; hoehe[spalte]++; freieFelder--; // Pruefe ob Spiel fertig fertig = spielEnde(spieler); } void neuesSpiel() { static int spielNummer = 0; // Leere das Spielfeld for (int spalte = 0; spalte < 7; spalte++) { for (int zeile = 0; zeile < 6; zeile++) { spielFeld[spalte][zeile] = NIEMAND; } hoehe[spalte] = 0; } // Initialisiere Variablen fertig = false; sieger = NIEMAND; einwurfSpalte = undefiniert; freieFelder = 42; // Zaehle das Spiel spielNummer++; // Konsumiere alte Events int x, y; if (win.check_mouse_click()) win.get_mouse_click(x, y); // Beginne Spiel falls gerade Nummer if (spielNummer % 2 == 0) { // gerade Spielnummer int spalte; findeZug(COMPUTER, spielStaerke, unendlich, spalte); wirfEin(spalte, COMPUTER); } } void findeMausPosition(int x, int y, int& spalte, int& zeile) { spalte = x / raster - 1; zeile = y / raster - 2; } void behandleMausBewegung() { // Finde Spalte und Zeile wo sich der Cursor befindet int x, y, zeile, spalte; win.get_mouse(x, y); findeMausPosition(x, y, spalte, zeile); // Falls Cursor in Einwurf-Position ... einwurfSpalte = undefiniert; if (!fertig && zeile == 6 && spalte >= 0 && spalte < 7) { einwurfSpalte = spalte; einwurfZeile = 6; einwurfFarbe = spielFarbe[MENSCH]; } // Falls Cursor ueber Leerklappe ... klappe = (zeile == -1 && spalte >= 2 && spalte <= 4); // Falls Cursor ueber Spielstaerken-Skala ... if (zeile == -2) spielStaerkeWahl = spalte + 1; else spielStaerkeWahl = spielStaerke; } void behandleMausClick() { // Finde Spalte und Zeile wo sich der Cursor befindet int x, y, zeile, spalte; win.get_mouse_click(x, y); findeMausPosition(x, y, spalte, zeile); // Beende altes Spiel falls noetig if (sieger != NIEMAND) { sieger = NIEMAND; return; } // Falls Cursor in Einwurf-Position ... if (zeile == 6) { // Falls Spielzug in dieser Spalte moeglich ... if (spalte >= 0 && spalte < 7 && spielFeld[spalte][5] == NIEMAND) { // Akzeptiere Zug wirfEin(spalte, MENSCH); // Mache Computer-Zug if (!fertig) { int suchTiefe = (spielStaerke < freieFelder) ? spielStaerke : freieFelder-1; findeZug(COMPUTER, suchTiefe, unendlich, spalte); wirfEin(spalte, COMPUTER); } } } // Falls Leerklappe gedrueckt ... else if (zeile == -1 && spalte >= 2 && spalte <= 4) { cout << "Neues Spiel.\n"; fertig = true; sieger = COMPUTER; } // Falls neue Spielstaerke gewaehlt ... else if (zeile == -2) { spielStaerkeWahl = spielStaerke = spalte + 1; cout << "Neue Spielstaerke: " << spielStaerke << "\n"; } } // ------ Hauptprogramm int main(int argc, char** argv) { while (true) { neuesSpiel(); zeichneAlles(); while (!fertig) { // ESC key if (win.check_key() && win.get_key() == 27) return 0; if (win.check_mouse()) behandleMausBewegung(); if (win.check_mouse_click()) behandleMausClick(); zeichneAlles(); } switch(sieger) { case MENSCH: cout << "Du hast gewonnen! \n"; break; case COMPUTER: cout << "Ich habe gewonnen!\n"; break; case NIEMAND: cout << "Unentscheiden! \n"; break; } // wait while (!win.check_mouse_click() && !win.check_key()); } return 0; }