namespace ReversiSilnik { public struct WspółrzędnePola { public int Poziomo, Pionowo; public WspółrzędnePola(int poziomo, int pionowo) { this.Poziomo = poziomo; this.Pionowo = pionowo; } public string SymbolPola { get { if (Poziomo > 25 || Pionowo > 8) return "(" + Poziomo.ToString() + "," + Pionowo.ToString() + ")"; return "" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[Poziomo] + "123456789"[Pionowo]; } } } public class ReversiSilnik { public int SzerokośćPlanszy { get; private set; } public int WysokośćPlanszy { get; private set; } private int[,] plansza; public int NumerGraczaWykonującegoNastępnyRuch { get; private set; } = 1; private static int numerPrzeciwnika(int numerGracza) { return (numerGracza == 1) ? 2 : 1; } private bool czyWspółrzędnePolaPrawidłowe(WspółrzędnePola współrzędnePola) { return współrzędnePola.Poziomo >= 0 && współrzędnePola.Poziomo < SzerokośćPlanszy && współrzędnePola.Pionowo >= 0 && współrzędnePola.Pionowo < WysokośćPlanszy; } public int PobierzStanPola(WspółrzędnePola współrzędnePola) { if (!czyWspółrzędnePolaPrawidłowe(współrzędnePola)) throw new Exception("Nieprawidłowe współrzędne pola"); return plansza[współrzędnePola.Poziomo, współrzędnePola.Pionowo]; } private void czyśćPlanszę() { for (int i = 0; i < SzerokośćPlanszy; i++) for (int j = 0; j < WysokośćPlanszy; j++) plansza[i, j] = 0; int srodekSzer = SzerokośćPlanszy / 2; int srodekWys = WysokośćPlanszy / 2; plansza[srodekSzer - 1, srodekWys - 1] = plansza[srodekSzer, srodekWys] = 1; plansza[srodekSzer - 1, srodekWys] = plansza[srodekSzer, srodekWys - 1] = 2; } public ReversiSilnik(int numerGraczaRozpoczynającego, int szerokośćPlanszy = 8, int wysokośćPlanszy = 8) { if (numerGraczaRozpoczynającego < 1 || numerGraczaRozpoczynającego > 2) throw new Exception("Nieprawidłowy numer gracza rozpoczynającego grę"); SzerokośćPlanszy = szerokośćPlanszy; WysokośćPlanszy = wysokośćPlanszy; plansza = new int[SzerokośćPlanszy, WysokośćPlanszy]; czyśćPlanszę(); obliczLiczbyPól(); NumerGraczaWykonującegoNastępnyRuch = numerGraczaRozpoczynającego; } private void zmieńBieżącegoGracza() { NumerGraczaWykonującegoNastępnyRuch = numerPrzeciwnika(NumerGraczaWykonującegoNastępnyRuch); } private WspółrzędnePola? skanujPolaWKierunku(WspółrzędnePola współrzędnePola, int kierunekPoziomo, int kierunekPionowo) { //szukanie kamieni gracza w jednym z 8 kierunków int poziomo = współrzędnePola.Poziomo; int pionowo = współrzędnePola.Pionowo; bool znalezionyKamieńPrzeciwnika = false; bool znalezionyKamieńGraczaWykonującegoRuch = false; bool znalezionePustePole = false; bool osiągniętaKrawędźPlanszy = false; do { poziomo += kierunekPoziomo; pionowo += kierunekPionowo; WspółrzędnePola _współrzędnePola = new WspółrzędnePola(poziomo, pionowo); if (!czyWspółrzędnePolaPrawidłowe(_współrzędnePola)) osiągniętaKrawędźPlanszy = true; if (!osiągniętaKrawędźPlanszy) { if (plansza[poziomo, pionowo] == NumerGraczaWykonującegoNastępnyRuch) znalezionyKamieńGraczaWykonującegoRuch = true; if (plansza[poziomo, pionowo] == 0) znalezionePustePole = true; if (plansza[poziomo, pionowo] == numerPrzeciwnika(NumerGraczaWykonującegoNastępnyRuch)) znalezionyKamieńPrzeciwnika = true; } } while (!(osiągniętaKrawędźPlanszy || znalezionyKamieńGraczaWykonującegoRuch || znalezionePustePole)); //sprawdzenie warunku poprawności ruchu bool położenieKamieniaJestMożliwe = znalezionyKamieńPrzeciwnika && znalezionyKamieńGraczaWykonującegoRuch && !znalezionePustePole; return położenieKamieniaJestMożliwe ? new WspółrzędnePola(poziomo, pionowo) : null; } protected int połóżKamień(WspółrzędnePola współrzędnePola, bool tylkoTest) { //czy współrzędne są prawidłowe? if (!czyWspółrzędnePolaPrawidłowe(współrzędnePola)) throw new Exception("Nieprawidłowe współrzędne pola"); //czy pole nie jest już zajęte? if (plansza[współrzędnePola.Poziomo, współrzędnePola.Pionowo] != 0) return -1; int ilePólPrzejętych = 0; //pętla po 8 kierunkach for (int kierunekPoziomo = -1; kierunekPoziomo <= 1; kierunekPoziomo++) for (int kierunekPionowo = -1; kierunekPionowo <= 1; kierunekPionowo++) { //wymuszenie pominięcia przypadku, gdy obie zmienne są równe 0 if (kierunekPoziomo == 0 && kierunekPionowo == 0) continue; //skanowanie we wskazanym kierunku WspółrzędnePola? znalezioneWspółrzednePola = skanujPolaWKierunku(współrzędnePola, kierunekPoziomo, kierunekPionowo); //"odwrócenie" kamieni w przypadku spełnionego warunku if (znalezioneWspółrzednePola.HasValue) { int maks_indeks = Math.Max( Math.Abs(znalezioneWspółrzednePola.Value.Poziomo - współrzędnePola.Poziomo), Math.Abs(znalezioneWspółrzednePola.Value.Pionowo - współrzędnePola.Pionowo)); if (!tylkoTest) { for (int indeks = 0; indeks < maks_indeks; indeks++) plansza[współrzędnePola.Poziomo + indeks * kierunekPoziomo, współrzędnePola.Pionowo + indeks * kierunekPionowo] = NumerGraczaWykonującegoNastępnyRuch; } ilePólPrzejętych += maks_indeks - 1; } } //koniec pętli po kierunkach //zmiana gracza, jeżeli ruch został wykonany if (ilePólPrzejętych > 0 && !tylkoTest) { zmieńBieżącegoGracza(); obliczLiczbyPól(); } //zmienna ilePólPrzejętych nie uwzględnia dostawionego kamienia return ilePólPrzejętych; } public bool PołóżKamień(WspółrzędnePola współrzędnePola) { return połóżKamień(współrzędnePola, false) > 0; } public bool CzyMożnaPołożyćKamień(WspółrzędnePola współrzędnePola) { return połóżKamień(współrzędnePola, true) > 0; } private int[] liczbyPól = new int[3]; //puste, gracz 1, gracz 2 private void obliczLiczbyPól() { for (int i = 0; i < liczbyPól.Length; ++i) liczbyPól[i] = 0; for (int poziomo = 0; poziomo < SzerokośćPlanszy; ++poziomo) for (int pionowo = 0; pionowo < WysokośćPlanszy; ++pionowo) liczbyPól[plansza[poziomo, pionowo]]++; } public int LiczbaPustychPól { get => liczbyPól[0]; } public int LiczbaPólGracz1 { get => liczbyPól[1]; } public int LiczbaPólGracz2 { get => liczbyPól[2]; } private bool czyBieżącyGraczMożeWykonaćRuch() { for (int poziomo = 0; poziomo < SzerokośćPlanszy; ++poziomo) for (int pionowo = 0; pionowo < WysokośćPlanszy; ++pionowo) { WspółrzędnePola _współrzędnePola = new WspółrzędnePola(poziomo, pionowo); if (plansza[poziomo, pionowo] == 0 && CzyMożnaPołożyćKamień(_współrzędnePola)) return true; } return false; } public void Pasuj() { if (czyBieżącyGraczMożeWykonaćRuch()) throw new Exception("Gracz nie może oddać ruchu, jeżeli wykonanie ruchu jest możliwe"); zmieńBieżącegoGracza(); } public enum SytuacjaNaPlanszy { RuchJestMożliwy, BieżącyGraczNieMożeWykonaćRuchu, ObajGraczeNieMogąWykonaćRuchu, WszystkiePolaPlanszySąZajęte } public SytuacjaNaPlanszy ZbadajSytuacjęNaPlanszy() { if (LiczbaPustychPól == 0) return SytuacjaNaPlanszy.WszystkiePolaPlanszySąZajęte; //badanie możliwości ruchu bieżącego gracza bool czyMożliwyRuch = czyBieżącyGraczMożeWykonaćRuch(); if (czyMożliwyRuch) return SytuacjaNaPlanszy.RuchJestMożliwy; else { //badanie możliwości ruchu przeciwnika zmieńBieżącegoGracza(); bool czyMożliwyRuchOponenta = czyBieżącyGraczMożeWykonaćRuch(); zmieńBieżącegoGracza(); if (czyMożliwyRuchOponenta) return SytuacjaNaPlanszy.BieżącyGraczNieMożeWykonaćRuchu; else return SytuacjaNaPlanszy.ObajGraczeNieMogąWykonaćRuchu; } } public int NumerGraczaMającegoPrzewagę { get { if (LiczbaPólGracz1 == LiczbaPólGracz2) return 0; else return (LiczbaPólGracz1 > LiczbaPólGracz2) ? 1 : 2; } } } }