Professional Documents
Culture Documents
lr5 Ukr
lr5 Ukr
lr5 Ukr
Звіт
Київ 2021
ЗМІСТ
2 ЗАВДАННЯ...............................................................................................4
3 ВИКОНАННЯ...........................................................................................6
ВИСНОВОК.....................................................................................................7
КРИТЕРІЇ ОЦІНЮВАННЯ..........................................................................8
2
1 МЕТА ЛАБОРАТОРНОЇ РОБОТИ
Мета роботи - вивчити основні підходи до формалізації алгоритмів
знаходження рішень задач в умовах протидії. Ознайомитися з підходами до
програмування алгоритмів штучного інтелекту в іграх з повною інформацією.
3
2 ЗАВДАННЯ
№ Варіант
1 Баше https://ru.wikipedia.org/wiki/Баше_(игра)
2 Нейтріко http://www.iggamecenter.com/info/ru/neutreeko.html
3 Точки https://ru.wikipedia.org/wiki/Точки_(игра)
5 Алемунгула http://www.iggamecenter.com/info/ru/alemungula.html
6 Snakes http://www.papg.com/show?3AE4
7 Cram https://en.wikipedia.org/wiki/Cram_(game)
8 Тіко http://www.iggamecenter.com/info/ru/teeko.html
10 Gale http://www.papg.com/show?1TPI
11 Гомоку https://ru.wikipedia.org/wiki/Гомоку
12 Нім https://ru.wikipedia.org/wiki/Ним_(игра)
13 Клоббер http://www.iggamecenter.com/info/ru/clobber.html
14 Hackenbush http://www.papg.com/show?1TMP
19 Транспозиція http://www.iggamecenter.com/info/ru/transposition.html
4
20 Заєць и Вовки (за Вовків) http://www.iggamecenter.com/info/ru/foxh.html
21 Вари http://www.iggamecenter.com/info/ru/oware.html
22 Калах http://www.iggamecenter.com/info/ru/kalah.html
23 Реверсі https://ru.wikipedia.org/wiki/Реверси
26 Сим https://ru.wikipedia.org/wiki/Сим_(игра)
27 Col http://www.papg.com/show?2XLY
28 Snort http://www.papg.com/show?2XM1
29 Chomp http://www.papg.com/show?3AEA
5
3 ВИКОНАННЯ
namespace neutreekoCSHARP
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
bool isPawnSelected = false;
byte selectedPawnRow;
byte selectedPawnColumn;
int[,] field;
public MainWindow()
{
InitializeComponent();
AllocConsole();
var pawnList = new List<Pawn>{
new Pawn(){Style = (Style)Resources["FirstPlayerPawn"], GridColumn = 2, GridRow = 1},
new Pawn(){Style = (Style)Resources["FirstPlayerPawn"], GridColumn = 1, GridRow = 4},
new Pawn(){Style = (Style)Resources["FirstPlayerPawn"], GridColumn = 3, GridRow = 4},
new Pawn(){Style = (Style)Resources["SecondPlayerPawn"], GridColumn = 3, GridRow = 0},
new Pawn(){Style = (Style)Resources["SecondPlayerPawn"], GridColumn = 1, GridRow = 0},
new Pawn(){Style = (Style)Resources["SecondPlayerPawn"], GridColumn = 2, GridRow = 3},
};
Pawns.ItemsSource = pawnList;
}
6
{
Console.WriteLine("Hoorah!");
isPawnSelected = true;
selectedPawnColumn = ((e.Source as Button).DataContext as Pawn).GridColumn;
selectedPawnRow = ((e.Source as Button).DataContext as Pawn).GridRow;
}
<Window.Resources>
<Style TargetType="Ellipse"
x:Key="FirstPlayerPawn">
7
<Setter Property="Fill">
<Setter.Value>
<SolidColorBrush Color="Black"/>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="Ellipse"
x:Key="SecondPlayerPawn">
<Setter Property="Fill">
<Setter.Value>
<SolidColorBrush Color="White"/>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="3*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ItemsControl Name="Pawns"
Grid.Row="1"
Grid.Column="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid
ShowGridLines="True"
Name="GameGrid"
Background="Gray">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
8
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Row" Value="{Binding GridRow}" />
<Setter Property="Grid.Column" Value="{Binding GridColumn}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Click="OnPawnSelect"
KeyDown="Button_KeyDown">
<Button.Template>
<ControlTemplate>
<Ellipse Stroke="Black"
StrokeThickness="3"
Style="{Binding Style}"/>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True"/>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
// Include namespace system
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
<Application x:Class="neutreekoCSHARP.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:neutreekoCSHARP"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
9
</Application>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace neutreekoCSHARP
{
public class UIGame : Game
{
public int[,] turn(int pawnRow, int pawnColumn, int direction)
{
var ai = new AI(this);
ai.game_.currentPlayer_ = 1;
playUserMove(pawnRow, pawnColumn, direction);
new BoardOperations(ai.game_.board_).displayBoard();
if (hasWon(currentPlayer_))
Console.WriteLine("Game over. Player\'s " + currentPlayer_.ToString() + " victory.");
return ai.game_.board_;
}
if (hasWon(currentPlayer_))
Console.WriteLine("Game over. Player\'s " + currentPlayer_.ToString() + " victory.");
return ai.game_.board_;
}
}
}
// Include namespace system
namespace neutreekoCSHARP
{
public abstract class Strategy
{
//Turn on which the strategy is applied.
public Move currentMove_;
public abstract int run();
namespace neutreekoCSHARP
{
public sealed class Settings
{
/**
* Choice of two opponents.
* ie. The game can be multiplayer, human-AI, or AI-AI.
*/
public
const PlayerType PLAYER_1 = PlayerType.HUMAN;
public
const PlayerType PLAYER_2 = PlayerType.AI;
10
/**
* Maximum depth of recursive analysis.
* ie. Number of hits the AI will see ahead of time.
*/
public
const int MAX_MINMAX_DEPTH = 7;
/**
* Maximum depth of the recursive count of the number of possible errors.
* The number must be less than or equal to the depth of the assessment.
* ie. The AI will count the number of fatal errors that the opponent can
* do in the next round.
*/
public
const int MAX_OPENINGS_DEPTH = 4;
}
}
// Include namespace system
namespace neutreekoCSHARP
{
public enum PlayerType
{
AI, HUMAN
}
}
// Include namespace system
namespace neutreekoCSHARP
{
public class Move
{
public Coords position;
public Coords direction;
public Move(Coords position, Coords direction)
{
this.position = position;
this.direction = direction;
}
}
}
// Include namespace system
using System;
namespace neutreekoCSHARP
{
public class MinMax
{
public Game game_;
public AI ai_;
public int score_;
public int nOpenings_;
public MinMax(AI ai)
{
game_ = ai.game_;
ai_ = ai;
}
public int run()
{
if (game_.hasWon(game_.currentPlayer_))
return 1000;
public StrategyForMax(int minScore, int maxScore, int depth, Game game_, AI ai_)
:base (minScore, maxScore, depth)
{
player_ = game_.getOpponent();
this.game_ = game_;
this.ai_ = ai_;
}
namespace neutreekoCSHARP
{
namespace neutreekoCSHARP
13
{
public abstract class Game
{
public int[,] board_ = new int[5, 5];
public BoardOperations boardOperations_;
// Coordinates of the pawns. [, player1, player2] [pawn1, pawn2, pawn3].
public Coords[,] pawns_ = new Coords[3, 3];
public int currentPlayer_ = 2;
// 8 directions possibles (NO-N-NE-O-E-SO-S-SE)
public
readonly Coords[] directions_ = new Coords[8];
public Game()
{
boardOperations_ = new BoardOperations(board_);
if (isValidDirection)
{
if (position.isOnBoard())
{
if (this.board_[i, j] == this.currentPlayer_)
{
var move = new Move(position, this.directions_[direction]);
if (this.boardOperations_.isValidMove(move))
{
this.move(move);
return;
}
15
else
{
Console.WriteLine("Direction invalid");
}
}
else
{
Console.WriteLine("No pawns available");
}
}
else
{
Console.WriteLine("Position invalid");
}
}
else
{
Console.WriteLine("Direction invalid");
}
}
}
if (isValidDirection)
{
if (position.isOnBoard())
{
if (this.board_[i, j] == this.currentPlayer_)
{
var move = new Move(position, this.directions_[direction]);
if (this.boardOperations_.isValidMove(move))
{
this.move(move);
return;
}
else
{
Console.WriteLine("Direction invalid");
}
}
16
else
{
Console.WriteLine("No pawns available");
}
}
else
{
Console.WriteLine("Position invalid");
}
}
else
{
Console.WriteLine("Direction invalid");
}
}
}
namespace neutreekoCSHARP
{
public class Coords
{
public int i;
public int j;
public Coords(int i, int j)
{
this.i = i;
this.j = j;
}
public Coords add(Coords coords)
{
return new Coords(this.i + coords.i, this.j + coords.j);
}
public void addAssign(Coords coords)
{
this.i += coords.i;
this.j += coords.j;
}
public Coords clone()
{
return new Coords(i, j);
}
public bool equals(Coords coords)
{
return this.i == coords.i && this.j == coords.j;
}
public bool isOnBoard()
{
return this.i >= 0 && this.i < 5 && this.j >= 0 && this.j < 5;
}
}
}
// Include namespace system
using System;
namespace neutreekoCSHARP
{
public class BoardOperations
{
17
private int[,] board_;
public BoardOperations(int[,] board)
{
board_ = board;
}
public void displayBoard()
{
for (var i = 0; i < 5; i++)
{
for (var j = 0; j < 5; j++)
{
if (board_[i, j] != 0)
Console.Write(board_[i, j].ToString() + " ");
else
Console.Write("- ");
}
Console.WriteLine();
}
Console.WriteLine();
}
public void swap(Coords a, Coords b)
{
var tmp = board_[a.i, a.j];
board_[a.i, a.j] = board_[b.i, b.j];
board_[b.i, b.j] = tmp;
}
public bool isValidMove(Move move)
{
var newPosition = move.position.add(move.direction);
if (newPosition.isOnBoard())
{
return board_[newPosition.i, newPosition.j] == 0;
}
return false;
}
}
}
// Include namespace system
using System;
namespace neutreekoCSHARP
{
/**
Introduces an AI with a min-max algorithm.
*/
public class AIGame : Game
{
public void start()
{
// Initialisation.
var ai = new AI(this);
// Main loop.
do
{
currentPlayer_ = getOpponent();
boardOperations_.displayBoard();
Console.WriteLine("Player " + currentPlayer_.ToString() + " : ");
var player = (currentPlayer_ == 1) ? Settings.PLAYER_1 : Settings.PLAYER_2;
if (player == PlayerType.AI)
{
ai.playBestMove();
}
else
{
playUserMove();
}
18
} while (!hasWon(currentPlayer_));
boardOperations_.displayBoard();
Console.WriteLine("Game over. Player\'s " + currentPlayer_.ToString() + " victory.");
}
}
}
// Include namespace system
using System;
namespace neutreekoCSHARP
{
public class AI
{
public Game game_;
public AI(Game game)
{
game_ = game;
}
public int forEachPossibleMove(Strategy strategy, int player)
{
var res = 0;
// For each piece
for (var i = 0; i < 3; i++)
{
var oldPosition = game_.pawns_[player, i];
// foreach valid move
foreach (Coords direction in game_.directions_)
{
var move = new Move(oldPosition, direction);
if (game_.boardOperations_.isValidMove(move))
{
Coords newPosition = game_.move(move);
strategy.currentMove_ = move;
res = strategy.run();
game_.pawns_[player, i] = oldPosition;
game_.boardOperations_.swap(newPosition, oldPosition);
if (strategy.shouldExitNow())
{
return res;
}
}
}
}
return res;
}
public void playBestMove()
{
// Initialisation.
var strategy = new FindBestMoveStrategy(this);
// We apply the min-max algorithm.
forEachPossibleMove(strategy, game_.currentPlayer_);
// Interpretation
if (strategy.maxScore > 0)
{
Console.WriteLine("I'm going to win...\n");
}
else if (strategy.maxScore < 0)
{
Console.WriteLine("You can win ...\n");
}
19
// Finally, we make the best move.
game_.move(strategy.bestMove);
}
private class FindBestMoveStrategy : Strategy
{
public FindBestMoveStrategy(AI ai)
{
this.ai = ai;
}
public int maxScore = -1001;
public Move bestMove = null;
private int maxNOpenings = 0;
private readonly AI ai;
20
Рисунок 3.1 –
Рисунок 3.2 –
3.2
21
ВИСНОВОК
22
КРИТЕРІЇ ОЦІНЮВАННЯ
23