Класс Bone.cs:
using System.Windows;
namespace Domino
{
public class Bone : DependencyObject
{
internal int PointsQty1 { get; private set; }
internal int PointsQty2 { get; private set; }
internal int SumOfPoints { get; private set; }
internal bool AreHalfsEquil { get; private set; }
private protected Bone() { }
internal Bone(int pointsQty1, int pointsQty2)
{
PointsQty1 = pointsQty1;
PointsQty2 = pointsQty2;
SumOfPoints = pointsQty1 + pointsQty2;
AreHalfsEquil = PointsQty1 == PointsQty2;
}
}
}
Класс BoneGraphics.cs:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace Domino
{
struct RowColumnIndexer
{
public byte rowIndex;
public byte columnIndex;
}
internal enum StateOfBone
{
ClosedHorizontal,
ClosedVertical,
OpenVertical,
OpenHorizontal,
OpenHorizontalTransposed,
ClosedVerticalWithMargin,
OpenVerticalWithMargin,
Unvisible
}
public class BoneGraphics : Bone
{
private static readonly Dictionary pointsIndexesHorizontal;
private static readonly Dictionary pointsIndexesVertical;
private static readonly Style[] stylesPoint;
private static readonly SolidColorBrush[] colorsForPoints;
internal static bool IsDifferentColorOfPoints { get; set; }
private StateOfBone stateOfBone;
internal StateOfBone State
{
get
{
return stateOfBone;
}
set
{
stateOfBone = value;
switch (value)
{
case StateOfBone.ClosedHorizontal:
SetClosedBone("Horizontal", (6, 3), false);
break;
case StateOfBone.ClosedVertical:
SetClosedBone("Vertical", (3, 6), false);
break;
case StateOfBone.OpenHorizontal:
SetOpenView("Horizontal", (6, 3), false, false, false, false);
break;
case StateOfBone.OpenHorizontalTransposed:
SetOpenView("Horizontal", (6, 3), false, true, false, false);
break;
case StateOfBone.OpenVertical:
SetOpenView("Vertical", (3, 6), true, false, false, false);
break;
case StateOfBone.Unvisible:
SetOpenView("Vertical", (3, 6), true, false, true, false);
break;
case StateOfBone.ClosedVerticalWithMargin:
SetClosedBone("Vertical", (3, 6), true);
break;
case StateOfBone.OpenVerticalWithMargin:
SetOpenView("Vertical", (3, 6), true, false, false, true);
break;
}
}
}
internal static readonly DependencyProperty BoneGridProperty;
internal Grid BoneGrid
{
get { return (Grid)GetValue(BoneGridProperty); }
set { SetValue(BoneGridProperty, value); }
}
private Border borderGrid;
private Border borderMid;
private List points;
static BoneGraphics()
{
BoneGridProperty = DependencyProperty.Register("BoneGrid", typeof(Grid), typeof(BoneGraphics));
pointsIndexesHorizontal = new Dictionary();
pointsIndexesVertical = new Dictionary();
RowColumnIndexer rc00 = new RowColumnIndexer { rowIndex = 0, columnIndex = 0 };
RowColumnIndexer rc01 = new RowColumnIndexer { rowIndex = 0, columnIndex = 1 };
RowColumnIndexer rc02 = new RowColumnIndexer { rowIndex = 0, columnIndex = 2 };
RowColumnIndexer rc10 = new RowColumnIndexer { rowIndex = 1, columnIndex = 0 };
RowColumnIndexer rc11 = new RowColumnIndexer { rowIndex = 1, columnIndex = 1 };
RowColumnIndexer rc12 = new RowColumnIndexer { rowIndex = 1, columnIndex = 2 };
RowColumnIndexer rc20 = new RowColumnIndexer { rowIndex = 2, columnIndex = 0 };
RowColumnIndexer rc21 = new RowColumnIndexer { rowIndex = 2, columnIndex = 1 };
RowColumnIndexer rc22 = new RowColumnIndexer { rowIndex = 2, columnIndex = 2 };
pointsIndexesHorizontal.Add(0, new RowColumnIndexer[] { });
pointsIndexesHorizontal.Add(1, new RowColumnIndexer[] { rc11 });
pointsIndexesHorizontal.Add(2, new RowColumnIndexer[] { rc00, rc22 });
pointsIndexesHorizontal.Add(3, new RowColumnIndexer[] { rc00, rc11, rc22 });
pointsIndexesHorizontal.Add(4, new RowColumnIndexer[] { rc00, rc02, rc20, rc22 });
pointsIndexesHorizontal.Add(5, new RowColumnIndexer[] { rc00, rc02, rc11, rc20, rc22 });
pointsIndexesHorizontal.Add(6, new RowColumnIndexer[] { rc00, rc01, rc02, rc20, rc21, rc22 });
pointsIndexesVertical.Add(0, new RowColumnIndexer[] { });
pointsIndexesVertical.Add(1, new RowColumnIndexer[] { rc11 });
pointsIndexesVertical.Add(2, new RowColumnIndexer[] { rc02, rc20 });
pointsIndexesVertical.Add(3, new RowColumnIndexer[] { rc02, rc11, rc20 });
pointsIndexesVertical.Add(4, new RowColumnIndexer[] { rc00, rc02, rc20, rc22 });
pointsIndexesVertical.Add(5, new RowColumnIndexer[] { rc00, rc02, rc11, rc20, rc22 });
pointsIndexesVertical.Add(6, new RowColumnIndexer[] { rc00, rc10, rc20, rc02, rc12, rc22 });
colorsForPoints = new SolidColorBrush[6] { new SolidColorBrush(Colors.DarkRed),
new SolidColorBrush(Colors.OrangeRed),
new SolidColorBrush(Colors.DarkGoldenrod),
new SolidColorBrush(Colors.Green),
new SolidColorBrush(Colors.Blue),
new SolidColorBrush(Colors.DarkViolet) };
stylesPoint = new Style[7];
for (int i = 0; i < stylesPoint.Length; i++)
{
Style style = new Style();
style.Setters.Add(new Setter { Property = Ellipse.MarginProperty, Value = new Thickness(i) });
stylesPoint[i] = style;
}
}
internal BoneGraphics(int pointsQty1, int pointsQty2) : base(pointsQty1, pointsQty2) { SetNewBone(); }
internal BoneGraphics() : base() { SetNewBone(); }
private void SetOpenView(string VerticalOrHorizontal, (int, int) ColumnsAndRowsQty, bool isVertical, bool isTransposed, bool isUnvisible, bool isMargin)
{
SetNewBone();
BoneGrid.SetResourceReference(Grid.StyleProperty, $"StyleOpenBone{VerticalOrHorizontal}" + (isMargin ? "WithMargin" : ""));
borderGrid.SetResourceReference(Border.StyleProperty, $"StyleBorderBone{VerticalOrHorizontal}");
borderMid.SetResourceReference(Border.StyleProperty, $"StyleBorderMid{VerticalOrHorizontal}");
for (int i = 0; i < ColumnsAndRowsQty.Item1; i++)
BoneGrid.ColumnDefinitions.Add(new ColumnDefinition());
for (int i = 0; i < ColumnsAndRowsQty.Item2; i++)
BoneGrid.RowDefinitions.Add(new RowDefinition());
BoneGrid.Children.Add(borderGrid);
BoneGrid.Children.Add(borderMid);
SetPoints(isTransposed, isVertical);
if (isUnvisible) { BoneGrid.Visibility = Visibility.Hidden; }
}
private void SetClosedBone(string VerticalOrHorizontal, (int, int) ColumnsAndRowsQty, bool isMargin)
{
SetNewBone();
BoneGrid.SetResourceReference(Grid.StyleProperty, $"StyleClosedBone{VerticalOrHorizontal}" + (isMargin ? "WithMargin" : ""));
borderGrid.SetResourceReference(Border.StyleProperty, $"StyleBorderBone{VerticalOrHorizontal}");
borderMid.SetResourceReference(Border.StyleProperty, $"StyleBorderMid{VerticalOrHorizontal}");
for (int i = 0; i < ColumnsAndRowsQty.Item1; i++)
BoneGrid.ColumnDefinitions.Add(new ColumnDefinition());
for (int i = 0; i < ColumnsAndRowsQty.Item2; i++)
BoneGrid.RowDefinitions.Add(new RowDefinition());
BoneGrid.Children.Add(borderGrid);
BoneGrid.Children.Add(borderMid);
}
private void SetNewBone()
{
BoneGrid = new Grid();
borderGrid = new Border();
borderMid = new Border();
points = new List();
}
private void SetPoints(bool isTransposed, bool isVertical)
{
if (isVertical)
{
SetPointsForHalfBone(pointsIndexesVertical[PointsQty1], isVertical);
SetPointsForHalfBone(pointsIndexesVertical[PointsQty2], isVertical, 3);
}
else
{
SetPointsForHalfBone(pointsIndexesHorizontal[isTransposed ? PointsQty2 : PointsQty1], isVertical);
SetPointsForHalfBone(pointsIndexesHorizontal[isTransposed ? PointsQty1 : PointsQty2], isVertical, 3);
}
}
private void SetPointsForHalfBone(RowColumnIndexer[] rowColumnIndexer, bool isVertical, int addParamiter = 0)
{
int iTo = rowColumnIndexer.Length;
for (int i = 0; i < iTo; i++)
{
Ellipse ellipse = new Ellipse();
Grid.SetRow(ellipse, rowColumnIndexer[i].rowIndex + (isVertical ? addParamiter : 0));
Grid.SetColumn(ellipse, rowColumnIndexer[i].columnIndex + (isVertical ? 0 : addParamiter));
points.Add(ellipse);
BoneGrid.Children.Add(ellipse);
}
}
internal void ReStylePoints(double width)
{
int j = Math.Min(stylesPoint.Length - 1, (int)Math.Floor(width == 0 ? 1000 : width / 200));
for (int i = 0; i < points.Count; i++)
{
points[i].Style = stylesPoint[j];
int points1 = stateOfBone == StateOfBone.OpenHorizontalTransposed ? PointsQty2 : PointsQty1;
points[i].Fill = IsDifferentColorOfPoints ? (points1 > i ? colorsForPoints[Math.Max(0, (points1 == PointsQty1 ? PointsQty1 : PointsQty2) - 1)] : colorsForPoints[Math.Max(0, (points1 == PointsQty1 ? PointsQty2 : PointsQty1) - 1)]) : new SolidColorBrush(Colors.Black);
}
}
internal static Brush SetBackgroundBrush(bool isTurnToMove, bool isPossibleMove)
{
return !isTurnToMove ? Brushes.AliceBlue : isPossibleMove ? Brushes.LightGreen : Brushes.Wheat;
}
}
}
Класс BonesRepository.cs:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Linq;
using System.Windows.Media;
namespace Domino
{
internal static class BonesRepository
{
internal static BoneGraphics[] bones = new BoneGraphics[28];
internal static int[] counterOfPlayedPoints = new int[7];
internal static int GameMaxScore { get; set; }
internal static UserBonesZone UserZone { get; set; } = new UserBonesZone();
internal static OpponentsBonesZone OpponentLeftZone { get; set; } = new OpponentsBonesZone(StateOfBone.ClosedHorizontal) { Name = "OppLeft" };
internal static OpponentsBonesZone OpponentTopZone { get; set; } = new OpponentsBonesZone(StateOfBone.ClosedVerticalWithMargin) { Name = "OppTop" };
internal static OpponentsBonesZone OpponentRightZone { get; set; } = new OpponentsBonesZone(StateOfBone.ClosedHorizontal) { Name = "OppRight" };
internal static PlayedBonesZone PlayedZone { get; set; } = new PlayedBonesZone();
internal static RestBonesZone RestZone { get; set; } = new RestBonesZone();
internal static bool isGameActive;
private static bool isPairGame;
internal static List activePlayers;
private static int activePlayerIndex;
private static int equalScore = 0;
private static WindowScore windowScore;
internal static bool IsShowNames { get; set; } = true;
internal static int ActivePlayerIndex {
get { return activePlayerIndex; }
set
{
if (isGameActive)
{
activePlayers[activePlayerIndex].IsTurnToMove = false;
if (value >= activePlayers.Count)
activePlayerIndex = 0;
else
activePlayerIndex = value;
activePlayers[activePlayerIndex].IsTurnToMove = true;
}
}
}
static BonesRepository() { }
internal static void NextMove(bool isStillBones)
{
if (!isGameActive) return;
if (isStillBones && !IsEndOfPossibleMoves())
ActivePlayerIndex++;
else
{
OpenAllBones(RestZone, OpponentLeftZone, OpponentRightZone, OpponentTopZone);
AddScores();
UpdateCurrentScore();
ShowResults();
if (!IsGameOver())
{
ResetBetweenRounds();
StartNewRound();
FindFirstMover(false);
activePlayers[activePlayerIndex].IsTurnToMove = true;
}
else
FullReset(true);
}
}
internal static void SetBones()
{
int k = 0;
for (int i = 0; i < 7; i++)
for (int j = i; j < 7; j++)
{
bones[k] = new BoneGraphics(i, j);
k++;
}
}
internal static void StartNewGame(int opponentsQty)
{
isGameActive = true;
FullReset(false);
switch (opponentsQty)
{
case 0:
isPairGame = true;
activePlayers = new List { UserZone, OpponentLeftZone, OpponentTopZone, OpponentRightZone };
break;
case 1:
activePlayers = new List { UserZone, OpponentTopZone };
break;
case 2:
activePlayers = new List { UserZone, OpponentLeftZone, OpponentTopZone };
break;
case 3:
activePlayers = new List { UserZone, OpponentLeftZone, OpponentTopZone, OpponentRightZone };
break;
}
WindowScore.SetNewScoreWindow(opponentsQty);
SetAllPlayersBackground(Brushes.AliceBlue, activePlayers.ToArray());
StartNewRound();
FindFirstMover();
UpdateCurrentScore();
}
private static bool IsEndOfPossibleMoves()
{
if (counterOfPlayedPoints[PlayedZone.PointsLeftSide] == 8 && counterOfPlayedPoints[PlayedZone.PointsRightSide] == 8)
return true;
return false;
}
private static void OpenAllBones(params BonesZone[] bonesZone)
{
foreach (BonesZone zone in bonesZone)
zone.SetOpenState();
}
private static void AddScores()
{
int[] scores = new int[activePlayers.Count];
for (int i = 0; i < activePlayers.Count; i++)
{
for (int j = 0; j < activePlayers[i].Bones.Count; j++)
scores[i] += activePlayers[i].Bones[j].SumOfPoints;
if (scores[i] == 0 && activePlayers[i].Bones.Count > 0)
scores[i] = 10;
}
if (isPairGame)
{
if (scores[0] + scores[2] > scores[1] + scores[3])
{
UserZone.Score += scores[0] + (int)Math.Floor(equalScore / 2.0);
OpponentTopZone.Score += scores[2] + (int)Math.Ceiling(equalScore / 2.0);
equalScore = 0;
WindowScore.AddNewRoundScore(equalScore, scores[0], 0, scores[2], 0);
}
else
{
if (scores[0] + scores[2] < scores[1] + scores[3])
{
OpponentLeftZone.Score += scores[1] + (int)Math.Floor(equalScore / 2.0);
OpponentRightZone.Score += scores[3] + (int)Math.Ceiling(equalScore / 2.0);
equalScore = 0;
WindowScore.AddNewRoundScore(equalScore, 0, scores[1], 0, scores[3]);
}
else
{
equalScore += scores[0] + scores[2];
WindowScore.AddNewRoundScore(equalScore);
}
}
}
else
{
int maxScore = scores.Max();
List indexesWithMaxScore = new List();
for (int i = 0; i < activePlayers.Count; i++)
if (scores[i].Equals(maxScore))
indexesWithMaxScore.Add(i);
if (indexesWithMaxScore.Count == activePlayers.Count)
{
equalScore += scores[0];
WindowScore.AddNewRoundScore(equalScore);
}
else
{
WindowScore.AddNewRoundScore(maxScore, indexesWithMaxScore);
int counter = equalScore;
for (int i = 0; i < indexesWithMaxScore.Count; i++)
if (i != indexesWithMaxScore.Count - 1)
{
activePlayers[indexesWithMaxScore[i]].Score += scores[indexesWithMaxScore[i]] + equalScore / indexesWithMaxScore.Count;
counter -= equalScore / indexesWithMaxScore.Count;
}
else
{
activePlayers[indexesWithMaxScore[i]].Score += scores[indexesWithMaxScore[i]] + counter;
}
equalScore = 0;
}
}
}
internal static void UpdateCurrentScore()
{
if (isPairGame)
{
UserZone.CurrentScore = $"Your pair: {UserZone.Score + OpponentTopZone.Score}\nOpponent pair: {OpponentLeftZone.Score + OpponentRightZone.Score}";
}
else
{
if (isGameActive)
{
string str = "";
foreach (UserOrOppenentZone z in activePlayers)
str += $"{z.Name}: {z.Score}\n";
UserZone.CurrentScore = str;
}
}
}
private static void ShowResults()
{
windowScore = new WindowScore() { Owner = UserBonesZone.mainWindow };
windowScore.ShowDialog();
}
private static bool IsGameOver()
{
if (isPairGame)
{
if (UserZone.Score + OpponentTopZone.Score < GameMaxScore && OpponentLeftZone.Score + OpponentRightZone.Score < GameMaxScore)
return false;
else
{
MessageBox.Show($"{(UserZone.Score + OpponentTopZone.Score > OpponentLeftZone.Score + OpponentRightZone.Score ? "Lose this time. Try again!" : "You win!")}");
isGameActive = false;
return true;
}
}
else
{
if (activePlayers.Max(s => s.Score) >= GameMaxScore)
{
MessageBox.Show($"{(UserZone.Score == activePlayers.Max(s => s.Score) ? "Lose this time. Try again!" : "You win!")}");
isGameActive = false;
return true;
}
else
return false;
}
}
internal static void FullReset(bool isResetOnForm = false)
{
UserZone.CurrentScore = "";
if (activePlayers?.Count > 0) ResetScores(activePlayers.ToArray());
ResetBetweenRounds();
activePlayers = new List();
activePlayerIndex = 0;
isPairGame = false;
SetAllPlayersBackground(Brushes.White, UserZone, OpponentLeftZone, OpponentTopZone, OpponentRightZone);
if (isResetOnForm)
{
UserOrOppenentZone.mainWindow.SetVisibilityForTextBlocks(Visibility.Hidden, UserOrOppenentZone.mainWindow.TextBlockUserName, UserOrOppenentZone.mainWindow.TextBlockOppLeftName, UserOrOppenentZone.mainWindow.TextBlockOppTopName, UserOrOppenentZone.mainWindow.TextBlockOppRightName);
isGameActive = false;
UserOrOppenentZone.mainWindow.MenuItemsNewGameGroup.IsEnabled = true;
UserOrOppenentZone.mainWindow.MenuItemReset.IsEnabled = false;
}
}
private static void SetAllPlayersBackground(Brush brush, params UserOrOppenentZone[] players)
{
foreach (UserOrOppenentZone player in players)
player.SetBackgroundBrush(brush);
}
private static void ResetScores(params UserOrOppenentZone[] zones)
{
foreach (UserOrOppenentZone z in zones) z.Score = 0;
}
private static void ResetBetweenRounds()
{
counterOfPlayedPoints = new int[7];
ResetZones(PlayedZone, RestZone);
for (int i = 0; i < bones.Length; i++)
bones[i].BoneGrid.Name = null;
}
private static void ResetZones(params BonesZone[] zones)
{
if (activePlayers?.Count > 0) foreach (UserOrOppenentZone z in activePlayers) z.Reset();
foreach (BonesZone z in zones) z.Reset();
}
private static void StartNewRound()
{
SetStartBonesToEachPlayer();
}
private static void SetStartBonesToEachPlayer()
{
ShuffleBones();
RestZone.CopyAllBones(bones);
foreach (BonesZone zone in activePlayers)
for (int i = 0; i < 7; i++)
{
Random random = new Random();
int r = random.Next(0, RestZone.Bones.Count);
RestZone.TransferBone(zone, r, true, false, new Point(0, 0));
}
}
private static void ShuffleBones()
{
Random random = new Random();
for (int i = bones.Length - 1; i >= 1; i--)
{
int j = random.Next(0, i + 1);
BoneGraphics tmp = bones[j];
bones[j] = bones[i];
bones[i] = tmp;
}
}
private static void FindFirstMover(bool isNeedToSetMover = true)
{
for (int i = 1; i < 7; i++)
for (int j = 0; j < activePlayers.Count; j++)
{
if (!isNeedToSetMover) j = activePlayerIndex;
if (SetFirstMoverIfEquelHalfs(activePlayers[j], i))
{
if (isNeedToSetMover)
ActivePlayerIndex = j;
return;
}
if (!isNeedToSetMover) break;
}
SetFirstMoverIfNotEquelHalfs(isNeedToSetMover);
}
private static bool SetFirstMoverIfEquelHalfs(UserOrOppenentZone uooz, int i)
{
for (int j = 0; j < uooz.Bones.Count; j++)
if (uooz.Bones[j].PointsQty1 == i && uooz.Bones[j].PointsQty2 == i)
{
uooz.FirstBoneIndexToMove = j;
return true;
}
return false;
}
private static void SetFirstMoverIfNotEquelHalfs(bool isNeedToSetMover)
{
(int zone, int index) = (int.MaxValue, int.MaxValue);
int minimumSum = int.MaxValue;
for (int i = 0; i < activePlayers.Count; i++)
{
if (!isNeedToSetMover) i = activePlayerIndex;
int minBoneSum = activePlayers[i].Bones.Min(m => m.SumOfPoints == 0 ? int.MaxValue : m.SumOfPoints);
if (minBoneSum < minimumSum)
{
minimumSum = minBoneSum;
zone = i;
}
if (!isNeedToSetMover) break;
}
for (int i = 0; i < activePlayers[zone].Bones.Count; i++)
if (activePlayers[zone].Bones[i].SumOfPoints == minimumSum)
{
index = i;
break;
}
activePlayers[zone].FirstBoneIndexToMove = index;
if (isNeedToSetMover)
ActivePlayerIndex = zone;
}
}
}
Класс BonesZone.cs:
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
namespace Domino
{
abstract class BonesZone : DependencyObject
{
internal ObservableCollection Bones { get; set; }
internal ObservableCollection Grids { get; set; }
internal BonesZone()
{
Bones = new ObservableCollection();
Grids = new ObservableCollection();
}
internal virtual void Reset()
{
Bones.Clear();
Grids.Clear();
}
internal void SetOpenState()
{
for (int i = Bones.Count - 1; i > -1; i--)
{
BoneGraphics bg = Bones[i];
RemoveAtIndex(i);
switch (bg.State)
{
case StateOfBone.ClosedHorizontal:
bg.State = StateOfBone.OpenHorizontal;
break;
case StateOfBone.ClosedVertical:
bg.State = StateOfBone.OpenVertical;
break;
case StateOfBone.ClosedVerticalWithMargin:
bg.State = StateOfBone.OpenVerticalWithMargin;
break;
}
AddingBone(bg);
}
}
internal virtual void TransferBone(BonesZone zoneTo, int index, bool isToEnd, bool isNeedToTransferMove, System.Windows.Point startPoint)
{
BoneGraphics boneTmp = Bones[index];
if (zoneTo.GetType() == BonesRepository.PlayedZone.GetType())
AddCountersInRepository(boneTmp.PointsQty1, boneTmp.PointsQty2);
RemoveAtIndex(index);
StartAnimation(zoneTo, boneTmp, isToEnd, isNeedToTransferMove, startPoint);
if (!isNeedToTransferMove) zoneTo.AddBone(boneTmp, isToEnd);
}
private protected virtual void StartAnimation(BonesZone zoneTo, BoneGraphics bone, bool isToEnd, bool isNeedToTransferMove, System.Windows.Point startPoint) { }
private protected void AddCountersInRepository(int points1, int points2)
{
BonesRepository.counterOfPlayedPoints[points1]++;
BonesRepository.counterOfPlayedPoints[points2]++;
}
private protected virtual void AddingBone(BoneGraphics bone)
{
Bones.Add(bone);
Grids.Add(bone.BoneGrid);
Grids[^1].Name = $"G{Grids.Count - 1}";
}
internal abstract void AddBone(BoneGraphics bone, bool isToEnd = true);
private protected void RemoveAtIndex(int index)
{
Grids[index].Name = null;
Bones.RemoveAt(index);
Grids.RemoveAt(index);
for (int i = 0; i < Grids.Count; i++)
Grids[i].Name = $"G{i}";
}
}
}
Файл разметки MainWindow.xaml:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Domino"
mc:Ignorable="d"
Title="Domino"
Height="576" Width="1024">
Класс MainWindow.xaml.cs:
using System.Windows;
using System.Windows.Controls;
namespace Domino
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
SetInitials();
BonesRepository.SetBones();
}
internal void SetInitials()
{
UserBonesItems.DataContext = BonesRepository.UserZone.Grids;
OpponentTopBonesItems.DataContext = BonesRepository.OpponentTopZone.Grids;
OpponentLeftBonesItems.DataContext = BonesRepository.OpponentLeftZone.Grids;
OpponentRigthBonesItems.DataContext = BonesRepository.OpponentRightZone.Grids;
PlayedBonesItems.DataContext = BonesRepository.PlayedZone.Grids;
RestBonesItems.DataContext = BonesRepository.RestZone.Grids;
UserGridCell.DataContext = BonesRepository.UserZone;
OppLeftGridCell.DataContext = BonesRepository.OpponentLeftZone;
OppTopGridCell.DataContext = BonesRepository.OpponentTopZone;
OppRightGridCell.DataContext = BonesRepository.OpponentRightZone;
RestZoneGrid.DataContext = BonesRepository.RestZone;
TextBoxCurrentScore.DataContext = BonesRepository.UserZone;
TextBlockUserName.DataContext = BonesRepository.UserZone;
TextBlockOppLeftName.DataContext = BonesRepository.OpponentLeftZone;
TextBlockOppTopName.DataContext = BonesRepository.OpponentTopZone;
TextBlockOppRightName.DataContext = BonesRepository.OpponentRightZone;
UserOrOppenentZone.mainWindow = this;
UserOrOppenentZone.canvasForAnimation = canvas;
MenuItemSpeedN.IsChecked = true;
MenuitemPoints100.IsChecked = true;
MenuItemIsShowNames.IsChecked = true;
}
private void MenuItemSpeed_Checked(object sender, RoutedEventArgs e)
{
MenuItem menuItem = (MenuItem)sender;
UncheckAllMenuItemsExcept(menuItem, MenuItemSpeedVS, MenuItemSpeedS, MenuItemSpeedN, MenuItemSpeedF, MenuItemSpeedVF);
switch (menuItem.Name)
{
case "MenuItemSpeedVS":
UserOrOppenentZone.DelayInMs = 4000;
break;
case "MenuItemSpeedS":
UserOrOppenentZone.DelayInMs = 2000;
break;
case "MenuItemSpeedN":
UserOrOppenentZone.DelayInMs = 1000;
break;
case "MenuItemSpeedF":
UserOrOppenentZone.DelayInMs = 500;
break;
case "MenuItemSpeedVF":
UserOrOppenentZone.DelayInMs = 250;
break;
}
}
private void StartNewGame_Click(object sender, RoutedEventArgs e)
{
MenuItemsNewGameGroup.IsEnabled = false;
MenuItemReset.IsEnabled = true;
MenuItem clickedButton = (MenuItem)sender;
switch (clickedButton.Name)
{
case "MenuItemNewGameOpp1":
BonesRepository.StartNewGame(1);
SetVisibilityForTextBlocks(Visibility.Visible, TextBlockUserName, TextBlockOppTopName);
break;
case "MenuItemNewGameOpp2":
BonesRepository.StartNewGame(2);
SetVisibilityForTextBlocks(Visibility.Visible, TextBlockUserName, TextBlockOppLeftName, TextBlockOppTopName);
break;
case "MenuItemNewGameOpp3":
BonesRepository.StartNewGame(3);
SetVisibilityForTextBlocks(Visibility.Visible, TextBlockUserName, TextBlockOppLeftName, TextBlockOppTopName, TextBlockOppRightName);
break;
case "MenuItemNewGameOpp2x2":
BonesRepository.StartNewGame(0);
SetVisibilityForTextBlocks(Visibility.Visible, TextBlockUserName, TextBlockOppLeftName, TextBlockOppTopName, TextBlockOppRightName);
break;
}
}
private void MenuItemReset_Click(object sender, RoutedEventArgs e)
{
BonesRepository.FullReset(true);
}
private void MenuItemExit_Click(object sender, RoutedEventArgs e)
{
if (MessageBox.Show("Are you sure?", "Exit", MessageBoxButton.YesNo) == MessageBoxResult.Yes) Close();
}
private void MenuItemLossAt_Checked(object sender, RoutedEventArgs e)
{
MenuItem menuItem = (MenuItem)sender;
UncheckAllMenuItemsExcept(menuItem, MenuitemPoints100, MenuitemPoints200, MenuitemPoints300);
switch (menuItem.Name)
{
case "MenuitemPoints100":
BonesRepository.GameMaxScore = 100;
break;
case "MenuitemPoints200":
BonesRepository.GameMaxScore = 200;
break;
case "MenuitemPoints300":
BonesRepository.GameMaxScore = 300;
break;
}
}
internal void SetVisibilityForTextBlocks(Visibility visibility, params TextBlock[] textBlocks)
{
if (BonesRepository.IsShowNames)
foreach (TextBlock tb in textBlocks)
tb.Visibility = visibility;
}
private void UncheckAllMenuItemsExcept(MenuItem menuItemException, params MenuItem[] menuItems)
{
for (int i = 0; i < menuItems.Length; i++)
if (menuItems[i] != menuItemException)
menuItems[i].IsChecked = false;
}
private void MenuItemDiffColors_Click(object sender, RoutedEventArgs e)
{
MenuItem menuItem = (MenuItem)sender;
BoneGraphics.IsDifferentColorOfPoints = menuItem.IsChecked;
for (int i = 0; i < BonesRepository.bones.Length; i++)
BonesRepository.bones[i].ReStylePoints(border.ActualWidth);
}
private void MenuItemIsShowNames_Click(object sender, RoutedEventArgs e)
{
MenuItem menuItem = (MenuItem)sender;
if (menuItem.IsChecked)
{
BonesRepository.IsShowNames = menuItem.IsChecked;
switch (BonesRepository.activePlayers?.Count)
{
case 2:
SetVisibilityForTextBlocks(Visibility.Visible, TextBlockUserName, TextBlockOppTopName);
break;
case 3:
SetVisibilityForTextBlocks(Visibility.Visible, TextBlockUserName, TextBlockOppLeftName, TextBlockOppTopName);
break;
case 4:
SetVisibilityForTextBlocks(Visibility.Visible, TextBlockUserName, TextBlockOppLeftName, TextBlockOppTopName, TextBlockOppRightName);
break;
}
}
else
{
SetVisibilityForTextBlocks(Visibility.Hidden, TextBlockUserName, TextBlockOppLeftName, TextBlockOppTopName, TextBlockOppRightName);
BonesRepository.IsShowNames = menuItem.IsChecked;
}
}
private void MenuItemChangeNames_Click(object sender, RoutedEventArgs e)
{
WindowChangeNames windowChangeNames = new WindowChangeNames(BonesRepository.UserZone.Name, BonesRepository.OpponentLeftZone.Name, BonesRepository.OpponentTopZone.Name, BonesRepository.OpponentRightZone.Name) { Owner = this };
if (windowChangeNames.ShowDialog() == true)
{
BonesRepository.UserZone.Name = windowChangeNames.UserName;
BonesRepository.OpponentLeftZone.Name = windowChangeNames.OppLeftName;
BonesRepository.OpponentTopZone.Name = windowChangeNames.OppTopName;
BonesRepository.OpponentRightZone.Name = windowChangeNames.OppRightName;
BonesRepository.UpdateCurrentScore();
}
}
private void MenuItemAbout_Click(object sender, RoutedEventArgs e)
{
WindowAbout windowAbout = new WindowAbout() { Owner = this };
windowAbout.ShowDialog();
}
}
}
Класс OpponentsBonesZone.cs
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace Domino
{
class OpponentsBonesZone : UserOrOppenentZone
{
private StateOfBone State { get; set; }
private bool isTurnToMove;
internal override bool IsTurnToMove
{
get { return isTurnToMove; }
set
{
isTurnToMove = value;
BackgroundBrush = BoneGraphics.SetBackgroundBrush(IsTurnToMove, GetIndexOfMaxElement(BonesRepository.PlayedZone.PointsLeftSide, BonesRepository.PlayedZone.PointsRightSide) != -1);
if (isTurnToMove)
MakeMoveWithDelay();
}
}
internal OpponentsBonesZone(StateOfBone state) : base() { State = state; }
private async void MakeMoveWithDelay()
{
await Task.Delay(DelayInMs);
if (!TryMakeMove())
{
if (TryGetBoneFromRest())
IsTurnToMove = true;
else
BonesRepository.NextMove(Bones.Count > 0);
}
}
internal override void AddBone(BoneGraphics bone, bool isToEnd = true)
{
bone.State = State;
AddingBone(bone);
}
private int GetIndexOfMaxElement(int PLS, int PRS)
{
if (FirstBoneIndexToMove != -1) return FirstBoneIndexToMove;
return Bones.Select((value, index) => new { value, index = index + 1 })
.Where(b => b.value.PointsQty1 == PLS || b.value.PointsQty2 == PLS || b.value.PointsQty1 == PRS || b.value.PointsQty2 == PRS)
.OrderByDescending(b => b.value.SumOfPoints)
.Select(pair => pair.index)
.FirstOrDefault() - 1;
}
private bool TryMakeMove()
{
if (FirstBoneIndexToMove != -1)
{
MakeMoveFromSelectedBone();
return true;
}
int indexOfMaxElement = GetIndexOfMaxElement(BonesRepository.PlayedZone.PointsLeftSide, BonesRepository.PlayedZone.PointsRightSide);
if (indexOfMaxElement == -1)
return false;
else
{
var boneLocation = Bones[indexOfMaxElement].BoneGrid.PointFromScreen(new Point(0, 0));
if ((Bones[indexOfMaxElement].PointsQty1 == BonesRepository.PlayedZone.PointsLeftSide || Bones[indexOfMaxElement].PointsQty2 == BonesRepository.PlayedZone.PointsLeftSide) &&
(Bones[indexOfMaxElement].PointsQty1 == BonesRepository.PlayedZone.PointsRightSide || Bones[indexOfMaxElement].PointsQty2 == BonesRepository.PlayedZone.PointsRightSide) &&
(BonesRepository.PlayedZone.PointsLeftSide != BonesRepository.PlayedZone.PointsRightSide))
{
if (BonesRepository.PlayedZone.PointsLeftSide > BonesRepository.PlayedZone.PointsRightSide)
TransferBone(BonesRepository.PlayedZone, indexOfMaxElement, false, true, boneLocation);
else
TransferBone(BonesRepository.PlayedZone, indexOfMaxElement, true, true, boneLocation);
}
else
{
if (Bones[indexOfMaxElement].PointsQty1 == BonesRepository.PlayedZone.PointsLeftSide || Bones[indexOfMaxElement].PointsQty2 == BonesRepository.PlayedZone.PointsLeftSide)
TransferBone(BonesRepository.PlayedZone, indexOfMaxElement, false, true, boneLocation);
else
TransferBone(BonesRepository.PlayedZone, indexOfMaxElement, true, true, boneLocation);
}
return true;
}
}
private void MakeMoveFromSelectedBone()
{
TransferBone(BonesRepository.PlayedZone, FirstBoneIndexToMove, true, true, Bones[FirstBoneIndexToMove].BoneGrid.PointFromScreen(new Point(0, 0)));
FirstBoneIndexToMove = -1;
}
private bool TryGetBoneFromRest()
{
if (BonesRepository.RestZone.Bones.Count > 1)
{
Random random = new Random();
int r = random.Next(0, BonesRepository.RestZone.Bones.Count);
BonesRepository.RestZone.TransferBone(this, r, true, false, BonesRepository.RestZone.Bones[r].BoneGrid.PointFromScreen(new Point(0, 0)));
if (BonesRepository.RestZone.Bones.Count == 1)
{
BonesRepository.RestZone.SetOpenState();
AddCountersInRepository(BonesRepository.RestZone.Bones[0].PointsQty1, BonesRepository.RestZone.Bones[0].PointsQty2);
}
BackgroundBrush = BoneGraphics.SetBackgroundBrush(IsTurnToMove, GetIndexOfMaxElement(BonesRepository.PlayedZone.PointsLeftSide, BonesRepository.PlayedZone.PointsRightSide) != -1);
return true;
}
else return false;
}
}
}
Класс PercentageConverter.cs:
using System;
using System.Globalization;
using System.Windows.Data;
namespace Domino
{
public class PercentageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
for (int i = 0; i < BonesRepository.bones.Length; i++)
BonesRepository.bones[i].ReStylePoints(System.Convert.ToDouble(value));
return System.Convert.ToDouble(value) * System.Convert.ToDouble(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator == "." ? parameter.ToString() : parameter.ToString().Replace('.', ','));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}
}
Класс PlayedBonesZone.xaml:
using System;
using System.Windows;
namespace Domino
{
class PlayedBonesZone : BonesZone
{
private readonly int BonesHalfsOnOneLine = 20;
internal int PointsLeftSide { get; set; }
internal int PointsRightSide { get; set; }
internal override void Reset()
{
base.Reset();
PointsLeftSide = -1;
PointsRightSide = -1;
}
internal override void AddBone(BoneGraphics bone, bool isAddAtEnd = true)
{
bool isTranspose = false;
if (Bones.Count != 0)
if (isAddAtEnd)
{
if (Bones[^1].PointsQty1 == bone.PointsQty1)
isTranspose = false;
else
{
if (Bones[^1].PointsQty2 == bone.PointsQty1)
isTranspose = false;
else
isTranspose = true;
}
}
else
{
if (Bones[0].PointsQty1 == bone.PointsQty2)
isTranspose = false;
else
{
if (Bones[0].PointsQty2 == bone.PointsQty2)
isTranspose = false;
else
isTranspose = true;
}
}
bone.State = bone.AreHalfsEquil ? StateOfBone.OpenVertical : isTranspose ? StateOfBone.OpenHorizontalTransposed : StateOfBone.OpenHorizontal;
if (Bones.Count == 0)
{
PointsRightSide = bone.State == StateOfBone.OpenHorizontalTransposed ? bone.PointsQty1 : bone.PointsQty2;
PointsLeftSide = bone.State == StateOfBone.OpenHorizontalTransposed ? bone.PointsQty2 : bone.PointsQty1;
Bones.Add(bone);
for (int i = 0; i < (PointsLeftSide == PointsRightSide ? BonesHalfsOnOneLine : BonesHalfsOnOneLine - 1); i++) AddUnvisibleGrid();
Grids[BonesHalfsOnOneLine / 2 - (BonesHalfsOnOneLine % 2 == 0 ? 1 : 0)] = bone.BoneGrid;
}
else
{
if (isAddAtEnd)
PointsRightSide = bone.State == StateOfBone.OpenHorizontalTransposed ? bone.PointsQty1 : bone.PointsQty2;
else
PointsLeftSide = bone.State == StateOfBone.OpenHorizontalTransposed ? bone.PointsQty2 : bone.PointsQty1;
AddingBone(bone, isAddAtEnd);
}
}
private int GetIndexOfLastVisibleGrid(bool isFromEnd)
{
if (isFromEnd)
{
for (int i = Grids.Count - 1; i >= 0; i--)
if (Grids[i].Visibility != Visibility.Hidden)
return i;
}
else
for (int i = 0; i < Grids.Count; i++)
if (Grids[i].Visibility != Visibility.Hidden)
return i;
return 0;
}
private void AddingBone(BoneGraphics bone, bool isToEnd)
{
Bones.Insert(isToEnd ? Bones.Count : 0, bone);
int shift = 0;
if (IsNeedToAddNewLines(bone.AreHalfsEquil, isToEnd))
for (int i = 0; i < BonesHalfsOnOneLine; i++)
{
AddUnvisibleGrid();
AddUnvisibleGrid(false);
}
int indexOfLastVisibleGrid = GetIndexOfLastVisibleGrid(isToEnd);
if (IsNeedToAddEmptyBoneBefore(bone.AreHalfsEquil, isToEnd, indexOfLastVisibleGrid))
shift = isToEnd ? 1 : -1;
Grids[indexOfLastVisibleGrid + (isToEnd ? 1 : -1) + shift] = bone.BoneGrid;
if (!bone.AreHalfsEquil) Grids.RemoveAt(isToEnd ? Grids.Count - 1 : 0);
}
private bool IsNeedToAddEmptyBoneBefore(bool isEquelBone, bool isToEnd, int indexOfLastVisibleGrid)
{
if (!isEquelBone)
{
if (isToEnd)
{
if ((Grids.Count - indexOfLastVisibleGrid) % BonesHalfsOnOneLine == 2)
return true;
}
else
if (indexOfLastVisibleGrid % BonesHalfsOnOneLine == 1)
return true;
}
return false;
}
private bool IsNeedToAddNewLines(bool isEquelBone, bool isToEnd)
{
if (isToEnd)
{
if (GetIndexOfLastVisibleGrid(isToEnd) > Grids.Count - (isEquelBone ? 2 : 3))
return true;
}
else
if (GetIndexOfLastVisibleGrid(isToEnd) < (isEquelBone ? 1 : 2))
return true;
return false;
}
private void AddUnvisibleGrid(bool isToEnd = true)
{
Grids.Insert(isToEnd ? GetIndexOfLastVisibleGrid(true) + (Grids.Count > 0 ? 1 : 0) : GetIndexOfLastVisibleGrid(false), new BoneGraphics { State = StateOfBone.Unvisible }.BoneGrid);
}
internal protected System.Windows.Point GetTargetPoint(bool isToEnd, bool isEquel)
{
int indexLastVisibleBone = GetIndexOfLastVisibleGrid(isToEnd);
return new System.Windows.Point()
{
X = Grids.Count == 0 ? -1 : Math.Abs(Grids[indexLastVisibleBone].PointFromScreen(new System.Windows.Point(0, 0)).X) + Math.Min(Grids[indexLastVisibleBone].Width, Grids[indexLastVisibleBone].Height) * (isToEnd ? (Bones[^1].AreHalfsEquil ? 1.0 : 2.0) : (isEquel ? -1.0 : -2.0)),
Y = Grids.Count == 0 ? -1 : Math.Abs(Grids[indexLastVisibleBone].PointFromScreen(new System.Windows.Point(0, 0)).Y) + Math.Max(Grids[indexLastVisibleBone].Width, Grids[indexLastVisibleBone].Height) / 4.0 * (isEquel ? -1.0 : (Bones[isToEnd ? ^1 : 0].AreHalfsEquil ? 1.0 : 0.0))
};
}
}
}
Класс RestBonesZone.cs
using System.Windows;
namespace Domino
{
class RestBonesZone : BonesZone {
internal static readonly DependencyProperty RestGridHeightProperty;
internal string RestGridHeight
{
get { return (string)GetValue(RestGridHeightProperty); }
set { SetValue(RestGridHeightProperty, value); }
}
static RestBonesZone() { RestGridHeightProperty = DependencyProperty.Register("RestGridHeight", typeof(string), typeof(RestBonesZone)); }
internal RestBonesZone() : base() { RestGridHeight = "0*"; }
internal override void AddBone(BoneGraphics bone, bool isToEnd = true)
{
if (Bones.Count == 0) RestGridHeight = ".8*";
bone.State = StateOfBone.ClosedVertical;
bone.BoneGrid.MouseDown += BonesRepository.UserZone.RestBoneGrid_MouseDown;
AddingBone(bone);
}
internal override void Reset()
{
base.Reset();
RestGridHeight = "0*";
}
internal void CopyAllBones(BoneGraphics[] bonesFrom)
{
for (int i = 0; i < bonesFrom.Length; i++)
AddBone(bonesFrom[i]);
}
internal override void TransferBone(BonesZone zoneTo, int index, bool isToEnd, bool isNeedToTransferMove, System.Windows.Point startPoint)
{
base.TransferBone(zoneTo, index, isToEnd, isNeedToTransferMove, startPoint);
if (Bones.Count == 0) RestGridHeight = "0*";
}
}
}
Класс ScorePerRound.cs
using System;
using System.Windows;
using System.Linq;
namespace Domino
{
class ScorePerRound : DependencyObject
{
internal static int roundCounter;
internal static readonly DependencyProperty RoundNumberProperty;
internal static readonly DependencyProperty UserScoreProperty;
internal static readonly DependencyProperty OppLeftScoreProperty;
internal static readonly DependencyProperty OppTopScoreProperty;
internal static readonly DependencyProperty OppRightScoreProperty;
internal static readonly DependencyProperty EqualScoreProperty;
internal static readonly DependencyProperty UserPairScoreProperty;
internal static readonly DependencyProperty OpponentPairScoreProperty;
internal string RoundNumber { get { return (string)GetValue(RoundNumberProperty); } set { SetValue(RoundNumberProperty, value); } }
internal int UserScore { get { return (int)GetValue(UserScoreProperty); } set { SetValue(UserScoreProperty, value); } }
internal int OppLeftScore { get { return (int)GetValue(OppLeftScoreProperty); } set { SetValue(OppLeftScoreProperty, value); } }
internal int OppTopScore { get { return (int)GetValue(OppTopScoreProperty); } set { SetValue(OppTopScoreProperty, value); } }
internal int OppRightScore { get { return (int)GetValue(OppRightScoreProperty); } set { SetValue(OppRightScoreProperty, value); } }
internal int EqualScore { get { return (int)GetValue(EqualScoreProperty); } set { SetValue(EqualScoreProperty, value); } }
internal int UserPairScore { get { return (int)GetValue(UserPairScoreProperty); } set { SetValue(UserPairScoreProperty, value); } }
internal int OpponentPairScore { get { return (int)GetValue(OpponentPairScoreProperty); } set { SetValue(OpponentPairScoreProperty, value); } }
static ScorePerRound()
{
RoundNumberProperty = DependencyProperty.Register("RoundNumber", typeof(string), typeof(ScorePerRound));
UserScoreProperty = DependencyProperty.Register("UserScore", typeof(int), typeof(ScorePerRound));
OppLeftScoreProperty = DependencyProperty.Register("OppLeftScore", typeof(int), typeof(ScorePerRound));
OppTopScoreProperty = DependencyProperty.Register("OppTopScore", typeof(int), typeof(ScorePerRound));
OppRightScoreProperty = DependencyProperty.Register("OppRightScore", typeof(int), typeof(ScorePerRound));
EqualScoreProperty = DependencyProperty.Register("EqualScore", typeof(int), typeof(ScorePerRound));
UserPairScoreProperty = DependencyProperty.Register("UserPairScore", typeof(int), typeof(ScorePerRound));
OpponentPairScoreProperty = DependencyProperty.Register("OpponentPairScore", typeof(int), typeof(ScorePerRound));
}
internal ScorePerRound() { }
internal ScorePerRound(int userScore, int oppLeftScore, int oppTopScore, int oppRightScore, int equilScore, int lastEquilScore)
{
int playersWithNotZeroScoreInitial = new int[4] { userScore, oppLeftScore, oppTopScore, oppRightScore }.Count(c => c > 0);
int playersWithNotZeroScoreLeft = playersWithNotZeroScoreInitial;
RoundNumber = (++roundCounter).ToString();
UserScore = userScore + (userScore == 0 || lastEquilScore == 0 ? 0 : AddLastEquilScore(lastEquilScore, playersWithNotZeroScoreInitial, ref playersWithNotZeroScoreLeft));
OppLeftScore = oppLeftScore + (oppLeftScore == 0 || lastEquilScore == 0 ? 0 : AddLastEquilScore(lastEquilScore, playersWithNotZeroScoreInitial, ref playersWithNotZeroScoreLeft));
OppTopScore = oppTopScore + (oppTopScore == 0 || lastEquilScore == 0 ? 0 : AddLastEquilScore(lastEquilScore, playersWithNotZeroScoreInitial, ref playersWithNotZeroScoreLeft));
OppRightScore = oppRightScore + (oppRightScore == 0 || lastEquilScore == 0 ? 0 : AddLastEquilScore(lastEquilScore, playersWithNotZeroScoreInitial, ref playersWithNotZeroScoreLeft));
EqualScore = equilScore;
UserPairScore = UserScore + OppTopScore;
OpponentPairScore = OppLeftScore + OppRightScore;
}
private int AddLastEquilScore(int lastEquilScore, int playersWithNotZeroScore, ref int playersWithNotZeroScoreLeft)
{
if (playersWithNotZeroScoreLeft != 1)
{
playersWithNotZeroScoreLeft--;
return (int)Math.Floor((double)lastEquilScore / playersWithNotZeroScore);
}
else
return (int)Math.Ceiling((double)lastEquilScore / playersWithNotZeroScore);
}
}
}
Класс ScoreTotal.cs
using System.Collections.ObjectModel;
using System.Linq;
namespace Domino
{
class ScoreTotal : ScorePerRound
{
internal ScoreTotal(ObservableCollection scoresPerRounds)
{
RoundNumber = "Total:";
EqualScore = 0;
UserScore = scoresPerRounds.Sum(s => s.UserScore);
OppLeftScore = scoresPerRounds.Sum(s => s.OppLeftScore);
OppTopScore = scoresPerRounds.Sum(s => s.OppTopScore);
OppRightScore = scoresPerRounds.Sum(s => s.OppRightScore);
UserPairScore = UserScore + OppTopScore;
OpponentPairScore = OppLeftScore + OppRightScore;
}
}
}
Класс UserBonesZone.cs
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Domino
{
class UserBonesZone : UserOrOppenentZone
{
private static bool isShowNotificationTwoSides = true;
private bool isTurnToMove;
internal override bool IsTurnToMove
{
get { return isTurnToMove; }
set
{
isTurnToMove = value;
BackgroundBrush = BoneGraphics.SetBackgroundBrush(IsTurnToMove, IsPossibleMove());
if (isTurnToMove && (BonesRepository.PlayedZone.PointsLeftSide == -1 || !IsPossibleMove()) && BonesRepository.RestZone.Bones.Count < 2 && FirstBoneIndexToMove == -1)
NextMoveWithDelay();
}
}
internal static readonly DependencyProperty CurrentScoreProperty;
internal string CurrentScore
{
get { return (string)GetValue(CurrentScoreProperty); }
set { SetValue(CurrentScoreProperty, value); }
}
static UserBonesZone() { CurrentScoreProperty = DependencyProperty.Register("CurrentScore", typeof(string), typeof(UserOrOppenentZone)); }
internal UserBonesZone() : base() { Name = "User"; }
private async void NextMoveWithDelay()
{
await Task.Delay(DelayInMs);
BonesRepository.NextMove(Bones.Count > 0);
}
private bool IsPossibleMove()
{
if (FirstBoneIndexToMove != -1) return true;
for (int i = 0; i < Bones.Count; i++)
if (Bones[i].PointsQty1 == BonesRepository.PlayedZone.PointsLeftSide ||
Bones[i].PointsQty2 == BonesRepository.PlayedZone.PointsLeftSide ||
Bones[i].PointsQty1 == BonesRepository.PlayedZone.PointsRightSide ||
Bones[i].PointsQty2 == BonesRepository.PlayedZone.PointsRightSide)
return true;
return false;
}
internal override void AddBone(BoneGraphics bone, bool isToEnd = true)
{
bone.State = StateOfBone.OpenVerticalWithMargin;
bone.BoneGrid.MouseDown += UserBoneGrid_MouseDown;
AddingBone(bone);
}
internal void UserBoneGrid_MouseDown(object sender, MouseEventArgs e)
{
if (!IsTurnToMove || HasAlreadyMadeMove) return;
Grid grid = (Grid)sender;
BoneGraphics bone = BonesRepository.UserZone.Bones[grid.Name.Length == 2 ? int.Parse($"{grid.Name[^1]}") : int.Parse($"{grid.Name[^2]}{grid.Name[^1]}")];
var boneLocation = bone.BoneGrid.PointToScreen(new Point(0, 0));
if (BonesRepository.PlayedZone.Bones.Count == 0)
{
if (FirstBoneIndexToMove != -1)
{
if ((bone.AreHalfsEquil && bone.PointsQty1 == Bones[FirstBoneIndexToMove].PointsQty1 && bone.PointsQty2 == Bones[FirstBoneIndexToMove].PointsQty2) || (!Bones[FirstBoneIndexToMove].AreHalfsEquil && bone.SumOfPoints == Bones[FirstBoneIndexToMove].SumOfPoints))
{
FirstBoneIndexToMove = -1;
TransferBoneAfterClick(grid, this, BonesRepository.PlayedZone, true, boneLocation);
}
}
}
else
{
if (((bone.PointsQty1 == BonesRepository.PlayedZone.PointsLeftSide && bone.PointsQty2 == BonesRepository.PlayedZone.PointsRightSide) ||
(bone.PointsQty2 == BonesRepository.PlayedZone.PointsLeftSide && bone.PointsQty1 == BonesRepository.PlayedZone.PointsRightSide)) &&
(!bone.AreHalfsEquil) &&
(BonesRepository.PlayedZone.PointsLeftSide != BonesRepository.PlayedZone.PointsRightSide))
{
bool isLeftButton = e.LeftButton == MouseButtonState.Pressed;
bool isRigthButton = e.RightButton == MouseButtonState.Pressed;
if (isShowNotificationTwoSides)
{
WindowNotificationTwoSidesOK windowNotificationTwoSidesOK = new WindowNotificationTwoSidesOK { Owner = mainWindow };
if (windowNotificationTwoSidesOK.ShowDialog() == true)
{
isShowNotificationTwoSides = windowNotificationTwoSidesOK.isShowThisAgain;
if (windowNotificationTwoSidesOK.isPutBoneDueToChoise)
TransferDueToChoise(grid, isLeftButton, isRigthButton, boneLocation);
}
}
else
TransferDueToChoise(grid, isLeftButton, isRigthButton, boneLocation);
}
else
{
if (bone.PointsQty1 == BonesRepository.PlayedZone.PointsRightSide || bone.PointsQty2 == BonesRepository.PlayedZone.PointsRightSide)
TransferBoneAfterClick(grid, this, BonesRepository.PlayedZone, true, boneLocation);
else
{
if (bone.PointsQty1 == BonesRepository.PlayedZone.PointsLeftSide || bone.PointsQty2 == BonesRepository.PlayedZone.PointsLeftSide)
TransferBoneAfterClick(grid, this, BonesRepository.PlayedZone, true, boneLocation, false);
}
}
}
}
private void TransferDueToChoise(Grid grid, bool isLeftButton, bool isRigthButton, System.Windows.Point boneLocation)
{
if (isLeftButton)
TransferBoneAfterClick(grid, this, BonesRepository.PlayedZone, true, boneLocation, false);
else
if (isRigthButton)
TransferBoneAfterClick(grid, this, BonesRepository.PlayedZone, true, boneLocation);
}
internal void RestBoneGrid_MouseDown(object sender, MouseEventArgs e) // клик на "базаре" (неразобранных костях)
{
if (!IsTurnToMove || IsPossibleMove()) return;
if (BonesRepository.RestZone.Bones.Count > 1)
{
Grid grid = (Grid)sender;
TransferBoneAfterClick(grid, BonesRepository.RestZone, BonesRepository.UserZone, false, grid.PointFromScreen(new Point(0, 0)));
BackgroundBrush = BoneGraphics.SetBackgroundBrush(IsTurnToMove, IsPossibleMove());
}
if (BonesRepository.RestZone.Bones.Count == 1)
{
BonesRepository.RestZone.SetOpenState();
AddCountersInRepository(BonesRepository.RestZone.Bones[0].PointsQty1, BonesRepository.RestZone.Bones[0].PointsQty2);
if (!IsPossibleMove()) BonesRepository.NextMove(Bones.Count > 0);
}
}
private void TransferBoneAfterClick(Grid grid, BonesZone zoneFrom, BonesZone zoneTo, bool isNeedToTransferMove, System.Windows.Point boneLocation, bool isToEnd = true)
{
if (isNeedToTransferMove) HasAlreadyMadeMove = true;
zoneFrom.TransferBone(zoneTo, grid.Name.Length == 2 ? int.Parse($"{grid.Name[^1]}") : int.Parse($"{grid.Name[^2]}{grid.Name[^1]}"), isToEnd, isNeedToTransferMove, boneLocation);
}
}
}
Класс UserOrOpponentZone
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace Domino
{
abstract class UserOrOppenentZone : BonesZone
{
internal static MainWindow mainWindow;
internal static Canvas canvasForAnimation;
private protected bool isNeedToTransferMove;
private protected BonesZone zoneTo;
private protected BoneGraphics bone;
private protected bool isToEnd;
private protected bool HasAlreadyMadeMove { get; set; } = false;
internal static readonly DependencyProperty NameProperty;
internal string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
internal int Score { get; set; }
internal virtual bool IsTurnToMove { get; set; }
internal int FirstBoneIndexToMove { get; set; } = -1;
internal static int DelayInMs { get; set; }
internal static readonly DependencyProperty BackgroundBrushProperty;
internal Brush BackgroundBrush
{
get { return (Brush)GetValue(BackgroundBrushProperty); }
private protected set { SetValue(BackgroundBrushProperty, value); }
}
static UserOrOppenentZone()
{
BackgroundBrushProperty = DependencyProperty.Register("BackgroundBrush", typeof(Brush), typeof(UserOrOppenentZone));
NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(UserOrOppenentZone));
}
internal UserOrOppenentZone() : base() { }
internal override void Reset()
{
base.Reset();
FirstBoneIndexToMove = -1;
BackgroundBrush = Brushes.AliceBlue;
HasAlreadyMadeMove = false;
}
internal void SetBackgroundBrush(Brush brush)
{
BackgroundBrush = brush;
}
private protected override void StartAnimation(BonesZone zoneTo, BoneGraphics bone, bool isToEnd, bool isNeedToTransferMove, System.Windows.Point startPoint)
{
this.isNeedToTransferMove = isNeedToTransferMove;
this.bone = bone;
this.zoneTo = zoneTo;
this.isToEnd = isToEnd;
if (bone.AreHalfsEquil)
bone.State = StateOfBone.OpenVertical;
else
{
if (BonesRepository.PlayedZone.Bones.Count == 0)
bone.State = StateOfBone.OpenHorizontal;
else
{
if (isToEnd)
bone.State = BonesRepository.PlayedZone.PointsRightSide == bone.PointsQty1 ? StateOfBone.OpenHorizontal : StateOfBone.OpenHorizontalTransposed;
else
bone.State = BonesRepository.PlayedZone.PointsLeftSide == bone.PointsQty2 ? StateOfBone.OpenHorizontal : StateOfBone.OpenHorizontalTransposed;
}
}
var windowPoint = mainWindow.PointFromScreen(new System.Windows.Point(0, 0));
var borderPoint = mainWindow.border.PointFromScreen(new System.Windows.Point(0, 0));
borderPoint.Y -= mainWindow.borderRest.ActualHeight / 2.0;
bone.BoneGrid.Margin = new Thickness(Math.Abs(startPoint.X) - Math.Abs(windowPoint.X), Math.Abs(startPoint.Y) - Math.Abs(windowPoint.Y) - 23, 0, 0);
canvasForAnimation.Children.Add(bone.BoneGrid);
Storyboard myStoryboard = new Storyboard();
myStoryboard.Completed += MyStoryboard_Completed;
ObjectAnimationUsingKeyFrames animation = new ObjectAnimationUsingKeyFrames();
Storyboard.SetTarget(animation, bone.BoneGrid);
Storyboard.SetTargetProperty(animation, new PropertyPath("Margin"));
System.Windows.Point target = BonesRepository.PlayedZone.GetTargetPoint(isToEnd, bone.AreHalfsEquil);
if (target.X == -1 && target.Y == -1)
{
target = new System.Windows.Point(
Math.Floor(Math.Abs(borderPoint.X) + Math.Abs(mainWindow.border.ActualWidth / 2)) - Math.Min(bone.BoneGrid.Width, bone.BoneGrid.Height),
Math.Floor(Math.Abs(borderPoint.Y) + Math.Abs(mainWindow.border.ActualHeight / 2)) - Math.Min(bone.BoneGrid.Width, bone.BoneGrid.Height) * (bone.AreHalfsEquil ? 1 : 0.5));
}
double diffX = Math.Abs(startPoint.X) - target.X;
double diffY = Math.Abs(startPoint.Y) - target.Y;
for (int count = 1; count < 101; count++)
{
double left = bone.BoneGrid.Margin.Left - (diffX / 100.0 * count);
double top = bone.BoneGrid.Margin.Top - (diffY / 100.0 * count);
DiscreteObjectKeyFrame keyFrame = new DiscreteObjectKeyFrame(new
Thickness(left, top, 0, 0), TimeSpan.FromMilliseconds(0.01 * DelayInMs * count));
animation.KeyFrames.Add(keyFrame);
}
myStoryboard.Children.Add(animation);
myStoryboard.Begin();
}
private void MyStoryboard_Completed(object sender, EventArgs e)
{
canvasForAnimation.Children.Remove(bone.BoneGrid);
zoneTo.AddBone(bone, isToEnd);
HasAlreadyMadeMove = false;
if (isNeedToTransferMove) BonesRepository.NextMove(Bones.Count > 0);
}
}
}
Файл разметки WindowAbout.xaml
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
ShowInTaskbar ="False"
WindowStyle="ToolWindow"
WindowStartupLocation="CenterOwner"
Title="About" SizeToContent="WidthAndHeight">
About application:
You can play Domino vs PC using this application.
Rules:
Goal of game: to get less points than opponent.
Players quantity: 2-4 (if 4 players game could be paired - 2 vs 2; in this case score is general for each pair of players; players in pair are opposite each other).
Game is over when one of players (or pair of players) gets 100 points (max score could be changed in settings).
General: there are 28 bones (0-0, 0-1, ... , 5-5, 5-6, 6-6). Every player gets 7 bones before each round.
Ungiven bones (if there are less than 4 players) stays on the table at closed state.
Every player can see just self bones and can`t tell any other player any information about self bones.
First round should be started by player who has least bone with the same point`s quantity on it except 0-0; in case of lack of bones with the same points`s quantity - players who has bone with smallest sum of points.
Every next round should be started by player which ended previous one. Player should play from the least bone with the same point`s quantity on it except 0-0; in case of lack of bones with the same points`s quantity - from bone with smallest sum of points.
First bone is putting to the center of the table. Every next player clockwise should put one of his bones sideways the left or right part of played bones until end of the round.
Neighboring played bones should have equal quantity of points on halfs close to each other.
If player has no applicable bone to put to the table he should take bone from rest unplayed bones and repeat until he has applicable bone.
Last of rest bones could not be taken (if there are less than 4 players in the game) and should be opened.
Round is over if one of players has no more bones left or there is no more possible moves.
If any player has the only bone 0-0 at the end of round his score is 10 not 0 in this round.
Player/players/pair with biggest quantity of points on self bones left get(s) those points. If all the players/pairs have the same quantity of points - those points will be played in the next round and loser(s) of next round will get them.
Файл разметки WindowChangeNames.xaml
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
ResizeMode="NoResize"
ShowInTaskbar ="False"
WindowStyle="ToolWindow"
WindowStartupLocation="CenterOwner"
Title="Change names" SizeToContent="WidthAndHeight">
User name:
Opponent from left name:
Opponent from top name:
Opponent from right name:
OK
Класс WindowChangeNames.xaml.cs
using System.Windows;
namespace Domino
{
///
/// Логика взаимодействия для WindowChangeNames.xaml
///
public partial class WindowChangeNames : Window
{
internal string UserName;
internal string OppLeftName;
internal string OppTopName;
internal string OppRightName;
public WindowChangeNames(string userName, string oppLeftName, string oppTopName, string oppRightName)
{
InitializeComponent();
UserName = userName;
OppLeftName = oppLeftName;
OppTopName = oppTopName;
OppRightName = oppRightName;
TextBoxUserName.Text = userName;
TextBoxOppLeftName.Text = oppLeftName;
TextBoxOppTopName.Text = oppTopName;
TextBoxOppRightName.Text = oppRightName;
}
private void ButtonOK_Click(object sender, RoutedEventArgs e)
{
UserName = TextBoxUserName.Text != "" ? TextBoxUserName.Text : UserName;
OppLeftName = TextBoxOppLeftName.Text != "" ? TextBoxOppLeftName.Text : OppLeftName;
OppTopName = TextBoxOppTopName.Text != "" ? TextBoxOppTopName.Text : OppTopName;
OppRightName = TextBoxOppRightName.Text != "" ? TextBoxOppRightName.Text : OppRightName;
this.DialogResult = true;
}
}
}
Файл разметки WindowNotificationTwoSlidesOK.xaml
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
ResizeMode="NoResize"
ShowInTaskbar ="False"
WindowStyle="ToolWindow"
WindowStartupLocation="CenterOwner"
Title="Which side put bone on?" SizeToContent="WidthAndHeight">
You can put this bone to both sides. Please use left mouse button to put on left side or rigth mouse button to put on right side.
Do not show again
Put according to click
Change choise
Класс WindowNotificationTwoSlidesOK.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace Domino
{
public partial class WindowNotificationTwoSidesOK : Window
{
internal bool isShowThisAgain = true;
internal bool isPutBoneDueToChoise = false;
public WindowNotificationTwoSidesOK()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Button button = (Button)sender;
if (button.Name == "ButtonOK") isPutBoneDueToChoise = true;
isShowThisAgain = !(bool)CheckBoxIsShowThisAgain.IsChecked;
this.DialogResult = true;
}
}
}
Файл разметки WindowScore.xaml
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
ResizeMode="NoResize"
ShowInTaskbar ="False"
WindowStartupLocation="CenterOwner"
WindowStyle="ToolWindow"
Title="Results" SizeToContent="WidthAndHeight">
Класс WindowScore.xaml.cs
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
namespace Domino
{
///
/// Логика взаимодействия для WindowScore.xaml
///
public partial class WindowScore : Window
{
private static ObservableCollection ScoresPerRounds { get; set; }
private static int OpponentsQty { get; set; }
public WindowScore()
{
InitializeComponent();
DataGridScore.DataContext = ScoresPerRounds;
ColumnUserPoints.Header = BonesRepository.UserZone.Name;
ColumnOppLeftPoints.Header = BonesRepository.OpponentLeftZone.Name;
ColumnOppTopPoints.Header = BonesRepository.OpponentTopZone.Name;
ColumnOppRightPoints.Header = BonesRepository.OpponentRightZone.Name;
switch (OpponentsQty)
{
case 0:
SetGridViewColumnUnvisible(ColumnUserPoints, ColumnOppLeftPoints, ColumnOppTopPoints, ColumnOppRightPoints, ColumnEmpty1);
break;
case 1:
SetGridViewColumnUnvisible(ColumnOppLeftPoints, ColumnOppRightPoints, ColumnUserPairPoints, ColumnOppPairPoints, ColumnEmpty3);
break;
case 2:
SetGridViewColumnUnvisible(ColumnOppRightPoints, ColumnUserPairPoints, ColumnOppPairPoints, ColumnEmpty3);
break;
case 3:
SetGridViewColumnUnvisible(ColumnUserPairPoints, ColumnOppPairPoints, ColumnEmpty3);
break;
}
}
internal static void SetNewScoreWindow(int opponentsQty)
{
ScoresPerRounds = new ObservableCollection();
OpponentsQty = opponentsQty;
ScorePerRound.roundCounter = 0;
}
private void SetGridViewColumnUnvisible(params DataGridTextColumn[] columns)
{
foreach (DataGridTextColumn c in columns)
c.Visibility = Visibility.Collapsed;
}
internal static void AddNewRoundScore(int equilScore)
{
AddNewRoundScore(equilScore, 0, 0, 0, 0);
}
internal static void AddNewRoundScore(int maxScore, List indexes)
{
int user = 0, oppLeft = 0, oppTop = 0, oppRigth = 0;
foreach (int i in indexes)
switch (i)
{
case 0:
user = maxScore;
break;
case 1:
if (OpponentsQty > 1)
oppLeft = maxScore;
else
oppTop = maxScore;
break;
case 2:
oppTop = maxScore;
break;
case 3:
oppRigth = maxScore;
break;
}
AddNewRoundScore(0, user, oppLeft, oppTop, oppRigth);
}
internal static void AddNewRoundScore(int equilScore, int userScore, int oppLeftScore, int oppTopScore = 0, int oppRightScore = 0)
{
if (ScoresPerRounds.Count > 1)
ScoresPerRounds.RemoveAt(ScoresPerRounds.Count - 1);
ScoresPerRounds.Add(new ScorePerRound(userScore, oppLeftScore, oppTopScore, oppRightScore, equilScore, ScoresPerRounds.Count > 0 ? ScoresPerRounds[^1].EqualScore : 0));
ScoresPerRounds.Add(new ScoreTotal(ScoresPerRounds));
}
}
} Достарыңызбен бөлісу: