Problem z Kółko i krzyżyk na 36 pól i grę komputera z graczem

0
#include <iostream>

using namespace std;

// Funkcja rysuje planszę gry w kółko i krzyżyk
// Plansza przechowywana jest w tablicy t[] 
void plansza(char t[])
{
	for (int i = 1; i <= 36; i++)
	{
		cout << " " << t[i] << " ";
		if (i % 6)
			cout << "|";
		else if (i != 36)
			cout << "\n---+---+---+---+---+---\n";
		else cout << endl;
	}
}


bool win(char t[], char g, bool cisza)
{
	bool test;
	int i;

	test = false;
	for (i = 1; i <= 31; i += 6)
		test |= ((t[i] == g) && (t[i + 1] == g) && (t[i + 2] == g) && (t[i + 3] == g) && (t[i + 4] == g) && (t[i + 5] == g));
	for (i = 1; i <= 6; i++)
		test |= ((t[i] == g) && (t[i + 6] == g) && (t[i + 12] == g) && (t[i + 18] == g) && (t[i + 24] == g) && (t[i + 30] == g));
	test |= ((t[1] == g) && (t[8] == g) && (t[15] == g) && (t[22] == g) && (t[29] == g) && (t[35] == g));
	test |= ((t[6] == g) && (t[11] == g) && (t[16] == g) && (t[21] == g) && (t[26] == g) && (t[32] == g));
	if (test)
	{
		if (!cisza)
		{
			plansza(t);
			cout << "\nGRACZ " << g << " WYGRYWA!!!\n\n";
			return true;
		}
		return false;
	}
}


bool remis(char t[], bool cisza)
{ 
	for (int i = 1; i <= 36; i++) if (t[i] == ' ') return false;

	if (!cisza)
	{
		plansza(t); cout << "\nREMIS !!!\n\n";
	}
	return true;
}

// Algorytm rekurencyjny MINIMAX
// Do algorytmu wchodzimy z planszą, na której ustawione jest pole
// bieżącego gracza. Parametr gracz przekazuje literkę gracza, a
// parametr mx przekazuje jego wynik w przypadku wygranej
//----------------------------------------------------------------
int minimax(char t[], char gracz)
{
	int m, mmx;

	// Najpierw sprawdzamy, czy bieżący gracz wygrywa na planszy. Jeśli tak, to
	// zwracamy jego maksymalny wynik

	if (win(t, gracz, true)) return (gracz == 'X') ? 1 : -1;

	// Następnie sprawdzamy, czy nie ma remisu. Jeśli jest, zwracamy wynik 0

	if (remis(t, true)) return 0;

	// Będziemy analizować możliwe posunięcia przeciwnika. Zmieniamy zatem
	// bieżącego gracza na jego przeciwnika

	gracz = (gracz == 'X') ? 'O' : 'X';

	// Algorytm MINIMAX w kolejnych wywołaniach rekurencyjnych naprzemiennie analizuje
	// grę gracza oraz jego przeciwnika. Dla gracza oblicza maksimum wyniku gry, a dla
	// przeciwnika oblicza minimum. Wartość mmx ustawiamy w zależności od tego, czyje
	// ruchy analizujemy:
	// X - liczymy max, zatem mmx <- -10
	// O - liczymy min, zatem mmx <-  10

	mmx = (gracz == 'O') ? 10 : -10;

	// Przeglądamy planszę szukając wolnych pół na ruch gracza. Na wolnym polu ustawiamy
	// literkę gracza i wyznaczamy wartość tego ruchu rekurencyjnym wywołaniem
	// algorytmu MINIMAX. Planszę przywracamy i w zależności kto gra:
	// X - wyznaczamy maximum
	// O - wyznaczamy minimum

	for (int i = 1; i <= 36; i++)
		if (t[i] == ' ')
		{
			t[i] = gracz;
			m = minimax(t, gracz);
			t[i] = ' ';
			if (((gracz == 'O') && (m < mmx)) || ((gracz == 'X') && (m > mmx))) mmx = m;
		}
	return mmx;
}

// Funkcja wyznacza ruch dla komputera.
int komputer(char t[])
{
	int ruch, i, m, mmx;

	mmx = -10;
	for (i = 1; i <= 36; i++)
		if (t[i] == ' ')
		{
			t[i] = 'X';
			m = minimax(t, 'X');
			t[i] = ' ';
			if (m > mmx)
			{
				mmx = m; ruch = i;
			}
		}
	return ruch;
}

// Funkcja umożliwia ruch gracza
// Po ruchu następuje zamiana gracza
void ruch(char t[], char &gracz)
{
	int r;

	plansza(t);
	if (gracz == 'O')
	{
		cout << "\nCZLOWIEK : wybiera ruch : ";
		cin >> r;
	}
	else
	{
		r = komputer(t);
		cout << "\nKOMPUTER : wybiera ruch : " << r << endl;
	}
	cout << "---------------------------\n\n";
	if ((r >= 1) && (r <= 36) && (t[r] == ' ')) t[r] = gracz;
	gracz = (gracz == 'O') ? 'X' : 'O';
}

int main()
{
	char t[10], gracz, wybor;

	do
	{
		cout << "Gra w Kolko i Krzyzyk dla gracza i komputera\n"
			"============================================\n\n";
		for (int i = 1; i <= 36; i++) t[i] = ' ';
		gracz = 'O';

		while (!win(t, 'X', false) && !win(t, 'O', false) && !remis(t, false)) ruch(t, gracz);

		cout << "Jeszcze raz ? (T = TAK) : ";
		cin >> wybor;
		cout << "\n\n\n";

	} while ((wybor == 'T') || (wybor == 't'));
	
}
0

No i?

0

no i nie działa po pierwszym ruchu nie da się nic zrobić

1

Debugger do ręki i patrz, gdzie się zatrzymuje. Masz trochę zbyt skomplikowany kod do statycznej analizy…

0

Problem w tym że program się odpala i po pierwszym ruchu się freezuje i muszę zamknąć konsole

2

pewnie minmax mieli i mieli bo nie ograniczyłeś głębokości rekurencji.
na dodatek nie ma zrobionej optymalizacji, w której dany układ nie będzie analizowany wielokrotnie (do tego samego układu można dojść na wiele sposobów).

1

Z funkcją remis poszedłeś na łatwiznę, bo już poniższy układ doprowadzi do remisu, choć część pól jest pusta:
x*---x
-x*---
--x*--
---x*-
----*x
*---x*
W tym układzie nie ma żadnego ruchu, który dawałby zwycięstwo a jednocześnie nie osiągasz Twojego warunku remisu, w którym każde pole musi mieć symbol gracza.
Być może to jest powód, że algorytm kręci się w kółko bo żadna ze stron nie jest w stanie wygrać, a jednocześnie nie osiąga remisu.

1

A teraz krytyka kodu:

  • funkcje powinny mieć nazwę zawierającą czasownik (w końcu coś robią)
  • zmienne powinny być rzeczownikami
  • gorsze od pisania kodu po polsku jest pisanie równocześnie po polsku i angielsku - pisz po angielsku
  • od groma liczb magicznych.
  • niby korzystasz z C++ a piszesz tak jakby to było C
  • części minmax-a nie powinny niczego wypisywać!
  • wiele innych rzeczy mniej ważnych

1 użytkowników online, w tym zalogowanych: 0, gości: 1