Windows Forms – 3 i rad

Inledning

3 i rad eller "Tic Tac Toe" som det kallas på engelska är en klassisk programmeringsuppgift. Vi tänker här presentera en lösning i Windows Forms där vi använder befintliga komponenter.

Man skulle kunna kalla artikeln för "Tic Tac Toe" på 10 minuter om man så vill.

bild

Regler

Vi har nog alla spelat 3 i rad någon gång. Den som först får 3 i rad vinner! Detta kan ske på 8 olika sätt eftersom det finns 3 kolumner, 3 rader och 2 diagonaler.

Traditionellt sett spelar man "O" eller "X".

Implementation

Vi tänker oss en spelplan utav 3 x 3 Button-komponenter. Knapparna har ingen text förrän spelare "X" eller "O" trycker på dem.

Varje knapptryckning genererar ett Click-event som vi kopplar. Alla 9 knappar är kopplade till samma metod, dvs. alla knappar behandlas lika.

Den som "lägger en bricka" på spelplanen, alltså trycker på en knapp, är också den som kan vinna. Vi måste kolla alla kolumner, rader och diagonaler och se om denna spelare har 3 i rad. Om så är fallet så notifierar vi via MessageBox samt nollställer brädet. Det kan också vara så att ingen vunnit. I detta fall bör vi också notifiera samt nollställa brädet.

Det intressanta med implementationen är hur vi bearbetar data, dvs. Button-komponenterna. För att systematiskt bearbeta informationen om "X" eller "O" så väljer vi att lägga knapparna i en 2-dimensionell "array" (fält på svenska). Två dimensioner passar bra då vi får en bredd och en höjd som motsvarar brädets 3 x 3 knappar. Det kan tyckas en aning krångligt men en anledning till att göra på detta vis är att vi mycket lättare kan gå från ett 3 x 3 bräde till t.ex. ett 8 x 8 bräde.

Känner du dig osäker på fält så rekommenderas att först läsa Fält (array).

Video

Vi rekommenderar att se videon, i alla fall de första minuterna, för att hänga med på vilka ändringar som gjorts i den visuella editorn i Visual Studio.

Kod

Tic Tac Toe

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TicTacToe
{
    public partial class Form1 : Form
    {
        bool XTurn = false;

        Button[,] array;

        public Form1()
        {
            InitializeComponent();

            array = new Button[,] { {button1, button2, button3 },
                                    {button4, button5, button6 },
                                    {button7, button8, button9 }};
        }

        private void ResetBoard()
        {
            int size = array.GetLength(0);

            for (int x = 0; x < size; x++)
            {
                for (int y = 0; y < size; y++)
                {
                    array[y, x].Text = string.Empty;
                }
            }
        }

        private void Button_Click(object sender, EventArgs e)
        {
            Button b = sender as Button;
            if (b == null || !string.IsNullOrEmpty(b.Text))
                return;

            string player = (XTurn) ? "X" : "O";
            b.Text = player;

            XTurn = !XTurn;

            int size = array.GetLength(0);
            
            //Kolla om någon vann!
            //kolumner
            for (int x = 0; x < size; x++)
            {
                for (int y = 0; y < size && array[y, x].Text == player; y++)
                {
                    if (y == size - 1)
                    {
                        MessageBox.Show(this, "Player " + player + " won!");
                        ResetBoard();
                    }
                }
            }

            //rader
            for (int y = 0; y < size; y++)
            {
                for (int x = 0; x < size && array[y, x].Text == player; x++)
                {
                    if (x == size - 1)
                    {
                        MessageBox.Show(this, "Player " + player + " won!");
                        ResetBoard();
                    }
                }
            }

            //Diagonal 1
            for (int i = 0; i < size && array[i, i].Text == player; i++)
            {
                if (i == size - 1)
                {
                    MessageBox.Show(this, "Player " + player + " won!");
                    ResetBoard();
                }
            }

            //Diagonal 2
            for (int i = 0; i < size && array[size - 1 - i, i].Text == player; i++)
            {
                if (i == size - 1)
                {
                    MessageBox.Show(this, "Player " + player + " won!");
                    ResetBoard();
                }
            }

            //Spelet slut?
            bool finished = true;

            for (int x = 0; x < size; x++)
            {
                for (int y = 0; y < size; y++)
                {
                    if (string.IsNullOrEmpty(array[y, x].Text))
                        finished = false;
                }
            }

            if (finished)
            {
                MessageBox.Show(this, "It's a draw!");
                ResetBoard();
            }
        }
    }
}

Övning 1

I exemplet ovan så är alla 9 knappar utplacerade manuellt. Detta är inte särskilt effektivt ifall vi vill utöka storleken på brädet.

Uppgiften går ut på att istället skapa de 9 knapparna i kod. Du måste alltså ställa in alla egenskaper som t.ex. storlek, bakgrundsfärg, Click-event, etc. Använd en loop som baseras på storleken.

Övning 2

Gör så att du kan ställa in storleken på brädet via en variabel i koden. Anpassa gärna storleken på knapparna samt storleken på typsnittet efter storleken på brädet.

Inför också en variabel som bestämmer "hur många i rad" som krävs för att vinna.

Du måste alltså justera algoritmerna för att bestämma vinnaren.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *

Scroll to top