# TicTacToe KI



## Gnoccy (9. Mrz 2012)

Nabend,

Habe da gerade ein kleines Problem, und zwar arbeite ich zur Zeit an einer KI für TicTacToe. Mein bisheriger Code dazu sieht wie folgt aus:


```
public class KI 
{
	int gibZug(Feld f, boolean spieler1AmZug)
	{
		Feld kifeld = new Feld();
		
		
		String spieler;
		if (spieler1AmZug == true)
		{
			spieler = "X";
		}
		else
		{
			spieler = "O";
		}
		
		
		int zug = -1;
		int bZugWert = 0;
		int aZugWert = 0;
		
		//Feld übertragen
		for(int i = 0; i < 2; i++)
		{
			for(int j = 0;j < 2; j++)
			{
				kifeld.setField(i, j, f.getField(i, j));
			}
		}
		
		for (int z1 = 0;z1 < 8; z1++)
		{
			
			int x1 = z1 % 3;
			int y1 = (z1 - x1) / 3;
			
			if(kifeld.isValidMove(z1))
			{
				System.out.println(z1);
				kifeld.setField(x1, y1, spieler);
				if(kifeld.gewonnen())
				{
					aZugWert =+ 1;
					if(aZugWert >= bZugWert)
					{
						bZugWert = aZugWert;
						zug = z1;
					}
					kifeld.setField(x1, y1, "__");
				}
				else
				{
					for(int z2 = 0; z2 < 8; z2++)
					{
						int x2 = z2 % 3;
						int y2 = (z2 - x2) / 3;
						
						if(kifeld.isValidMove(z2))
						{
							kifeld.setField(x2, y2, spieler);
							if(kifeld.gewonnen())
							{
								aZugWert =- 1;
								if(aZugWert >= bZugWert)
								{
									bZugWert = aZugWert;
									zug = z1;
									kifeld.setField(x2, y2, "__");
								}
								
							}
							else
							{
								for (int z3 = 0;z3 < 8; z3++)
								{
									
									int x3 = z3 % 3;
									int y3 = (z3 - x3) / 3;
									
									if(kifeld.isValidMove(z3))
									{
										kifeld.setField(x3, y3, spieler);
										if(kifeld.gewonnen())
										{
											aZugWert =+ 1;
											if(aZugWert >= bZugWert)
											{
												bZugWert = aZugWert;
												zug = z1;
												kifeld.setField(x3, y3, "__");
											}
										}
										else
										{
											for(int z4 = 0; z4 < 8; z4++)
											{
												int x4 = z4 % 3;
												int y4 = (z4 - x4) / 3;
												
												if(kifeld.isValidMove(z4))
												{
													kifeld.setField(x4, y4, spieler);
													if(kifeld.gewonnen())
													{
														aZugWert =- 1;
														if(aZugWert >= bZugWert)
														{
															bZugWert = aZugWert;
															zug = z1;
															kifeld.setField(x4, y4, "__");
														}
														
													}
													else
													{
														for (int z5 = 0;z5 < 8; z5++)
														{
															
															int x5 = z5 % 3;
															int y5 = (z5 - x5) / 3;
															
															if(kifeld.isValidMove(z5))
															{
																kifeld.setField(x5, y5, spieler);
																if(kifeld.gewonnen())
																{
																	aZugWert =+ 1;
																	if(aZugWert >= bZugWert)
																	{
																		bZugWert = aZugWert;
																		zug = z1;
																		kifeld.setField(x5, y5, "__");
																	}
																}
																else
																{
																	for(int z6 = 0; z6 < 8; z6++)
																	{
																		int x6 = z6 % 3;
																		int y6 = (z6 - x6) / 3;
																		
																		if(kifeld.isValidMove(z6))
																		{
																			kifeld.setField(x6, y6, spieler);
																			if(kifeld.gewonnen())
																			{
																				aZugWert =- 1;
																				if(aZugWert >= bZugWert)
																				{
																					bZugWert = aZugWert;
																					zug = z1;
																					kifeld.setField(x6, y6, "__");
																				}
																				
																			}
																			else
																			{
																				for (int z7 = 0;z7 < 8; z7++)
																				{
																					
																					int x7 = z7 % 3;
																					int y7 = (z7 - x7) / 3;
																					
																					if(kifeld.isValidMove(z7))
																					{
																						kifeld.setField(x7, y7, spieler);
																						if(kifeld.gewonnen())
																						{
																							aZugWert =+ 1;
																							if(aZugWert >= bZugWert)
																							{
																								bZugWert = aZugWert;
																								zug = z1;
																								kifeld.setField(x7, y7, "__");
																							}
																						}
																						else
																						{
																							for(int z8 = 0; z8 < 8; z8++)
																							{
																								int x8 = z8 % 3;
																								int y8 = (z8 - x8) / 3;
																								
																								if(kifeld.isValidMove(z8))
																								{
																									kifeld.setField(x8, y8, spieler);
																									if(kifeld.gewonnen())
																									{
																										aZugWert =- 1;
																										if(aZugWert >= bZugWert)
																										{
																											bZugWert = aZugWert;
																											zug = z1;
																											kifeld.setField(x8, y8, "__");
																										}
																										
																									}
																									else
																									{
																										for (int z9 = 0;z9 < 8; z9++)
																										{
																											System.out.println(aZugWert);
																											int x9 = z9 % 3;
																											int y9 = (z9 - x9) / 3;
																											
																											if(kifeld.isValidMove(z9))
																											{
																												kifeld.setField(x9, y9, spieler);
																												if(kifeld.gewonnen())
																												{
																													System.out.println(aZugWert);
																													aZugWert =+ 1;
																													if(aZugWert >= bZugWert)
																													{
																														bZugWert = aZugWert;
																														zug = z1;
																														kifeld.setField(x9, y9, "__");
																													}
																												}
																											}
																										}
																									}
																								}
																							}
																						}
																					}
																				}
																			}
																		}
																	}
																}
															}
														}
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
		
		
		
		
		
		
		return zug;
	}
	
	

}
```

Ich weiss, das ginge sicherlich noch schöner und eleganter, aber da habe ich gerade keine Lust zu 

Die Idee dahinter is, dass ein Zug simuliert wird und danach geprüft wird, ob der Spieler gewonnen oder verloren hat. Hat er gewonnen, wird eine Variable um eins erhöht, hat er verloren um eins verringert. Trifft keines von beiden zu wird der nächste Zug simuliert.
Gleichzeitig wird der Zug mit der bisher höchsten "Punktzahl"  gespeichert und am ende zurückgegeben. Mein Problem ist nun, das immer -1 zurückgegeben wird, was zu fehlern im weiterem verlauf des Programms führt.
Kann mir da wer helfen? Oder habe ich da eventuell einen völlig falschen Ansatz und mein ganzer Code ist quatsch?
Würde mich auf jeden Fall über hilfe freuen.

MFG:Gnoccy


----------



## XHelp (9. Mrz 2012)

Gnoccy hat gesagt.:


> Ich weiss, das ginge sicherlich noch schöner und eleganter, aber da habe ich gerade keine Lust zu


Und ich für meinen Teil habe keine Lust mich durch den "Code" durcharbeiten :bahnhof:
Da irgendwas nachzuvollziehen ist beinah unmöglich. Schreib den vernünftig um, dann wirst du auch mit Sicherheit selber den Fehler finden.


----------



## Gast2 (9. Mrz 2012)

```
}
                                                                                                                }
                                                                                                            }
                                                                                                        }
                                                                                                    }
                                                                                                }
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                }
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
```
Allein diese Einrückung, krass :rtfm:
Da kann ich XHelp nur zustimmen, schreib den Code mal so um dass den auch außenstehende gut lesen können.


----------



## truesoul (9. Mrz 2012)

EikeB hat gesagt.:


> ```
> }
> }
> }
> ...



:lol: 28 Zeilen 



> Ich weiss, das ginge sicherlich noch schöner und eleganter, aber da habe ich gerade keine Lust zu


Jo, dazu hätt ich auch keine lust


----------



## hüteüberhüte (9. Mrz 2012)

hhhmmm, ist das nicht so, dass der Zug am besten wäre, der mit den wenigsten Zügen zu 4 gleichen führen würde? Wenn bis dahin mehrere Zugmöglichkeiten möglich sind, um 4 gleiche zu bekommen, wäre der Zug dann entsprechend besser? Muss gestehen, dass ich auch keinen Plan habe, wie die Strategie sein sollte... Vielleicht erklärt XHelp oder EikeB die Strategie/Taktik!? Bin mir fast sicher, dass das einer weiß


----------



## pappawinni (9. Mrz 2012)

ich bin eben mal über den Code gefolgen und mir fielen sofort Zeilen dieser Art ins Auge, massenhaft:
 aZugWert =+ 1;
 aZugWert =- 1;
und da fragte ich mich, was dabei wohl herauskommen wird .....???:L
und was da eigentlich beabsichtigt war....:shock: .... vielleicht
 aZugWert ++;  (aZugWert *+=* 1; )
 aZugWert --;  (aZugWert *-=* 1; )
feif:feif:


----------



## XHelp (9. Mrz 2012)

hüteüberhüte hat gesagt.:


> Vielleicht erklärt XHelp oder EikeB die Strategie/Taktik!?


Beim Stichwort MiniMax ist man sicherlich gut aufgehoben. Es gibt auch bestimmt einige Implementierungen in Java für TicTacToe, die man sich angucken könnte.
Aber welche Strategie da oben verwendet wird - keine Ahnung


----------



## pappawinni (9. Mrz 2012)

Naja, ist doch im Grunde egal, was sich einer aussucht, um sich auszutoben.
Und dann gibt es ja in der Softwareentwicklung auch mehrere Stufen, nichtwahr.
Zuerst kommt es mal darauf an, dass das Ding läuft.
Make it nice kommt zuletzt :lol:


----------



## Gnoccy (9. Mrz 2012)

Ich weiss nicht, ob das eben evtl etwas falsch rübergekommen ist, aber das Problem ist, dass ich einfach keine Idee habe, wie man das ganze umschreiben könnte. Da immer wieder relativ ähnliche Elemente wiederholt werden, gehe ich mal davon aus, dass man das ganze auch mit einer (for?) Schleife realisieren kann, nur wie gesagt, ich komme nicht drauf wie.
Grundsätzlich sollen alle Schleifen das selbe tuen:
Sie Simulieren mit jedem durchlauf einen der (theoretisch) 9 möglichen Züge in TicTacToe. Danach wir überprüft, ob der Spieler mit einem dieser Züge gewonnen hat, und falls ja, wird die variable aZugWert um eins erhöht.
Hat er nicht gewonnen, wird der nächste Zug simuliert. Da es sich ja hierbei um den Zug des Gegners handelt, wird aZugWert, wenn der Spieler mit diesem Zug gewinnt um eins verringert.
Das geht so weiter, bis alle möglichen Züge durchgegangen sind, also 9 mal, dabei wechselt der Spieler der zieht immer hin und her, also wird zu aZugWert entweder addiert, oder subtrahieren.

Wie gesagt, ich denke mal, dass man anstatt der 9 Schleifen auch eine der Schleifen 9 mal wiederholen könnte, allerdings weiss ich gerade nicht, wie ich das dann mit den Punkten und dem wechsel zwischen +/- hinbekommen soll. Aber darum geht es ja auch gar nicht.

Was ich damit sagen will ist, dass es nicht nötig ist, sich alle neun Schleifen durchzulesen, ich gebe zu, dass das verdammt unübersichtlich wird. Die ersten zwei sollten reichen, um das Prinzip zu verstehen, und außerdem sollte da auch schon der Fehler erkennbar sein und sich in den restlichen Schleifen wiederholen.

Sollte trotzdem jemand einen Tipp für mich haben, wie ich alles in einer Schleife zusammenfassen kann, wäre ich natürlich auch dafür sehr dankbar.


----------



## pappawinni (9. Mrz 2012)

Hallo ? 
Ich hatte doch schon geschrieben:
aZugWert =+ 1;
ist eine einfache Zuweisung eines Wertes und KEIN Inkrement.
Anders gesagt, wenn du hier den Wert von aZugWert erhöhen wolltest, dann wird das nichts.
Das gleiche gilt für:
aZugWert =- 1;
Das macht das gleiche wie 
aZugWert = -1;
Du wolltest vermutlich dekrement, also
aZugWert -= 1;
Schreib da besser
aZugWert --;


----------



## Gnoccy (9. Mrz 2012)

Ok, das hätte ich vielleicht sage sollen, das habe ich schon ausprobiert, ändert aber nichts. Als ich deinen post gelesen habe, ist mir auch klar geworden, was ich da gemacht habe, aber wie gesagt, ame Ergebniss ändert sich letztendlich nichts.


----------



## truesoul (10. Mrz 2012)

Naja, alles in einer Methode packen ist schonmal eine schlechte Idee. 
Code's in Methoden auslagern. 
Sich mal Rekursion anschauen und versuchen mit Rekursion an die Sache heranzugehen. 
Sich hier im Forum mal andere Beispiele anschauen, da findest du sicherlich über die SuFu genug. 
Ansonsten Google anschmeißen. 

Java ist auch eine Insel – 2.7 Methoden einer Klasse


----------



## hüteüberhüte (10. Mrz 2012)

XHelp hat gesagt.:


> Beim Stichwort MiniMax ist man sicherlich gut aufgehoben. Es gibt auch bestimmt einige Implementierungen in Java für TicTacToe, die man sich angucken könnte.
> Aber welche Strategie da oben verwendet wird - keine Ahnung



MiniMax kannte ich auch noch nicht, aber es läuft auf eine Bewertung der Spielsituation hinaus, stimmts? Und wie sollte ein Spielsituation bewertet werden? Mir fällt bei 4Gewinnt nur gewonnen oder verloren ein. Sollte die Anzahl gleicher in einer "Reihe/Spalte/Diagonale" mit einfließen? Jedenfalls erst mal Danke für die Verlinkung. Muss das an anderer Stelle nochmal nachlesen.

Aber unabhängig davon: Nach einem MiniMax-Algorithmus sieht die "Idee" oben aber nicht aus oder?


----------



## Gnoccy (10. Mrz 2012)

Sollte aber ein MiniMax Algorithmus sein...

Naja, ich hab den ganzen Code jetzt noch mal über den Haufen geworfen und mit einem deterministischem Ansatz von vorne angefangen. Läuft auch einigermaßen, auch wenn es sicher noch Verbesserungsmöglichkeiten gibt.

Trotzdem danke an alle, die mir helfen wollten.


----------



## hüteüberhüte (10. Mrz 2012)

...wollte auch helfen, aber du kannst na nicht erwarten, dass sich das bei dieser "verschachtelung" jemand durchliest ^^


----------



## Gnoccy (11. Mrz 2012)

Jep, is mir auch klar, nur hatte ich echt keine Idee, wie ich das anders lösen sollte.
Das war auch der Grund, weshalb ich das nochmal beschrieben habe, damit man sich das nicht komplett durchlesen muss um das zu verstehen.


----------

