// Deze methode tovert een klik op de form om in een klik op plek (x,y) in het speelveld // Dit doen we door de array af te gaan en te checken of de muis in die bepaalde plek zit private void klik(object o, MouseEventArgs mea) { for (int x = 0; x < gamestate.SizeX; x++) { for (int y = 0; y < gamestate.SizeY; y++) { // De volgende conditie vraagt of de muis zich in vakje (x,y) bevindt. if (mea.X > xstart + diam * x && mea.X <= xstart + diam * (x + 1) && mea.Y > ystart + diam * y && mea.Y <= ystart + diam * (y + 1)) { // Als we hier zijn, hebben we het vakje gevonden waar de muis klikte! if (gamestate.Read(x, y) == 1 || gamestate.Read(x, y) == -1) { return; // Doe niets als er al een bolletje in dat vakje zit } if (ReversiFuncties.MagMove(gamestate, x, y)) // Als de zet geldig is, ga de gamestate dan updaten { ReversiFuncties.UpdateGamestate(ref gamestate, x, y); this.Invalidate(); while (NewGameForm.vsai == true && gamestate.WiensBeurt == -1 && gamestate.LastTurn == false) { gamestate = MinMax.GeefBesteMove(ref gamestate, 4); this.Invalidate(); } } else { return; // Zo niet, doe niets. } } } } }
// Deze methode geeft alle mogelijke zetten gegeven een array van toekomstige gamestates, gegeven de huidige gamestate public static GameState[] MogelijkeMoves(GameState gamestate) { // Dit doen we door een array te maken en op iedere mogelijke plek een zet te proberen, en als een zet mag, // dan voegen we de vernieuwde gamestate toe aan gamearr GameState[] gamearr = new GameState[gamestate.SizeX * gamestate.SizeY]; int k = 0; for (int i = 0; i < gamestate.SizeX; i++) { for (int j = 0; j < gamestate.SizeY; j++) { if (ReversiFuncties.MagMove(gamestate, i, j)) { GameState gamevar = new GameState(gamestate.SizeX, gamestate.SizeY); gamearr[k] = new GameState(gamestate.SizeX, gamestate.SizeY); gamevar.statearray = gamestate.statearray; gamevar.WiensBeurt = gamestate.WiensBeurt; ReversiFuncties.UpdateGamestate(ref gamevar, i, j); gamearr[k] = gamevar; k++; } } } if (k == 0) { GameState[] arr = new GameState[1]; arr[0] = new GameState(gamestate.SizeX, gamestate.SizeY); return(arr); } // Nu zijn er nog een heleboel plekken in de gamearr niet geïnitialiseerd (omdat daar geen move mogelijk was) // Dus die verwijderen we en maken een nieuwe array aan met de juiste grootte int l = 0; while (gamearr[l].statearray != null) { l++; } GameState[] gamearrcopy = gamearr; // Normaal zou dit een reference maken, maar dit is voorkomen door de set-minimethode in de struct Gamestate gamearr = new GameState[l]; for (int i = 0; i < k; i++) { gamearr[i] = gamearrcopy[i]; } return(gamearr); }
// Deze methode gebruiken we buiten deze klasse om de beste move (die de computer kan vinden) te zetten // Dit doen we door de boom te maken van diepte depth vanaf de huidige gamestate en dan te scoren. // De beste move wordt dan als nieuwe gamestate teruggegeven public static GameState GeefBesteMove(ref GameState gamestate, int depth) { Tree boom = GeefBoom(gamestate, depth); GameState state = BestMove(boom, gamestate.WiensBeurt); for (int i = 0; i < gamestate.SizeX; i++) { for (int j = 0; j < gamestate.SizeY; j++) { if (gamestate.statearray[i, j] != state.statearray[i, j] && gamestate.statearray[i, j] == 0) { ReversiFuncties.UpdateGamestate(ref gamestate, i, j); return(gamestate); } } } return(state); }
// Dit is waar het speelveld wordt getekend // We tekenen het veld en alle stenen in dezelfde dubbele for-loop. (het klinkt inefficiënt om iedere // keer het bord en alle stenen opnieuw te tekenen, maar het kost zo weinig rekenkracht dat het (bijna) niet merkbaar is, // zeker met DoubleBuffered = true;. Daarnaast kost dit het minste regels code) private void teken(object o, PaintEventArgs pea) { // De grootte van de form wordt aangepast aan grootte van spel this.ClientSize = new Size(120 + diam * gamestate.SizeX, 180 + diam * gamestate.SizeY); Graphics g = pea.Graphics; g.FillEllipse(Brushes.Red, 45, 50, diam, diam); // Dit is om het er leuker g.FillEllipse(Brushes.Blue, 45, 80, diam, diam); // uit te laten zien // In de volgende forloops lopen we ieder vakje na om te tekenen én om te tellen. gamestate.RoodN = 0; gamestate.BlauwN = 0; for (int x = 0; x < gamestate.SizeX; x++) { for (int y = 0; y < gamestate.SizeY; y++) { // Nu zijn we op plek (x,y) op het bord. Rectangle rect = new Rectangle(xstart + diam * x, ystart + diam * y, diam, diam); Rectangle rectsmall = new Rectangle(xstart + diam * x + 3, ystart + diam * y + 3, diam - 6, diam - 6); pea.Graphics.DrawRectangle(Pens.Black, rect); // Nu tekenen we het bord afhankelijk van de gamestate (0 = leeg, 1 = blauw, -1 = rood) if (gamestate.Read(x, y) == 0) { } else if (gamestate.Read(x, y) == 1) { g.FillEllipse(Brushes.Blue, rect); gamestate.BlauwN++; } // teken blauw en tel één op bij BlauwN else if (gamestate.Read(x, y) == -1) { g.FillEllipse(Brushes.Red, rect); gamestate.RoodN++; } // teken rood en tel één op bij RoodN else { new ErrorForm("Deze melding zou nooit zichtbaar moeten zijn, gamestate moet altijd -1, 0 of 1 zijn"); } // Nu gaan we ook afhankelijk van of helpshown == true hier tekenen als dit vakje een mogelijke zet is. if (ReversiFuncties.MagMove(gamestate, x, y) && gamestate.WiensBeurt == 1 && helpshown) { g.FillEllipse(Brushes.LightSkyBlue, rect); } else if (ReversiFuncties.MagMove(gamestate, x, y) && gamestate.WiensBeurt == -1 && helpshown) { g.FillEllipse(Brushes.LightSalmon, rect); } } } roodl.Text = gamestate.RoodN + " stenen"; blauwl.Text = gamestate.BlauwN + " stenen"; if (gamestate.LastTurn) { if (gamestate.BlauwN > gamestate.RoodN) { beurtl.Text = "Blauw heeft gewonnen!"; beurtl.ForeColor = Color.Blue; } else if (gamestate.BlauwN < gamestate.RoodN) { beurtl.Text = "Rood heeft gewonnen!"; beurtl.ForeColor = Color.Red; } else { beurtl.Text = "Remise!"; beurtl.ForeColor = Color.Black; } return; } // Als laatste wordt nog even de tekst van wie er aan de beurt is omgewisseld. (als gamestate.LastTurn == false) if (gamestate.WiensBeurt == 1) { beurtl.Text = "Blauw is aan zet"; beurtl.ForeColor = Color.Blue; } else { beurtl.Text = "Rood is aan zet"; beurtl.ForeColor = Color.Red; } }