complete, step before doing ai

This commit is contained in:
maxwes08
2025-10-14 10:40:53 +02:00
parent 3a2ffc69f0
commit 6662b92891
5 changed files with 515 additions and 39 deletions

56
Box.cs Normal file
View File

@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace TicTacToe
{
public class Box
{
public Action<int> Pressed;
public int Index;
public bool BotOwned = false;
private Button _button;
public bool Filled = false;
public Box(Button button, int index)
{
_button = button;
Index = index;
button.Click += Clicked;
_button.Text = "";
}
private void Clicked(object sender, EventArgs e)
{
Pressed.Invoke(Index);
}
public void Destroy()
{
_button.Text = "";
_button.Click -= Clicked;
}
public void SetEnabled(bool value)
{
_button.Enabled = value;
}
public void PlayerClaim(bool bot)
{
Filled = true;
BotOwned = bot;
if (bot)
{
_button.Text = "O";
}
else
{
_button.Text = "X";
}
}
}
}

222
Form1.Designer.cs generated
View File

@@ -28,12 +28,226 @@
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Text = "Form1";
menuStrip1 = new MenuStrip();
fileToolStripMenuItem = new ToolStripMenuItem();
newGameToolStripMenuItem = new ToolStripMenuItem();
exitToolStripMenuItem = new ToolStripMenuItem();
helpToolStripMenuItem = new ToolStripMenuItem();
aboutToolStripMenuItem = new ToolStripMenuItem();
lbl_wins = new Label();
grid_7 = new Button();
grid_4 = new Button();
grid_1 = new Button();
grid_2 = new Button();
grid_5 = new Button();
grid_8 = new Button();
grid_0 = new Button();
grid_3 = new Button();
grid_6 = new Button();
lbl_loses = new Label();
menuStrip1.SuspendLayout();
SuspendLayout();
//
// menuStrip1
//
menuStrip1.ImageScalingSize = new Size(24, 24);
menuStrip1.Items.AddRange(new ToolStripItem[] { fileToolStripMenuItem, helpToolStripMenuItem });
menuStrip1.Location = new Point(0, 0);
menuStrip1.Name = "menuStrip1";
menuStrip1.Size = new Size(800, 33);
menuStrip1.TabIndex = 3;
menuStrip1.Text = "menuStrip1";
//
// fileToolStripMenuItem
//
fileToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { newGameToolStripMenuItem, exitToolStripMenuItem });
fileToolStripMenuItem.Name = "fileToolStripMenuItem";
fileToolStripMenuItem.Size = new Size(54, 29);
fileToolStripMenuItem.Text = "File";
//
// newGameToolStripMenuItem
//
newGameToolStripMenuItem.Name = "newGameToolStripMenuItem";
newGameToolStripMenuItem.Size = new Size(270, 34);
newGameToolStripMenuItem.Text = "New game";
//
// exitToolStripMenuItem
//
exitToolStripMenuItem.Name = "exitToolStripMenuItem";
exitToolStripMenuItem.Size = new Size(270, 34);
exitToolStripMenuItem.Text = "Exit";
//
// helpToolStripMenuItem
//
helpToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { aboutToolStripMenuItem });
helpToolStripMenuItem.Name = "helpToolStripMenuItem";
helpToolStripMenuItem.Size = new Size(65, 29);
helpToolStripMenuItem.Text = "Help";
//
// aboutToolStripMenuItem
//
aboutToolStripMenuItem.Name = "aboutToolStripMenuItem";
aboutToolStripMenuItem.Size = new Size(164, 34);
aboutToolStripMenuItem.Text = "About";
//
// lbl_wins
//
lbl_wins.AutoSize = true;
lbl_wins.Location = new Point(337, 44);
lbl_wins.Name = "lbl_wins";
lbl_wins.Size = new Size(131, 25);
lbl_wins.TabIndex = 4;
lbl_wins.Text = "Antal Vinster: 0";
//
// grid_7
//
grid_7.Font = new Font("Segoe UI", 22F, FontStyle.Bold);
grid_7.Location = new Point(368, 260);
grid_7.Name = "grid_7";
grid_7.Size = new Size(64, 64);
grid_7.TabIndex = 5;
grid_7.Text = "O";
grid_7.UseVisualStyleBackColor = true;
//
// grid_4
//
grid_4.Font = new Font("Segoe UI", 22F, FontStyle.Bold);
grid_4.Location = new Point(368, 190);
grid_4.Name = "grid_4";
grid_4.Size = new Size(64, 64);
grid_4.TabIndex = 6;
grid_4.Text = "O";
grid_4.UseVisualStyleBackColor = true;
//
// grid_1
//
grid_1.Font = new Font("Segoe UI", 22F, FontStyle.Bold);
grid_1.Location = new Point(368, 120);
grid_1.Name = "grid_1";
grid_1.Size = new Size(64, 64);
grid_1.TabIndex = 7;
grid_1.Text = "X";
grid_1.UseVisualStyleBackColor = true;
//
// grid_2
//
grid_2.Font = new Font("Segoe UI", 22F, FontStyle.Bold);
grid_2.Location = new Point(438, 120);
grid_2.Name = "grid_2";
grid_2.Size = new Size(64, 64);
grid_2.TabIndex = 8;
grid_2.Text = "O";
grid_2.UseVisualStyleBackColor = true;
//
// grid_5
//
grid_5.Font = new Font("Segoe UI", 22F, FontStyle.Bold);
grid_5.Location = new Point(438, 190);
grid_5.Name = "grid_5";
grid_5.Size = new Size(64, 64);
grid_5.TabIndex = 9;
grid_5.Text = "O";
grid_5.UseVisualStyleBackColor = true;
//
// grid_8
//
grid_8.Font = new Font("Segoe UI", 22F, FontStyle.Bold);
grid_8.Location = new Point(438, 260);
grid_8.Name = "grid_8";
grid_8.Size = new Size(64, 64);
grid_8.TabIndex = 10;
grid_8.Text = "O";
grid_8.UseVisualStyleBackColor = true;
//
// grid_0
//
grid_0.Font = new Font("Segoe UI", 22F, FontStyle.Bold);
grid_0.Location = new Point(298, 120);
grid_0.Name = "grid_0";
grid_0.Size = new Size(64, 64);
grid_0.TabIndex = 13;
grid_0.Text = "O";
grid_0.UseVisualStyleBackColor = true;
//
// grid_3
//
grid_3.Font = new Font("Segoe UI", 22F, FontStyle.Bold);
grid_3.Location = new Point(298, 190);
grid_3.Name = "grid_3";
grid_3.Size = new Size(64, 64);
grid_3.TabIndex = 12;
grid_3.Text = "O";
grid_3.UseVisualStyleBackColor = true;
//
// grid_6
//
grid_6.Font = new Font("Segoe UI", 22F, FontStyle.Bold);
grid_6.Location = new Point(298, 260);
grid_6.Name = "grid_6";
grid_6.Size = new Size(64, 64);
grid_6.TabIndex = 11;
grid_6.Text = "O";
grid_6.UseVisualStyleBackColor = true;
//
// lbl_loses
//
lbl_loses.AutoSize = true;
lbl_loses.Location = new Point(337, 69);
lbl_loses.Name = "lbl_loses";
lbl_loses.Size = new Size(146, 25);
lbl_loses.TabIndex = 14;
lbl_loses.Text = "Antal Förluster: 0";
//
// Form1
//
AutoScaleDimensions = new SizeF(10F, 25F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(lbl_loses);
Controls.Add(grid_0);
Controls.Add(grid_3);
Controls.Add(grid_6);
Controls.Add(grid_8);
Controls.Add(grid_5);
Controls.Add(grid_2);
Controls.Add(grid_1);
Controls.Add(grid_4);
Controls.Add(grid_7);
Controls.Add(lbl_wins);
Controls.Add(menuStrip1);
MainMenuStrip = menuStrip1;
Name = "Form1";
Text = "Form1";
menuStrip1.ResumeLayout(false);
menuStrip1.PerformLayout();
ResumeLayout(false);
PerformLayout();
}
#endregion
private Button btn_restart;
private MenuStrip menuStrip1;
private ToolStripMenuItem fileToolStripMenuItem;
private ToolStripMenuItem helpToolStripMenuItem;
private Label label1;
private ToolStripMenuItem aboutToolStripMenuItem;
private Button button3;
private Button button4;
private Button button5;
private Button button8;
public Button grid_7;
public Button grid_5;
public Button grid_8;
public Button grid_3;
public Button grid_6;
public Button grid_4;
public Button grid_0;
public Button grid_1;
public Button grid_2;
public Label lbl_wins;
public ToolStripMenuItem newGameToolStripMenuItem;
public Label lbl_loses;
public ToolStripMenuItem exitToolStripMenuItem;
}
}

View File

@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
@@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
@@ -117,4 +117,7 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

176
Game.cs Normal file
View File

@@ -0,0 +1,176 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Media;
using System.Text;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
namespace TicTacToe
{
public class Game
{
Form1 form;
Box[] boxes = new Box[9];
bool BotRound = false;
public Game()
{
form = Program.form;
boxes[0] = new Box(form.grid_0, 0); boxes[0].Pressed += ButtonClicked;
boxes[1] = new Box(form.grid_1, 1); boxes[1].Pressed += ButtonClicked;
boxes[2] = new Box(form.grid_2, 2); boxes[2].Pressed += ButtonClicked;
boxes[3] = new Box(form.grid_3, 3); boxes[3].Pressed += ButtonClicked;
boxes[4] = new Box(form.grid_4, 4); boxes[4].Pressed += ButtonClicked;
boxes[5] = new Box(form.grid_5, 5); boxes[5].Pressed += ButtonClicked;
boxes[6] = new Box(form.grid_6, 6); boxes[6].Pressed += ButtonClicked;
boxes[7] = new Box(form.grid_7, 7); boxes[7].Pressed += ButtonClicked;
boxes[8] = new Box(form.grid_8, 8); boxes[8].Pressed += ButtonClicked;
}
public void Start()
{
Round();
}
public void ButtonClicked(int index)
{
Box box = boxes[index];
if (box.Filled) return;
box.PlayerClaim(BotRound);
RoundEnded();
}
public void Round()
{
if (BotRound)
{
BotTurn();
}
else
{
PlayerTurn();
}
}
public void BotTurn()
{
SetInputEnabled(false);
Random random = new Random();
Box box;
bool[] boxCache = new bool[9];
while (true)
{
int randomIndex = random.Next(0, 8);
box = boxes[randomIndex];
boxCache[randomIndex] = true;
if (!box.Filled)
{
break;
}
}
box.PlayerClaim(true);
RoundEnded();
}
public bool CheckWins()
{
int[][] lines =
{
new[] {0, 1, 2},
new[] {3, 4, 5},
new[] {6, 7, 8},
new[] {0, 3, 6},
new[] {1, 4, 7},
new[] {2, 5, 8},
new[] {0, 4, 8},
new[] {2, 4, 6}
};
foreach (var line in lines)
{
if (!boxes[line[0]].Filled || !boxes[line[1]].Filled || !boxes[line[2]].Filled)
continue;
if (boxes[line[0]].BotOwned == BotRound &&
boxes[line[1]].BotOwned == BotRound &&
boxes[line[2]].BotOwned == BotRound)
{
return true;
}
}
return false;
}
public void PlayerTurn()
{
SetInputEnabled(true);
}
public void CheckWin()
{
}
public void RoundEnded()
{
if (CheckWins())
{
if (BotRound)
{
MessageBox.Show("You lost");
Program.AddLose();
}
else
{
MessageBox.Show("You won");
Program.AddWin();
}
return;
}
BotRound = !BotRound;
if (IsAllBoxesFilled())
{
MessageBox.Show("Tie");
}
else
{
Round();
}
}
public bool IsAllBoxesFilled()
{
foreach (Box box in boxes)
{
if (!box.Filled)
return false;
}
return true;
}
public void SetInputEnabled(bool value)
{
foreach (Box box in boxes)
{
box.SetEnabled(value);
}
}
public void Destroy()
{
foreach (Box box in boxes)
{
box.Destroy();
}
}
}
}

View File

@@ -1,17 +1,44 @@
namespace TicTacToe
{
internal static class Program
public static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
public static Form1 form = new Form1();
static Game game;
static int wins = 0;
static int loses = 0;
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new Form1());
game = new Game();
game.Start();
form.newGameToolStripMenuItem.Click += NewGame;
form.exitToolStripMenuItem.Click += Exit;
Application.Run(form);
}
static void NewGame(object sender, EventArgs e)
{
game.Destroy();
game = new Game();
game.Start();
}
static void Exit(object sender, EventArgs e)
{
Application.Exit();
}
public static void AddLose()
{
loses += 1;
form.lbl_loses.Text = "Antal F<>rluster: " + loses.ToString();
}
public static void AddWin()
{
wins += 1;
form.lbl_wins.Text = "Antal Vinster: " + wins.ToString();
}
}
}