Wie kann ich für ein dynamisches Vier gewinnt eine Gewinnabfrage erstellen?
Hallo,
ich frage mich, wie ich für ein dynamisches Vier gewinnt eine Gewinnabfrage erstellen kann.
Mein aktueller Code (ohne Klassen für Grafik) sieht so aus:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Windows.Threading;
namespace N_Gewinnt_Mölleken
{
public partial class MainWindow : Window
{
Linie linie;
Chip chip;
private bool isHorizontalMoveEnabled = true;
int anzahlspalten = 40;
int anzahlzeilen = 9;
int BallColor = 1;
int GewinnMenge = 4;
DispatcherTimer timer;
Double ticks_old;
int Spieler = 1;
Double BRadius;
Double BallX;
Double AktuellX = 0;
int NichtAus;
private bool isLeftKeyPressed = false;
private bool isRightKeyPressed = false;
int count = 0;
int[,] BallPosition;
public MainWindow()
{
InitializeComponent();
BallPosition = new int[anzahlspalten, anzahlzeilen];
}
private void wnd_Loaded(object sender, RoutedEventArgs e)
{
this.WindowState = WindowState.Maximized;
InitializeGame();
}
private void InitializeGame()
{
timer = new DispatcherTimer();
timer.Tick += timer_Tick;
timer.Interval = new TimeSpan(0, 0, 0, 0, 15);
timer.Start();
double screenwidth = SystemParameters.PrimaryScreenWidth;
double screenheight = SystemParameters.PrimaryScreenHeight;
double x1 = screenwidth - (screenwidth * 0.3), y1 = screenheight - (screenheight * 0.10), x2 = x1, y2 = screenheight - (screenheight * 0.9);
for (int spalten = 0; spalten <= anzahlspalten; spalten++)
{
linie = new Linie(x1, y1, x2, y2);
linie.Draw(cvs);
x1 -= ((screenwidth - (screenwidth * 0.3)) / anzahlspalten);
x2 = x1;
}
linie = new Linie(screenwidth * 0.7, screenheight * 0.9, x1 + ((screenwidth - (screenwidth * 0.3)) / anzahlspalten), screenheight * 0.9);
linie.Draw(cvs);
BRadius = ((screenwidth - 4 - (screenwidth * 0.3)) / anzahlspalten) / 2;
BallX = ((screenwidth - (screenwidth * 0.3)) / anzahlspalten) / 2;
chip = new Chip(BallX, 130, BRadius, 0, 0, Spieler);
chip.Draw(cvs);
}
private void timer_Tick(object sender, EventArgs e)
{
Double ticks = Environment.TickCount;
if (ticks_old == 0)
{
ticks_old = ticks;
return;
}
double elapsed = (ticks - ticks_old);
ticks_old = ticks;
}
private void wnd_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Left)
{
MoveBallLeft();
}
else if (e.Key == Key.Right)
{
MoveBallRight();
}
if (e.Key == Key.Down)
{
MoveBallDown();
}
}
private void MoveBallRight()
{
if (isHorizontalMoveEnabled && count < anzahlspalten - 1)
{
AktuellX = AktuellX + BallX;
Canvas.SetLeft(chip.Elli, AktuellX * 2);
count += 1;
}
}
private void MoveBallLeft()
{
if (isHorizontalMoveEnabled && count > 0)
{
AktuellX = AktuellX - BallX;
Canvas.SetLeft(chip.Elli, AktuellX * 2);
count -= 1;
}
}
// ...
private void MoveBallDown()
{
NichtAus = 0;
for (int i = 0; i < anzahlzeilen; i++)
{
if (BallPosition[count, i] == 0)
{
BallPosition[count, i] = Spieler;
// Logik für die Darstellung des Chips
MessageBox.Show("ChipPlatziert");
NichtAus = 1;
MessageBox.Show($"Chip an Position ({count}, {i}) platziert. Wert im Array: {BallPosition[count, i]}");
break;
}
MessageBox.Show("EineZeileBlockiert");
}
if (NichtAus == 0)
{
MessageBox.Show("Sie können in dieser Zeile nicht platzieren");
}
if (Spieler == 1)
{
Spieler = -1;
}
else if (Spieler == -1)
{
Spieler = 1;
}
}
}
}
1 Antwort
![](https://images.gutefrage.net/media/user/tide1109/1568022372988_nmmslarge__1179_667_2597_2597_5d90cc1a685fa94406cd63e940354bf2.jpg?v=1568022373000)
int anzahlspalten = 40;
int anzahlzeilen = 9;
int[,] BallPosition; // = new int[anzahlspalten, anzahlzeilen];
int GewinnMenge = 4;
Das sind soweit die wichtigen Zeilen, die du für die Siegabfrage benötigst.
BallPosition wird bestimmt die Matrix sein, die den aktuellen Spielstand hält. Ich nehme an, dass der Wert 0 frei bedeutet und 1 bzw. 2 für Spieler 1 bzw. Spieler 2 steht.
Ich habe es zwar nicht getestet, aber für den vertikalen Sieg müsste folgende Funktion das Ergebnis zurückliefern:
public int istSiegerVertikal() {
for (int i = 0; i < anzahlspalten; i++) {
int counter = 0;
int previousState = 0;
for (int j = 0; j < anzahlzeilen; j++) {
int currentState = BallPosition[i][j];
// Feld leer, dann setze Bälle in Folge auf 0
if (currentState == 0) {
counter = 0;
} else {
// Wenn der aktuelle Zustand gleich dem vorherigen Zustand ist, dann erhöhe den Counter.
// Ansonsten fange für anderen Spieler bei 1 an
if (currentState == previousState) {
counter++;
} else {
counter = 1;
}
}
// Wenn GewinnMenge erreicht, dann hat der Spieler gewonnen
if (counter == GewinnMenge) {
return currentState;
}
previousState = currentState;
}
}
// Es wurde kein Sieger gefunden
return 0;
}
Ich habe es in Java umgesetzt, aber die Sprachen sind sehr ähnlich. Vielleicht musst du sogar nichts verändern.
Für Waagerecht musst du die Schleifen umdrehen, sodass du zuerst durch die Spalten gehst und danach durch die Zeilen.
In der einen Richtung für Diagional sollte dieser Code funktionieren:
public int isSiegerDiagonalTeil1() {
for (int iStart = 0; iStart < anzahlspalten - GewinnMenge; iStart++) {
for (int jStart = 0; jStart < anzahlzeilen - GewinnMenge; jStart++) {
int counter = 0;
int previousState = 0;
for (int i = iStart, j = jStart; i < anzahlspalten && j < anzahlzeilen; i++, j++) {
int currentState = BallPosition[i][j];
// Feld leer, dann setze Bälle in Folge auf 0
if (currentState == 0) {
counter = 0;
} else {
// Wenn der aktuelle Zustand gleich dem vorherigen Zustand ist, dann erhöhe den Counter.
// Ansonsten fange für anderen Spieler bei 1 an
if (currentState == previousState) {
counter++;
} else {
counter = 1;
}
}
// Wenn GewinnMenge erreicht, dann hat der Spieler gewonnen
if (counter == GewinnMenge) {
return currentState;
}
previousState = currentState;
}
}
}
return 0;
}
Es ist definitiv nicht die effizienteste Lösung sein, da er einige Spalten doppelt überprüfen wird. Da kannst du noch eine effizientere Lösung finden.
Dann musst du diese Diagonale Überprüfung auch in der anderen Richtung ausführen. Dazu musst du in der innersten for Schleife i oder j beim maximal möglichen Wert starten lassen und pro Iteration herunterzählen (z.B. i--).
Beim Zusammensetzen führst du alle 4 Varianten zum Gewinnen nacheinander aus. Wenn bereits eine 1 bzw. 2 für ein Sieg zurückgegeben wurde, kannst du direkt abbrechen und den Sieger verkünden. Falls durch eine 0 kein Sieger gefunden wurde, musst du die nächste Variante ausführen. Falls nach der vierten Variante wieder ein 0 kommt, hat einfach noch keiner gewonnen.
Teste den Code vorher auf jeden Fall nochmal!
Ich habe auch Java genutzt, welches sehr ähnlich zu C# ist. Das Konzept solltest du auf jeden Fall verstehen. Copy & Paste könnte mit eventuell leichten Anpassungen möglich sein.
Vor allem für den Diagonalen Weg lassen sich bestimmt noch bessere Algorithmen finden, die effizienter sind.
![](https://images.gutefrage.net/media/default/user/13_nmmslarge.png?v=1551279448000)
Korrektur, ich habe einfach nur ein else vergessen... also doch keine probleme, danke bei der hilfe xD
Danke erstmal, aktuell habe ich eine ähnliche Lösung mit dem Gedankengang, von dem aktuell platzierten Chip in jede Richtung zu gucken, ob nebenan noch andere Chips der selben Farbe liegen, allerdings treten ein paar komische logik fehler auf, hier ein beispiel:
private void CheckHorizontal(int YPosBall)
{
//funktioniert nicht (abfrage nach rechts falsch)
for (int i = 0; i <= GewinnMenge; i++)
{
try
{
if (BallPosition[count - i, YPosBall] == Spieler)
{
gewinnabfrage++;
}
{
break;
}
}
catch (Exception e)
{
}
}
//funktioniert (abfrage nach links richtig)
for (int i = 0; i <= GewinnMenge; i++)
{
try
{
if (BallPosition[count + i, YPosBall] == Spieler)
{
gewinnabfrage++;
}
else
{
break;
}
}
catch (Exception e)
{
}
}
Ich denke, dass dieser lösungsansatz effizienter ist, wobei ich jedoch probleme bei der umsetzung habe