/*
Alexander Goldt & Pascal Wendt
Wir haben 4 verschiedene Computergegner programmiert mit unterschiedlichen schwierigkeitsgraden
einfach: Die KI raet wo sie setzt
implementierung: void easymode
mittel: siehe schwer, aber die KI "vergisst" manchmal zu prüfen ob sie gewinnen kann
implementierung: void simHunan
schwer: die KI geht systematisch vor und spielt eine Strategie die es einem Gegner nicht ermöglicht zu gewinnen.
es ist maximal ein Unentschieden möglich.
implementierung: void schwer
Unmöglich: ein witzgegner der alle Felder mit seinem Zeichen überschreibt
implementierung: void unmoeglich
tl;dr
bitte "void schwer" anstatt "void berechneSpielzug" angucken
als Computergegner h auswählen
*/
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define NONE '\0'
void gibIntroAus();
void gibGewinnerAus(char gewinner);
void gibSpielfeldAus(const char spielfeld[][3]);
void liesSpielzugEin(char spielfeld[][3], char SpielerAmZug);
char hatGewinner(const char spielfeld[][3]);
void berechneSpielzug(char spielfeld[][3], char SpielerAmZug);
int anzahlZuege(const char spielfeld[][3]);
char schwierigkeit();
void easymode(char spielfeld[][3], char spieleramZug);
char gegner(char spieleramzug);
void unmoeglich(char pos[][3], char player);
void schwer(char pos[][3], char player);
int kannOppWin(char pos[][3], char player);
int kannPlayerWin(char pos[][3], char player);
int mitteFrei(char pos[][3], char player);
int randSetzen(char pos[][3], char player);
void simHuman(char pos[][3], char player);
//Implementierungen
void gibIntroAus(){
printf("Wilkommen zu TicTacToe!\n");
printf("Sie koennen entweder zu zweit oder gegen den Computer spielen.\n");
srand(time(NULL));
}
void gibGewinnerAus(char gewinner){
if (gewinner == 'x')
printf("\t\tDer Gewinner ist:\n\t\tX\n", gewinner);
if (gewinner == 'o')
printf("\t\tDer Gewinner ist:\n\t\tO\n", gewinner);
if (gewinner == '*')
printf("Diese Runde ist unentschieden\n");
else return;
}
void gibSpielfeldAus(const char spielfeld[][3]){
unsigned int i, j;
printf("\n 1 2 3 \n");
printf("--------\n");
for (i = 0; i < 3; i++){
printf("%i|", i+1);
for (j = 0; j < 3; j++){
if (spielfeld[i][j] == '\0')
printf(" |");
if (spielfeld[i][j] == 'x')
printf("X|");
if (spielfeld[i][j] == 'o')
printf("O|");
if (j == 2)
printf("\n");
}
printf("--------\n");
}
printf("\n\n");
}
void liesSpielzugEin(char spielfeld[][3], char SpielerAmZug){
char buffer[81];
int x, y;
printf("Bitte gib die Koordinaten fuer deinen Zug ein\nSpieler %c\n[x,y]\n",SpielerAmZug);
gets_s(buffer, 81);
sscanf_s(buffer, "%d,%d", &y, &x);
x--;
y--;
if ((x >= 0 && x <= 2) && (y >= 0 && y <= 2)){
if (spielfeld[x][y] == '\0'){
spielfeld[x][y] = SpielerAmZug;
return;
}
else (liesSpielzugEin(spielfeld, SpielerAmZug));
}
}
char hatGewinner(const char spielfeld[][3]){
if (spielfeld[0][0] == spielfeld[1][1] && spielfeld[1][1] == spielfeld[2][2] && spielfeld[2][2] != '\0')
return spielfeld[0][0];
if (spielfeld[0][2] == spielfeld[1][1] && spielfeld[1][1] == spielfeld[2][0] && spielfeld[2][0] != '\0')
return spielfeld[0][2];
if (spielfeld[0][0] == spielfeld[1][0] && spielfeld[1][0] == spielfeld[2][0] && spielfeld[2][0] != '\0')
return spielfeld[0][0];
if (spielfeld[0][1] == spielfeld[1][1] && spielfeld[1][1] == spielfeld[2][1] && spielfeld[2][1] != '\0')
return spielfeld[0][1];
if (spielfeld[0][2] == spielfeld[1][2] && spielfeld[1][2] == spielfeld[2][2] && spielfeld[2][2] != '\0')
return spielfeld[0][2];
if (spielfeld[0][0] == spielfeld[0][1] && spielfeld[0][1] == spielfeld[0][2] && spielfeld[0][2] != '\0')
return spielfeld[0][0];
if (spielfeld[1][0] == spielfeld[1][1] && spielfeld[1][1] == spielfeld[1][2] && spielfeld[1][2] != '\0')
return spielfeld[1][0];
if (spielfeld[2][0] == spielfeld[2][1] && spielfeld[2][1] == spielfeld[2][2] && spielfeld[2][2] != '\0')
return spielfeld[2][0];
if (anzahlZuege(spielfeld) == 9)
return '*';
return '\0';
}
void berechneSpielzug(char spielfeld[][3], char SpielerAmZug){
static char diff1;
static char diff2;
if (SpielerAmZug == 'x'){
if (anzahlZuege(spielfeld) < 2)
diff1 = schwierigkeit();
if (diff1 == 'e')
easymode(spielfeld, SpielerAmZug);
if (diff1 == 'm')
simHuman(spielfeld, SpielerAmZug);
if (diff1 == 'i')
unmoeglich(spielfeld, SpielerAmZug);
if (diff1 == 'h')
schwer(spielfeld, SpielerAmZug);
}
else{
if (anzahlZuege(spielfeld) < 2)
diff2 = schwierigkeit();
if (diff2 == 'e')
easymode(spielfeld, SpielerAmZug);
if (diff2 == 'm')
simHuman(spielfeld, SpielerAmZug);
if (diff2 == 'i')
unmoeglich(spielfeld, SpielerAmZug);
if (diff2 == 'h')
schwer(spielfeld, SpielerAmZug);
}
}
char schwierigkeit(){
char difficulty;
printf("\nBitte waehlen sie die Schwierigkeit des Computergegners:\nE - Einfach\nM - Mittel\nH - Schwer \nI - Impossible\n>>");
/*
einfach - Zufälliges setzen
schwer - Setzen mit system / kein Sieg mehr möglich durch den Gegner der KI
Impossible - Es wird alles mit dem Zeichen der KI überschrieben / Scherzmodus
Mittel - wie Schwer, nur werden random teile der strategie "vergessen" / Gewinnen möglich evtl.
*/
difficulty = getchar();
while (getchar() != '\n');
switch (difficulty){
case 'e':
return 'e';
case 'E':
return 'e';
case 'h':
return 'h';
case 'H':
return 'h';
case 'i':
return 'i';
case 'I':
return 'i';
case'm':
return 'm';
case 'M':
return 'm';
schwierigkeit();
break;
}
return 'e';
}
//Die Implementierungen für die Schwierigkeiten
void easymode(char spielfeld[][3], char spieleramZug){
int x ;
int y ;
x = rand() % 3;
y = rand() % 3;
while (spielfeld[x][y] != '\0'){
x = rand() % 3;
y = rand() % 3;
}
spielfeld[x][y] = spieleramZug;
}
void unmoeglich(char pos[][3], char player){
unsigned int i, j;
for (i = 0; i < 3; i++){
for (j = 0; j < 3; j++){
pos[i][j] = player;
}
}
printf("Du kannst mich mal %c!\n", gegner);
return;
}
void schwer(char pos[][3], char player){
if (kannOppWin(pos, player))
return;
if (kannPlayerWin(pos, player))
return;
if (mitteFrei(pos, player))
return;
if (eckeSetzen(pos, player))
return;
if (randSetzen(pos, player))
return;
else{
printf("Ich weis nicht wo ich noch mein %c setzen soll.\nEs scheint mir alles voll zu sein!\nVielleicht hat %c ja geschummelt!\nSCHIEBUNG!!!", player, gegner(player));
}
}
void simHuman(char pos[][3], char player){
int forget = 0;
forget = rand() % 2;
if (forget != 0 && kannOppWin(pos, player))
return;
if (forget != 1 && kannPlayerWin(pos, player))
return;
if (mitteFrei(pos, player))
return;
if (eckeSetzen(pos, player))
return;
if (randSetzen(pos, player))
return;
else{
printf("Ich weis nicht wo ich noch mein %c setzen soll.\nEs scheint mir alles voll zu sein!\nVielleicht hat %c ja geschummelt!\nSCHIEBUNG!!!", player, gegner(player));
}
}
//Die Implementierungen für "schwer" und "simHuman"
int kannOppWin(char pos[][3], char player){
if ((pos[0][0] == pos[0][2]) && (pos[0][1] == NONE) && (pos[0][0] == gegner(player))){
pos[0][1] = player;
return 1;
}
if ((pos[0][0] == pos[2][0]) && pos[1][0] == NONE && pos[0][0] == gegner(player)){
pos[1][0] = player;
return 1;
}
if ((pos[2][0] == pos[2][2]) && pos[2][1] == NONE && pos[2][0] == gegner(player)){
pos[2][1] = player;
return 1;
}
if ((pos[2][2] == pos[0][2]) && pos[1][2] == NONE && pos[2][2] == gegner(player)){
pos[1][2] = player;
return 1;
}
if ((pos[0][0] == pos[2][2]) && pos[1][1] == NONE && pos[0][0] == gegner(player)){
pos[1][1] = player;
return 1;
}
if ((pos[2][0] == pos[0][2]) && pos[1][1] == NONE && pos[2][0] == gegner(player)){
pos[1][1] = player;
return 1;
}
if (pos[0][0] == pos[0][1] && pos[0][2] == NONE && pos[0][0] == gegner(player)){
pos[0][2] = player;
return 1;
}
if (pos[0][1] == pos[0][2] && pos[0][0] == NONE && pos[0][1] == gegner(player)){
pos[0][0] = player;
return 1;
}
if (pos[0][0] == pos[1][0] && pos[2][0] == NONE && pos[0][0] == gegner(player)){
pos[2][0] = player;
return 1;
}
if (pos[1][0] == pos[2][0] && pos[0][0] == NONE && pos[0][0] == gegner(player)){
pos[0][0] = player;
return 1;
}
if (pos[2][0] == pos[2][1] && pos[2][2] == NONE && pos[2][0] == gegner(player)){
pos[2][2] = player;
return 1;
}
if (pos[2][1] == pos[2][2] && pos[2][0] == NONE && pos[2][1] == gegner(player)){
pos[2][0] = player;
return 1;
}
if (pos[0][2] == pos[1][2] && pos[2][2] == NONE && pos[0][2] == gegner(player)){
pos[2][2] = player;
return 1;
}
if (pos[1][2] == pos[2][2] && pos[0][2] == NONE && pos[1][2] == gegner(player)){
pos[0][2] = player;
return 1;
}
if (pos[1][2] == pos[1][1] && pos[1][0] == NONE && pos[1][2] == gegner(player)){
pos[1][0] = player;
return 1;
}
if (pos[1][0] == pos[1][1] && pos[1][2] == NONE && pos[1][1] == gegner(player)){
pos[1][2] = player;
return 1;
}
if (pos[1][1] == pos[2][2] && pos[0][0] == NONE && pos[2][2] == gegner(player)){
pos[0][0] = player;
return 1;
}
if (pos[0][0] == pos[1][1] && pos[2][2] == NONE && pos[1][1] == gegner(player)){
pos[2][2] = player;
return 1;
}
if (pos[0][1] == pos[1][1] && pos[2][1] == NONE && pos[1][1] == gegner(player)){
pos[2][1] = player;
return 1;
}
if (pos[1][1] == pos[2][1] && pos[0][1] == NONE && pos[2][1] == gegner(player)){
pos[0][1] = player;
return 1;
}
if (pos[0][2] == pos[1][1] && pos[2][0] == NONE && pos[0][2] == gegner(player)){
pos[2][0] = player;
return 1;
}
if (pos[1][1] == pos[2][0] && pos[0][2] == NONE && pos[1][1] == gegner(player)){
pos[0][2] = player;
return 1;
}
if (pos[0][1] == pos[2][1] && pos[1][1] == NONE && pos[0][1] == gegner(player)){
pos[1][1] = player;
return 1;
}
if (pos[1][0] == pos[1][2] && pos[1][1] == NONE && pos[1][0] == gegner(player)){
pos[1][1] = player;
return 1;
}
else return 0;
}
int kannPlayerWin(char pos[][3], char player){
//die bedingung &&pos[][] == player ist überflüssug aber da weil ich es mit suchen und ersetzen geänder hab
if ((pos[0][0] == pos[0][2]) && (pos[0][1] == NONE) && (pos[0][0] == player)){
pos[0][1] = player;
return 1;
}
if ((pos[0][0] == pos[2][0]) && pos[1][0] == NONE && pos[0][0] == player){
pos[1][0] = player;
return 1;
}
if ((pos[2][0] == pos[2][2]) && pos[2][1] == NONE && pos[2][0] == player){
pos[2][1] = player;
return 1;
}
if ((pos[2][2] == pos[0][2]) && pos[1][2] == NONE && pos[2][2] == player){
pos[1][2] = player;
return 1;
}
if ((pos[0][0] == pos[2][2]) && pos[1][1] == NONE && pos[0][0] == player){
pos[1][1] = player;
return 1;
}
if ((pos[2][0] == pos[0][2]) && pos[1][1] == NONE && pos[2][0] == player){
pos[1][1] = player;
return 1;
}
if (pos[0][0] == pos[0][1] && pos[0][2] == NONE && pos[0][0] == player){
pos[0][2] = player;
return 1;
}
if (pos[0][1] == pos[0][2] && pos[0][0] == NONE && pos[0][1] == player){
pos[0][0] = player;
return 1;
}
if (pos[0][0] == pos[1][0] && pos[2][0] == NONE && pos[0][0] == player){
pos[2][0] = player;
return 1;
}
if (pos[1][0] == pos[2][0] && pos[0][0] == NONE && pos[0][0] == player){
pos[0][0] = player;
return 1;
}
if (pos[2][0] == pos[2][1] && pos[2][2] == NONE && pos[2][0] == player){
pos[2][2] = player;
return 1;
}
if (pos[2][1] == pos[2][2] && pos[2][0] == NONE && pos[2][1] == player){
pos[2][0] = player;
return 1;
}
if (pos[0][2] == pos[1][2] && pos[2][2] == NONE && pos[0][2] == player){
pos[2][2] = player;
return 1;
}
if (pos[1][2] == pos[2][2] && pos[0][2] == NONE && pos[1][2] == player){
pos[0][2] = player;
return 1;
}
if (pos[1][2] == pos[1][1] && pos[1][0] == NONE && pos[1][2] == player){
pos[1][0] = player;
return 1;
}
if (pos[1][0] == pos[1][1] && pos[1][2] == NONE && pos[1][1] == player){
pos[1][2] = player;
return 1;
}
if (pos[1][1] == pos[2][2] && pos[0][0] == NONE && pos[2][2] == player){
pos[0][0] = player;
return 1;
}
if (pos[0][0] == pos[1][1] && pos[2][2] == NONE && pos[1][1] == player){
pos[2][2] = player;
return 1;
}
if (pos[0][1] == pos[1][1] && pos[2][1] == NONE && pos[1][1] == player){
pos[2][1] = player;
return 1;
}
if (pos[1][1] == pos[2][1] && pos[0][1] == NONE && pos[2][1] == player){
pos[0][1] = player;
return 1;
}
if (pos[0][2] == pos[1][1] && pos[2][0] == NONE && pos[0][2] == player){
pos[2][0] = player;
return 1;
}
if (pos[1][1] == pos[2][0] && pos[0][2] == NONE && pos[1][1] == player){
pos[0][2] = player;
return 1;
}
if (pos[0][1] == pos[2][1] && pos[1][1] == NONE && pos[0][1] == player){
pos[1][1] = player;
return 1;
}
if (pos[1][0] == pos[1][2] && pos[1][1] == NONE && pos[1][0] == player){
pos[1][1] = player;
return 1;
}
else return 0;
}
int mitteFrei(char pos[][3], char player){
if (pos[1][1] == NONE){
pos[1][1] = player;
return 1;
}
else return 0;
}
int eckeSetzen(char pos[][3], char player){
if (pos[0][0] == NONE){
pos[0][0] = player;
return 1;
}
if (pos[0][2] == NONE){
pos[0][2] = player;
return 1;
}
if (pos[2][0] == NONE){
pos[2][0] = player;
return 1;
}
if (pos[2][2] == NONE){
pos[2][2] = player;
return 1;
}
else return 0;
}
int randSetzen(char pos[][3], char player){
int i, j;
//Ich geh alle felder mit der for schleife durch weil wie anderen sowieso schon gesetzt sein müssten und ich das so einfacher finde.
//Bei einem 3x3 ist das auch nicht wichtig denke ich, da es keine geschwindigkeitsvorteile bringt nur die kantenfelder zu nehmen.
for (i = 0; i < 3; i++){
for (j = 0; j < 3; j++){
if (pos[i][j] == NONE){
pos[i][j] = player;
return 1;
}
}
}
return 0;
}
// Allgemeine hilfsfunktionen
int anzahlZuege(const char spielfeld[][3]){
unsigned int i, j;
unsigned int anzahl = 0;
for (i = 0; i < 3; i++){
for (j = 0; j < 3; j++){
if (spielfeld[i][j] != '\0')
anzahl++;
}
}
return anzahl;
}
char gegner(char spieleramzug){
if (spieleramzug == 'x')
return 'o';
else return 'x';
}