You are on page 1of 76

Міністерство освіти і науки України

Національний технічний університет України «Київський політехнічний


інститут імені Ігоря Сікорського"
Факультет інформатики та обчислювальної техніки

Кафедра інформатики та програмної інженерії

Звіт

з лабораторної роботи № 6 з дисципліни


«Проектування алгоритмів»

„Пошук в умовах протидії, ігри з елементом випадковості, ігри з неповною


інформацією”

Виконав(ла) Гавриленко Ян Сергійович


(шифр, прізвище, ім'я, по батькові)

Перевірив Головченко М.Н.


(прізвище, ім'я, по батькові)

Київ 2021
ЗМІСТ

1 МЕТА ЛАБОРАТОРНОЇ РОБОТИ......................................................3

2 ЗАВДАННЯ...............................................................................................4

3 ВИКОНАННЯ...........................................................................................6

3.1 ПРОГРАМНА РЕАЛІЗАЦІЯ АЛГОРИТМУ....................................................6


3.1.1 Вихідний код.....................................................................................6
3.1.2 Приклади роботи............................................................................6

ВИСНОВОК.....................................................................................................7

КРИТЕРІЇ ОЦІНЮВАННЯ..........................................................................8

2
1 МЕТА ЛАБОРАТОРНОЇ РОБОТИ
Мета роботи - вивчити основні підходи до формалізації алгоритмів
знаходження рішень задач в умовах протидії. Ознайомитися з підходами до
програмування алгоритмів штучного інтелекту в іграх з елементами
випадковості та в іграх з неповною інформацією.

3
2 ЗАВДАННЯ

Для ігор з елементами випадковості, згідно варіанту (таблиця 2.1)


реалізувати візуальний ігровий додаток, з користувацьким інтерфейсом, не
консольним, для гри користувача з комп'ютерним опонентом. Для реалізації
стратегії гри комп'ютерного опонента використовувати алгоритм мінімакс.
Для карткових ігор, згідно варіанту (таблиця 2.1), реалізувати візуальний
ігровий додаток, з користувацьким інтерфейсом, не консольним, для гри
користувача з комп'ютерним опонентом. Потрібно реалізувати стратегію
комп'ютерного опонента, і звести гру до гри з повною інформацією (див.
Лекцію), далі реалізувати стратегію гри комп'ютерного опонента за допомогою
алгоритму мінімаксу або альфа-бета-відсікань.
Реалізувати анімацію процесу жеребкування (+1 бал) або реалізувати
анімацію процесу роздачі карт і анімацію ходів (+1 бал).
Реалізувати варто тільки одне з бонусних завдань.
Зробити узагальнений висновок лабораторної роботи.
Таблиця 2.1 – Варіанти
№ Варіант
1 Яцзи https://game-wiki.guru/published/igryi/yaczzyi.html
2 Лудо http://www.iggamecenter.com/info/ru/ludo.html
3 Генерал http://www.rules.net.ru/kost.php?id=7
4 Свиня http://www.rules.net.ru/kost.php?id=3
5 Тринадцять http://www.rules.net.ru/kost.php?id=16
6 Индійські кості http://www.rules.net.ru/kost.php?id=9
7 Закрити сектор http://gamerules.ru/igry-v-kosti-part1#zakroi-sektor
8 Двадцять одне http://gamerules.ru/igry-v-kosti-part8#dvadtsat-odno
9 Бакси http://gamerules.ru/igry-v-kosti-part10#baksy
10 Подвійний генерал http://gamerules.ru/igry-v-kosti-part6#dvoinoi-general
11 101 https://www.durbetsel.ru/2_101.htm

4
12 Ночка http://life-games.net/index/nochka/0-192
13 Табу https://www.durbetsel.ru/2_taboo.htm
14 Чотири рядки https://www.durbetsel.ru/2_chetyre_stroki.htm
15 Свої козирі https://www.durbetsel.ru/2_svoi-koziri.htm
16 Війна з ботами https://www.durbetsel.ru/2_voina_s_botami.htm
17 Вибух https://www.durbetsel.ru/2_vzryv.htm
18 Останній гравець https://www.durbetsel.ru/2_posledny_igrok.htm
19 Скарбнички https://www.durbetsel.ru/2_sunduchki.htm
20 Богач https://www.durbetsel.ru/2_bogach.htm
21 Редуду https://www.durbetsel.ru/2_redudu.htm
22 Эльферн https://www.durbetsel.ru/2_elfern.htm
23 Ремінь https://www.durbetsel.ru/2_remen.htm
24 Курка https://www.durbetsel.ru/2_kurisa.htm
25 Навалка https://www.durbetsel.ru/2_navalka.htm
26 Яцзи https://game-wiki.guru/published/igryi/yaczzyi.html

27 Лудо http://www.iggamecenter.com/info/ru/ludo.html

28 Генерал http://www.rules.net.ru/kost.php?id=7

29 Свиня http://www.rules.net.ru/kost.php?id=3

30 Тринадцять http://www.rules.net.ru/kost.php?id=16

5
3 ВИКОНАННЯ

3.1 Програмна реалізація алгоритму

3.1.1 Вихідний код


package com.ludo.LUDOSimulator;
import java.util.Random;
/**
* Example of automatic LUDO player
* @author David Johan Christensen
*
* @version 0.9
*
*/
public class AggressiveLUDOPlayer implements LUDOPlayer {

LUDOBoard board;
Random rand;
public AggressiveLUDOPlayer(LUDOBoard board)
{
this.board = board;
rand = new Random();
}

public void play() {


board.print("Agressive player playing");

int[] myBricksValue = new int[4];


board.rollDice();
float max =-1;
int bestIndex = -1;
for(int i=0;i<4;i++)
{
float value = analyzeBrickSituation(i);
if(value>max&&value>0) {
bestIndex = i;
max = value;
}
}
if(bestIndex!=-1) board.moveBrick(bestIndex);
}
6
public float analyzeBrickSituation(int i) {
if(board.moveable(i)) {
int[][] current_board = board.getBoardState();
int[][] new_board = board.getNewBoardState(i,
board.getMyColor(), board.getDice());

if(hitOpponentHome(current_board,new_board)) {
return 2+rand.nextFloat();
}
else {
return 1+rand.nextFloat();
}
}
else {
return 0;
}
}
private boolean isSafe(int index) {
return board.isGlobe(index)||
board.almostHome(index,board.getMyColor());
}
private boolean hitOpponentHome(int[][] current_board, int[][]
new_board) {
int opponentsOnField = 0;
for(int i=0;i<4;i++) {
for(int j=0;j<4;j++) {
if(board.getMyColor()!=i) {
if(board.atField(current_board[i][j])&&!
board.atField(new_board[i][j])) {
return true;
}
}
}
}
return false;
}
}

package com.ludo.LUDOSimulator;
/**
* Example of automatic LUDO player
* @author David Johan Christensen
7
*
* @version 0.9
*
*/
public class FifoLUDOPlayer implements LUDOPlayer {
LUDOBoard board;
public FifoLUDOPlayer(LUDOBoard board)
{
this.board = board;
}
public void play() {
board.print("Fifo player playing");
board.rollDice();
for(int i=0;i<4;i++)
{
if(board.moveable(i)) {
board.moveBrick(i);
return;
}
}
}
public synchronized void delay() {
try {
wait(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}package com.ludo.LUDOSimulator;

8
public interface GameEndedListener {
public void gameEnded(int[] result);
}package com.ludo.LUDOSimulator;
import com.minmax.Helpers;
import com.helpers.prprNeuralLUDOPlayer;
import com.helpers.prprTDLUDOPlayer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class LUDO extends Frame implements ActionListener {


private static final long serialVersionUID = 1L;

static LUDOBoard board;

public LUDO() {
super("LUDO Simulator");
setBackground(Color.white);
board = new LUDOBoard();
add(board, BorderLayout.CENTER);

Menu optionsMenu = new Menu("Options", true);


optionsMenu.add("Reset Game");
optionsMenu.addActionListener(this);

MenuBar mbar = new MenuBar();


mbar.add(optionsMenu);
9
setBounds(30, 50, 1000, 800); // Set size and position of window.

setResizable(false);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
LUDO.this.dispose();
System.exit(0);

}
});
setVisible(visual);
}

public int playMinMax(Helpers c, int gameCount) {


int[] result = new int[4];
prprNeuralLUDOPlayer p = new prprNeuralLUDOPlayer(board,
c);
board.setPlayer(p, LUDOBoard.YELLOW);
board.setPlayer(new SemiSmartLUDOPlayer(board),
LUDOBoard.RED);
board.setPlayer(new SemiSmartLUDOPlayer(board),
LUDOBoard.BLUE);
board.setPlayer(new SemiSmartLUDOPlayer(board),
LUDOBoard.GREEN);

try {
for (int i = 0; i < gameCount; i++) {
board.play();
board.kill();
10
result[0] += board.getPoints()[0];
result[1] += board.getPoints()[1];
result[2] += board.getPoints()[2];
result[3] += board.getPoints()[3];

board.reset();
p.reset(board);
board.setPlayer(p, LUDOBoard.YELLOW);
board.setPlayer(new SemiSmartLUDOPlayer(board),
LUDOBoard.RED);
board.setPlayer(new SemiSmartLUDOPlayer(board),
LUDOBoard.BLUE);
board .setPlayer(new
SemiSmartLUDOPlayer(board),
LUDOBoard.GREEN);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return result[0];
}

public void actionPerformed(ActionEvent event) {


if (event.getActionCommand() == "Reset Game") {
board.kill();
}
}

public static boolean visual = true;


11
public void play() {
System.out.println("Playing Ludo");
int[] result = new int[4];
int iter = 50000;
prprTDLUDOPlayer p = new prprTDLUDOPlayer(board);
p.Euristic = 0.75;
board.setPlayer(p, LUDOBoard.YELLOW);
board.setPlayer(new RandomLUDOPlayer(board),
LUDOBoard.RED);
board.setPlayer(new RandomLUDOPlayer(board),
LUDOBoard.BLUE);
board.setPlayer(new RandomLUDOPlayer(board),
LUDOBoard.GREEN);

try {
for (int i = 0; i < iter; i+=4) {
board.play();
board.kill();

result[0] += board.getPoints()[0];
result[1] += board.getPoints()[1];
result[2] += board.getPoints()[2];
result[3] += board.getPoints()[3];

p.play();
board.reset();
p.reset(board);

if (i < iter * 0.5)


12
p.Euristic = 0.75;
else if (i < iter * 0.8)
p.Euristic = 0.9;
else if (i < iter * 0.9)
p.Euristic = 0.98;

board.setPlayer(p, LUDOBoard.YELLOW);
board.setPlayer(new RandomLUDOPlayer(board),
LUDOBoard.RED);
board.setPlayer(new RandomLUDOPlayer(board),
LUDOBoard.BLUE);
board
.setPlayer(new
RandomLUDOPlayer(board),
LUDOBoard.GREEN);
if ((i % 100) == 0 && i != 0) {
System.out.println(result[0]);
result = new int[4];
}
}

} catch (InterruptedException e) {
e.printStackTrace();
}

p.Debug();
}

public static void main(String[] args) {


LUDO l = new LUDO();
13
l.play();
}
}package com.ludo.LUDOSimulator;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;

/**
* The LUDOBoard class is the core class of the LUDO simulator used in the
couse
* of AI01 - tools of artificial intelligence.
*
* Automatic LUDO players may use this class to roll the dice, move a brick
and
* get information about the states of the game relevant to how the bricks
* should be moved.
*
* @author David Johan Christensen
* @version 0.91
*
*
*/
public class LUDOBoard extends Canvas {

public static final int BLUE = 2;


14
public static final int GREEN = 3;
public static final int RED = 1;
private static final long serialVersionUID = 1L;
public static final int YELLOW = 0;

public static void trap() {


try {
System.in.read();
System.in.read();
} catch (Exception e) {
e.printStackTrace();
}
}

private LUDOPlayer bluePlayer;


private BufferedImage boardImage, noDiceImage, dice1Image,
dice2Image,
dice3Image, dice4Image, dice5Image, dice6Image,
redBrickImage1,
redBrickImage2, redBrickImage3, redBrickImage4,
blueBrickImage1,
blueBrickImage2, blueBrickImage3, blueBrickImage4,
yellowBrickImage1, yellowBrickImage2,
yellowBrickImage3,
yellowBrickImage4, greenBrickImage1, greenBrickImage2,
greenBrickImage3, greenBrickImage4;
private int boardSize = 750;
private boolean brickMoved = true;
private int[][] bricks = { { 100, 101, 102, 103 }, { 200, 201, 202, 203 },
{ 300, 301, 302, 303 }, { 400, 401, 402, 403 } };
15
private int brickSize = boardSize / 25;
private int currentColor;
private String debugString = "Welcome to this LUDO simulator...";
private int dice = 0;
private int[] endFieldSquares = { 50, 11, 24, 37 };

private int[][] fieldSquaresXYPos = { { 92, 328 }, { 140, 329 },


{ 190, 330 }, { 236, 330 }, { 286, 331 }, { 329, 289 },
{ 329, 238 }, { 329, 190 }, { 329, 141 }, { 327, 90 }, { 329,
38 },
{ 376, 35 }, { 427, 35 }, { 428, 86 }, { 429, 136 }, { 427,
187 },
{ 426, 235 }, { 427, 289 }, { 470, 330 }, { 514, 329 },
{ 561, 330 }, { 611, 328 }, { 657, 332 }, { 713, 329 },
{ 716, 380 }, { 715, 430 }, { 662, 431 }, { 616, 431 },
{ 568, 431 }, { 516, 430 }, { 469, 430 }, { 431, 470 },
{ 423, 516 }, { 431, 562 }, { 428, 621 }, { 430, 667 },
{ 426, 718 }, { 376, 721 }, { 330, 722 }, { 326, 669 },
{ 329, 622 }, { 331, 572 }, { 330, 517 }, { 328, 472 },
{ 292, 435 }, { 240, 432 }, { 197, 436 }, { 145, 434 },
{ 92, 436 }, { 40, 434 }, { 39, 384 }, { 42, 332 } };
private ArrayList<GameEndedListener> gameEndedListeners = new
ArrayList<GameEndedListener>();

private int[] globes = { 0, 8, 13, 21, 26, 34, 39, 47 };


private LUDOPlayer greenPlayer;
private int[][][] homeSquaresXYPos = {
{ { 90, 378 }, { 140, 380 }, { 192, 382 }, { 242, 380 },
{ 288, 380 }, { 340, 380 } },
{ { 378, 90 }, { 376, 140 }, { 378, 186 }, { 378, 240 },
16
{ 380, 292 }, { 378, 344 } },
{ { 666, 380 }, { 616, 378 }, { 568, 380 }, { 516, 378 },
{ 466, 378 }, { 414, 376 } },
{ { 380, 670 }, { 378, 618 }, { 380, 570 }, { 380, 516 },
{ 380, 468 }, { 378, 422 } } };

public boolean killed = false;


private int point = 3;
private int[] points = new int[4];
private Random rand;
private LUDOPlayer redPlayer;
private int[] stars = { 5, 11, 18, 24, 31, 37, 44, 50 };
private int startColor = YELLOW;
private int[] startFieldSquares = { 0, 13, 26, 39 };
private int[][][] startSquaresXYPos = {
{ { 91, 90 }, { 192, 90 }, { 90, 193 }, { 190, 193 } },
{ { 563, 92 }, { 662, 88 }, { 564, 193 }, { 659, 194 } },
{ { 563, 568 }, { 663, 568 }, { 562, 669 }, { 663, 669 } },
{ { 93, 569 }, { 190, 568 }, { 91, 667 }, { 190, 668 } } };
private int steps = 25;
private int turns = 0;

private int[] turnsCounter = { 0, 0, 0, 0 };

private float waitTime = 1000 / steps;

private LUDOPlayer yellowPlayer;

public LUDOBoard() {
reset();
17
if (!LUDO.visual)
return;
setSize(1000, 800);
try {
String pathStart = "src/com/ludo/";
boardImage = ImageIO.read(new File(pathStart +
"ludoboard.jpg"));
redBrickImage1 = ImageIO.read(new File(pathStart +
"redbrick.png"));
redBrickImage2 = ImageIO.read(new File(pathStart +
"redbrick.png"));
redBrickImage3 = ImageIO.read(new File(pathStart +
"redbrick.png"));
redBrickImage4 = ImageIO.read(new File(pathStart +
"redbrick.png"));

blueBrickImage1 = ImageIO.read(new File(pathStart +


"bluebrick.png"));
blueBrickImage2 = ImageIO.read(new File(pathStart +
"bluebrick.png"));
blueBrickImage3 = ImageIO.read(new File(pathStart +
"bluebrick.png"));
blueBrickImage4 = ImageIO.read(new File(pathStart +
"bluebrick.png"));

yellowBrickImage1 = ImageIO.read(new File(pathStart +


"yellowbrick.png"));
yellowBrickImage2 = ImageIO.read(new File(pathStart +
"yellowbrick.png"));

18
yellowBrickImage3 = ImageIO.read(new File(pathStart +
"yellowbrick.png"));
yellowBrickImage4 = ImageIO.read(new File(pathStart +
"yellowbrick.png"));

greenBrickImage1 = ImageIO.read(new File(pathStart +


"greenbrick.png"));
greenBrickImage2 = ImageIO.read(new File(pathStart +
"greenbrick.png"));
greenBrickImage3 = ImageIO.read(new File(pathStart +
"greenbrick.png"));
greenBrickImage4 = ImageIO.read(new File(pathStart +
"greenbrick.png"));

dice1Image = ImageIO.read(new File(pathStart +


"dice1.jpg"));
dice2Image = ImageIO.read(new File(pathStart +
"dice2.jpg"));
dice3Image = ImageIO.read(new File(pathStart +
"dice3.jpg"));
dice4Image = ImageIO.read(new File(pathStart +
"dice4.jpg"));
dice5Image = ImageIO.read(new File(pathStart +
"dice5.jpg"));
dice6Image = ImageIO.read(new File(pathStart +
"dice6.jpg"));
noDiceImage = ImageIO.read(new File(pathStart +
"no_dice.jpg"));
} catch (IOException e) {
e.printStackTrace();
19
System.exit(0);
}
}

public boolean almostHome(int index, int color) {


return index >= ((color + 1) * 100 + 4)
&& index < ((color + 1) * 100 + 9);
}
private synchronized void animateMove(int color, int nr, int fromIndex,
int toIndex) {

String colour = "";


switch (color) {
case 0:
colour = "YELLOW";
break;
case 1:
colour = "RED";
break;
case 2:
colour = "BLUE";
break;
case 3:
colour = "GREEN";
break;
}

if (!LUDO.visual)
return;
float startXPixel = (float) index2Pixel(fromIndex, color)[0]
20
- (brickSize / 2);
float startYPixel = (float) index2Pixel(fromIndex, color)[1]
- (brickSize / 2);
float endXPixel = (float) index2Pixel(toIndex, color)[0]
- (brickSize / 2);
float endYPixel = (float) index2Pixel(toIndex, color)[1]
- (brickSize / 2);

for (float i = 0; i < steps; i++) {


int x = (int) ((endXPixel - startXPixel) * i / steps +
startXPixel);
int y = (int) ((endYPixel - startYPixel) * i / steps +
startYPixel);
if (color == YELLOW)
getGraphics().drawImage(yellowBrickImage1, x, y,
brickSize,
brickSize, null);
if (color == RED)
getGraphics().drawImage(redBrickImage1, x, y,
brickSize,
brickSize, null);
if (color == BLUE)
getGraphics().drawImage(blueBrickImage1, x, y,
brickSize,
brickSize, null);
if (color == GREEN)
getGraphics().drawImage(greenBrickImage1, x, y,
brickSize,
brickSize, null);

21
try {
wait((long) waitTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public boolean atField(int index) {


return index < 100;
}

public boolean atHome(int index, int color) {


return index == ((color + 1) * 100 + 9);
}

private int countBricksOn(int index) {


int count = 0;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (bricks[i][j] == index)
count++;
}
}
return count;
}

public int[][] getBoardState() {


int[][] bs = new int[4][4];
22
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
bs[i][j] = bricks[i][j];
}
}
return bs;
}

public int[] getBricks(int player) {


return bricks[player];
}

public int getDice() {


return dice;
}

public int[] getMyBricks() {


int[] b = new int[4];
b[0] = bricks[currentColor][0];
b[1] = bricks[currentColor][1];
b[2] = bricks[currentColor][2];
b[3] = bricks[currentColor][3];
return b;
}

public int getMyColor() {


return currentColor;
}

public int[][] getNewBoardState(int nr, int color, int dice2) {


23
int new_turns = -1;
int[][] new_bricks_state = getBoardState();
int index = new_bricks_state[color][nr];

/* Moving out of the start area */


if (inStartArea(index, color)) {
if (dice2 == 6) {
new_bricks_state[color][nr] =
startFieldSquares[color];
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (new_bricks_state[i][j] ==
new_bricks_state[color][nr]
&& i != color) {
new_bricks_state[i][j] = (i + 1) *
100 + j;
}
}
}
new_turns = 1;
return new_bricks_state;
} else {
return new_bricks_state; // Unable to move the
selected brick...
}
} else if (!(index <= endFieldSquares[color] && (index + dice2) >
endFieldSquares[color])
&& index < 100)
{
int moveToIndex = (index + dice2) % 52;
24
if (moveToIndex != endFieldSquares[color] &&
isStar(moveToIndex))
moveToIndex = nextStar(moveToIndex);
else if (moveToIndex == endFieldSquares[color])
moveToIndex = (color + 1) * 100 + 9;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (new_bricks_state[i][j] == moveToIndex &&
i != color) {
if (isGlobe(moveToIndex)) {
moveToIndex = (color + 1) * 100
+ nr;
} else if (countBricksOn(moveToIndex)
>= 2) {
moveToIndex = (color + 1) * 100
+ nr;
} else {
new_bricks_state[i][j] = (i + 1) *
100 + j;
}
}
}
}
new_bricks_state[color][nr] = moveToIndex;
if (dice2 == 6)
new_turns = 1;
else
new_turns = 0;
return new_bricks_state;
} else { /* Moving in(to) the home area */
25
if (index == ((1 + color) * 100 + 9)) {
return new_bricks_state; // Unable to move the
selected brick...
// illigal move already home
}
if (index < 51) { /* still on the field */
new_bricks_state[color][nr] = (index + dice2)
- (1 + endFieldSquares[color])
+ ((1 + color) * 100 + 4);
} else {
if ((index + dice2) > ((1 + color) * 100 + 9)) {
new_bricks_state[color][nr] = 2 * ((1 + color) *
100 + 9)
- (index + dice2);
} else
new_bricks_state[color][nr] = (index + dice2);
}
if (dice2 == 6) {
new_turns = 1;
} else {
new_turns = 0;
}
return new_bricks_state;
}
}

public int[] getPoints() {


return points;
}

26
protected int[] index2Pixel(int index, int color) {

/* Start Squares */
if (index >= 100 && index < 104)
return startSquaresXYPos[color][index - 100];
else if (index >= 200 && index < 204)
return startSquaresXYPos[color][index - 200];
else if (index >= 300 && index < 304)
return startSquaresXYPos[color][index - 300];
else if (index >= 400 && index < 404)
return startSquaresXYPos[color][index - 400];

/* Field Squares */
if (index < 52) {
return fieldSquaresXYPos[index];
}

/* Home Squares */
if (index >= 104 && index < 110)
return homeSquaresXYPos[color][index - 104];
else if (index >= 204 && index < 210)
return homeSquaresXYPos[color][index - 204];
else if (index >= 304 && index < 310)
return homeSquaresXYPos[color][index - 304];
else if (index >= 404 && index < 410)
return homeSquaresXYPos[color][index - 404];

System.out.println("Index ikke genkendt " + index);


return null;
}
27
private boolean inPlay(int index, int color) {
return !atHome(index, color) && !inStartArea(index, color);
}

public boolean inStartArea(int index, int color) {


return index >= (color + 1) * 100 && index <= (((color + 1) *
100) + 3);
}

public boolean isDone(int color) {


return atHome(bricks[color][0], color)
&& atHome(bricks[color][1], color)
&& atHome(bricks[color][2], color)
&& atHome(bricks[color][3], color);
}

public boolean isGlobe(int index) {


for (int i = 0; i < globes.length; i++) {
if (globes[i] == index)
return true;
}
return false;
}

public boolean isStar(int index) {


for (int i = 0; i < stars.length; i++) {
if (stars[i] == index)
return true;
}
28
return false;
}

public void kill() {


killed = true;
}

public boolean moveable(int nr) {


if (inStartArea(bricks[currentColor][nr], currentColor) && dice !=
6) {
return false;
}
if (atHome(bricks[currentColor][nr], currentColor)) {
return false;
}
return true;
}

public boolean moveBrick(int nr) {


if (nr < 0 || nr > 3)
throw new RuntimeException("Not valid brick nr: " + nr);
if (brickMoved) {
print("You must roll the dice before moving");
return false;
}
int index = bricks[currentColor][nr];
/* Moving out of the start area */
if (inStartArea(index, currentColor)) {
if (dice == 6) {

29
animateMove(currentColor, nr, bricks[currentColor]
[nr],
startFieldSquares[currentColor]);
bricks[currentColor][nr] =
startFieldSquares[currentColor];
// Hit opponent home from "my" globe
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (bricks[i][j] == bricks[currentColor]
[nr]
&& i != currentColor) {
animateMove(i, j, bricks[i][j], (i +
1) * 100 + j);
bricks[i][j] = (i + 1) * 100 + j;
}
}
}
brickMoved = true;
turns = 1;
print("Now roll the dice...");
return true;
} else {
print("Unable to move the selected brick...");
return false; // Illigal move
}
} else if (!(index <= endFieldSquares[currentColor] && (index +
dice) > endFieldSquares[currentColor])
&& index < 100) /* Moving on the field */
{
int moveToIndex = (index + dice) % 52;
30
animateMove(currentColor, nr, bricks[currentColor][nr],
moveToIndex);

// check for stars


if (moveToIndex != endFieldSquares[currentColor]
&& isStar(moveToIndex)) {
// animateMove(currentColor,nr,bricks[currentColor]
[nr],moveToIndex);
animateMove(currentColor, nr, moveToIndex,
nextStar(moveToIndex));
moveToIndex = nextStar(moveToIndex);
} else if (moveToIndex == endFieldSquares[currentColor])
{
// animateMove(currentColor,nr,bricks[currentColor]
[nr],moveToIndex);
animateMove(currentColor, nr, moveToIndex,
(currentColor + 1) * 100 + 9);
moveToIndex = (currentColor + 1) * 100 + 9;
}
// check for home hitting
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (bricks[i][j] == moveToIndex && i !=
currentColor) {
// someone needs to be hit home
if (isGlobe(moveToIndex)) {// he is on a
globe
animateMove(currentColor, nr,
moveToIndex,

31
(currentColor + 1) *
100 + nr);
moveToIndex = (currentColor + 1)
* 100 + nr; // I am
// hit
// home
} else if (countBricksOn(moveToIndex)
>= 2) { // there
// are
// at
// least
// two
// bricks
animateMove(currentColor, nr,
moveToIndex,
(currentColor + 1) *
100 + nr);
moveToIndex = (currentColor + 1)
* 100 + nr; // I am
// hit
// home
} else { // I hit him home
animateMove(i, j, bricks[i][j], (i +
1) * 100 + j);
bricks[i][j] = (i + 1) * 100 + j;
}
}
}
}
bricks[currentColor][nr] = moveToIndex;
32
brickMoved = true;
if (dice == 6)
turns = 1;
else
turns = 0;
print("Now roll the dice...");
return true;
} else { /* Moving in(to) the home area */
if (index == ((1 + currentColor) * 100 + 9)) {
print("Unable to move the selected brick...");
return false; // Illigal move already home
}
if (index < 51) { /* still on the field */
animateMove(currentColor, nr, bricks[currentColor]
[nr],
(index + dice) - (1 +
endFieldSquares[currentColor])
+ ((1 + currentColor) * 100
+ 4));
bricks[currentColor][nr] = (index + dice)
- (1 + endFieldSquares[currentColor])
+ ((1 + currentColor) * 100 + 4);
} else {
if ((index + dice) > ((1 + currentColor) * 100 + 9)) {
animateMove(currentColor, nr,
bricks[currentColor][nr], 2
* ((1 + currentColor) * 100 + 9) -
(index + dice));
bricks[currentColor][nr] = 2

33
* ((1 + currentColor) * 100 + 9) -
(index + dice);
} else {
animateMove(currentColor, nr,
bricks[currentColor][nr],
(index + dice));
bricks[currentColor][nr] = (index + dice);
}
}
brickMoved = true;
if (dice == 6) {
turns = 1;
print("Now roll the dice...");
} else {
turns = 0;
print("Next Player...");
}
return true;
}
}

private void nextPlayer() {


currentColor = (currentColor + 1) % 4;
if (!inPlay(bricks[currentColor][0], currentColor)
&& !inPlay(bricks[currentColor][1], currentColor)
&& !inPlay(bricks[currentColor][2], currentColor)
&& !inPlay(bricks[currentColor][3], currentColor)) {
turns = 3;
} else {
turns = 1;
34
}
brickMoved = true;
dice = 0;
repaint();
}

private int nextStar(int index) {


for (int i = 0; i < stars.length; i++) {
if (stars[i] == index)
return stars[(i + 1) % stars.length];
}
return 0;
}

public boolean nothingToDo() {


return !moveable(0) && !moveable(1) && !moveable(2) && !
moveable(3);
}

public void paint(Graphics graphics) {


paintBoardImage(graphics);
paintDice(graphics);
paintBricks(graphics);
paintTurn(graphics);
paintDebugString(graphics);
}

private void paintBoardImage(Graphics graphics) {


graphics.drawImage(boardImage, 0, 0, boardSize, boardSize,
null);
35
}

private void paintBricks(Graphics graphics) {


int[][] counter = new int[4][4];
for (int i = 0; i < 4; i++) { // color
for (int j = 0; j < 4; j++) { // reference brick
int ref = bricks[i][j];
for (int k = 0; k < 4; k++) { // brick of same color
if (ref == bricks[i][k]) {
counter[i][j]++;
}
}
}
}
for (int i = 0; i < 4; i++) {
switch (counter[0][i]) {
case 1:
graphics.drawImage(yellowBrickImage1,
index2Pixel(
bricks[YELLOW][i], YELLOW)[0]
- (brickSize / 2),
index2Pixel(bricks[YELLOW][i],
YELLOW)[1]
- (brickSize / 2), brickSize, brickSize,
null);
break;
case 2:
graphics.drawImage(yellowBrickImage2,
index2Pixel(
bricks[YELLOW][i], YELLOW)[0]
36
- (brickSize / 2),
index2Pixel(bricks[YELLOW][i],
YELLOW)[1]
- (brickSize / 2), brickSize, brickSize,
null);
break;
case 3:
graphics.drawImage(yellowBrickImage3,
index2Pixel(
bricks[YELLOW][i], YELLOW)[0]
- (brickSize / 2),
index2Pixel(bricks[YELLOW][i],
YELLOW)[1]
- (brickSize / 2), brickSize, brickSize,
null);
break;
case 4:
graphics.drawImage(yellowBrickImage4,
index2Pixel(
bricks[YELLOW][i], YELLOW)[0]
- (brickSize / 2),
index2Pixel(bricks[YELLOW][i],
YELLOW)[1]
- (brickSize / 2), brickSize, brickSize,
null);
break;
}
switch (counter[1][i]) {
case 1:

37
graphics.drawImage(redBrickImage1,
index2Pixel(bricks[RED][i],
RED)[0]
- (brickSize / 2),
index2Pixel(bricks[RED][i], RED)[1]
- (brickSize / 2), brickSize, brickSize,
null);
break;
case 2:
graphics.drawImage(redBrickImage2,
index2Pixel(bricks[RED][i],
RED)[0]
- (brickSize / 2),
index2Pixel(bricks[RED][i], RED)[1]
- (brickSize / 2), brickSize, brickSize,
null);
break;
case 3:
graphics.drawImage(redBrickImage3,
index2Pixel(bricks[RED][i],
RED)[0]
- (brickSize / 2),
index2Pixel(bricks[RED][i], RED)[1]
- (brickSize / 2), brickSize, brickSize,
null);
break;
case 4:
graphics.drawImage(redBrickImage4,
index2Pixel(bricks[RED][i],
RED)[0]
38
- (brickSize / 2),
index2Pixel(bricks[RED][i], RED)[1]
- (brickSize / 2), brickSize, brickSize,
null);
break;
}
switch (counter[2][i]) {
case 1:
graphics
.drawImage(blueBrickImage1,
index2Pixel(
bricks[BLUE][i], BLUE)[0]
- (brickSize / 2),
index2Pixel(bricks[BLUE][i],
BLUE)[1]
- (brickSize / 2), brickSize,
brickSize, null);
break;
case 2:
graphics
.drawImage(blueBrickImage2,
index2Pixel(
bricks[BLUE][i], BLUE)[0]
- (brickSize / 2),
index2Pixel(bricks[BLUE][i],
BLUE)[1]
- (brickSize / 2), brickSize,
brickSize, null);
break;
case 3:
39
graphics
.drawImage(blueBrickImage3,
index2Pixel(
bricks[BLUE][i], BLUE)[0]
- (brickSize / 2),
index2Pixel(bricks[BLUE][i],
BLUE)[1]
- (brickSize / 2), brickSize,
brickSize, null);
break;
case 4:
graphics
.drawImage(blueBrickImage4,
index2Pixel(
bricks[BLUE][i], BLUE)[0]
- (brickSize / 2),
index2Pixel(bricks[BLUE][i],
BLUE)[1]
- (brickSize / 2), brickSize,
brickSize, null);
break;
}
switch (counter[3][i]) {
case 1:
graphics.drawImage(greenBrickImage1, index2Pixel(
bricks[GREEN][i], GREEN)[0]
- (brickSize / 2),
index2Pixel(bricks[GREEN][i], GREEN)
[1]

40
- (brickSize / 2), brickSize,
brickSize, null);
break;
case 2:
graphics.drawImage(greenBrickImage2, index2Pixel(
bricks[GREEN][i], GREEN)[0]
- (brickSize / 2),
index2Pixel(bricks[GREEN][i], GREEN)
[1]
- (brickSize / 2), brickSize,
brickSize, null);
break;
case 3:
graphics.drawImage(greenBrickImage3, index2Pixel(
bricks[GREEN][i], GREEN)[0]
- (brickSize / 2),
index2Pixel(bricks[GREEN][i], GREEN)
[1]
- (brickSize / 2), brickSize,
brickSize, null);
break;
case 4:
graphics.drawImage(greenBrickImage4, index2Pixel(
bricks[GREEN][i], GREEN)[0]
- (brickSize / 2),
index2Pixel(bricks[GREEN][i], GREEN)
[1]
- (brickSize / 2), brickSize,
brickSize, null);
break;
41
}
}
}

private void paintDebugString(Graphics graphics) {


graphics.drawString(debugString, 732, 471);
}

private void paintDice(Graphics graphics) {


if (!brickMoved) {
switch (dice) {
case 0:
graphics.drawImage(noDiceImage, 760, 330, 100,
100, null);
break;
case 1:
graphics.drawImage(dice1Image, 760, 330, 100, 100,
null);
break;
case 2:
graphics.drawImage(dice2Image, 760, 330, 100, 100,
null);
break;
case 3:
graphics.drawImage(dice3Image, 760, 330, 100, 100,
null);
break;
case 4:
graphics.drawImage(dice4Image, 760, 330, 100, 100,
null);
42
break;
case 5:
graphics.drawImage(dice5Image, 760, 330, 100, 100,
null);
break;
case 6:
graphics.drawImage(dice6Image, 760, 330, 100, 100,
null);
break;
}
} else {
graphics.drawImage(noDiceImage, 760, 330, 100, 100,
null);
}
}

private void paintTurn(Graphics graphics) {


int x = 760;
int y = 200;
switch (currentColor) {
case RED:
switch (turns) {
case 1:
graphics.drawImage(redBrickImage1, x, y, 100, 100,
null);
break;
case 2:
graphics.drawImage(redBrickImage2, x, y, 100, 100,
null);
break;
43
case 3:
graphics.drawImage(redBrickImage3, x, y, 100, 100,
null);
break;
case 4:
graphics.drawImage(redBrickImage4, x, y, 100, 100,
null);
break;
}
break;
case GREEN:
switch (turns) {
case 1:
graphics.drawImage(greenBrickImage1, x, y, 100,
100, null);
break;
case 2:
graphics.drawImage(greenBrickImage2, x, y, 100,
100, null);
break;
case 3:
graphics.drawImage(greenBrickImage3, x, y, 100,
100, null);
break;
case 4:
graphics.drawImage(greenBrickImage4, x, y, 100,
100, null);
break;
}
break;
44
case BLUE:
switch (turns) {
case 1:
graphics.drawImage(blueBrickImage1, x, y, 100, 100,
null);
break;
case 2:
graphics.drawImage(blueBrickImage2, x, y, 100, 100,
null);
break;
case 3:
graphics.drawImage(blueBrickImage3, x, y, 100, 100,
null);
break;
case 4:
graphics.drawImage(blueBrickImage4, x, y, 100, 100,
null);
break;
}
break;

case YELLOW:
switch (turns) {
case 1:
graphics.drawImage(yellowBrickImage1, x, y, 100,
100, null);
break;
case 2:
graphics.drawImage(yellowBrickImage2, x, y, 100,
100, null);
45
break;
case 3:
graphics.drawImage(yellowBrickImage3, x, y, 100,
100, null);
break;
case 4:
graphics.drawImage(yellowBrickImage4, x, y, 100,
100, null);
break;
}
break;
}
}

public void play() throws InterruptedException {


while (!killed) {
while (turns > 0) {
if (killed)
return;
if (currentColor == YELLOW) {
if (!isDone(YELLOW)) {
yellowPlayer.play();
turnsCounter[YELLOW]++;
if (isDone(YELLOW)) {
points[YELLOW] = point;
point--;
}
} else {
turns = 0;
}
46
} else if (currentColor == RED) {
if (!isDone(RED)) {
redPlayer.play();
turnsCounter[RED]++;
if (isDone(RED)) {
points[RED] = point;
point--;
}
} else {
turns = 0;
}
} else if (currentColor == BLUE) {
if (!isDone(BLUE)) {
bluePlayer.play();
turnsCounter[BLUE]++;
if (isDone(BLUE)) {
points[BLUE] = point;
point--;
}
} else {
turns = 0;
}
} else if (currentColor == GREEN) {
if (!isDone(GREEN)) {
greenPlayer.play();
turnsCounter[GREEN]++;
if (isDone(GREEN)) {
points[GREEN] = point;
point--;
}
47
} else {
turns = 0;
}
}
}
nextPlayer();
print("Rool the dice");
if (isDone(YELLOW) && isDone(RED) &&
isDone(BLUE) && isDone(GREEN)) {
// System.out.print("{"+turnsCounter[YELLOW]+",
"+turnsCounter[RED]+", "+turnsCounter[BLUE]+", "+turnsCounter[GREEN]+"},");
// System.out.print("{"+points[YELLOW]+",
"+points[RED]+", "+points[BLUE]+", "+points[GREEN]+"},");
for (int i = 0; i < gameEndedListeners.size(); i++) {
gameEndedListeners.get(i).gameEnded(points);
}
return;
}
}
}

public void print(String str) {


debugString = currentColor + ": " + str;
repaint();
}

public void reset() {


if (rand == null)
rand = new Random();
currentColor = startColor;
48
turns = 3;

int[][] temp = { { 100, 101, 102, 103 }, { 200, 201, 202, 203 },
{ 300, 301, 302, 303 }, { 400, 401, 402, 403 } };
bricks = temp;
int[] temp2 = { 0, 0, 0, 0 };
turnsCounter = temp2;
killed = false;
point = 3;
dice = 0;
repaint();
}

public int rollDice() {


if (brickMoved || nothingToDo()) {
dice = Math.abs(rand.nextInt()) % 6 + 1;
brickMoved = false;
turns--;
if (!nothingToDo()) {
print("Now move a brick...");
} else {
if (turns > 0)
print("No brick can be moved, roll the dice
again..");
else
turns = 0;
}
repaint();
} else {
print("You must move a brick before you rool the dice");
49
}
return dice;
}

public void setPlayer(LUDOPlayer player, int color) {


switch (color) {
case YELLOW:
yellowPlayer = player;
break;
case RED:
redPlayer = player;
break;
case BLUE:
bluePlayer = player;
break;
case GREEN:
greenPlayer = player;
break;
}
}
}package com.ludo.LUDOSimulator;
/**
* Interface which any automatic ludo player must implement.
*
* @author David Johan Christensen
*
* @version 0.9
*
*/
public interface LUDOPlayer{
50
/**
* The play() method is called each time it is the players
* turn to roll the dice and play.
*
* See example players for inspiration.
*
*/
void play();
}package com.ludo.LUDOSimulator;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
* Example of automatic LUDO player
* @author David Johan Christensen
*
* @version 0.9
*
*/
public class ManualLUDOPlayer implements LUDOPlayer, MouseListener{

LUDOBoard board;

public ManualLUDOPlayer(LUDOBoard board) {


this.board = board;
}
boolean playing = false;
public void play() {
//do nothing wait for clicks
board.addMouseListener(this);
playing = true;
51
while(playing&&!board.killed)
try{Thread.currentThread().sleep(10);}catch(Exception e){}
board.removeMouseListener(this);
}
public void mouseClicked(MouseEvent mEvent) {
if(!playing) return;

if(mEvent.getX()>760&&mEvent.getX()<(760+100)&&mEvent.getY()>330&&mEv
ent.getY()<(330+100)) {
board.rollDice();
if(board.nothingToDo()) playing = false;
}
else {
int[] myBricks = board.getMyBricks();
double min = 10000;
int nr = -1;
for(int i=0;i<4;i++) {
int[] xy =
board.index2Pixel(myBricks[i],board.getMyColor());
double temp = (xy[0]-mEvent.getX())*(xy[0]-
mEvent.getX())+(xy[1]-mEvent.getY())*(xy[1]-mEvent.getY());
if(temp<min) {
min= temp;
nr = i;
}
}
if(nr!=-1&&min<250) {
if(board.moveBrick(nr)) playing = false;
else board.print("Unable to move selected brick...");
52
}
else {
board.print("You must click one of your bricks...");
}
}
}
public void mousePressed(MouseEvent arg0) {}
public void mouseReleased(MouseEvent arg0) {}
public void mouseEntered(MouseEvent arg0) {}
public void mouseExited(MouseEvent arg0) {}
}package com.ludo.LUDOSimulator;
import java.util.Random;
/**
* Example of automatic LUDO player
* @author David Johan Christensen
*
* @version 0.9
*
*/
public class PacifisticLUDOPlayer implements LUDOPlayer {

LUDOBoard board;
Random rand;
public PacifisticLUDOPlayer(LUDOBoard board)
{
this.board = board;
rand = new Random();
}

public void play() {


53
board.print("Pacifistic player playing");

int[] myBricksValue = new int[4];


board.rollDice();
float max =-1;
int bestIndex = -1;
for(int i=0;i<4;i++)
{
float value = analyzeBrickSituation(i);
if(value>max&&value>0) {
bestIndex = i;
max = value;
}
}
if(bestIndex!=-1) board.moveBrick(bestIndex);
}
public float analyzeBrickSituation(int i) {
if(board.moveable(i)) {
int[][] current_board = board.getBoardState();
int[][] new_board = board.getNewBoardState(i,
board.getMyColor(), board.getDice());

if(!hitOpponentHome(current_board,new_board)) {
return 2+rand.nextFloat();
}
else {
return 1+rand.nextFloat();
}
}
else {
54
return 0;
}
}
private boolean hitOpponentHome(int[][] current_board, int[][]
new_board) {
int opponentsOnField = 0;
for(int i=0;i<4;i++) {
for(int j=0;j<4;j++) {
if(board.getMyColor()!=i) {
if(board.atField(current_board[i][j])&&!
board.atField(new_board[i][j])) {
return true;
}
}
}
}
return false;
}

}
package com.ludo.LUDOSimulator;
import java.util.Random;
/**
* Example of automatic LUDO player
* @author David Johan Christensen
*
* @version 0.9
*
*/
public class RandomLUDOPlayer implements LUDOPlayer{
55
LUDOBoard board;
Random rand;
public RandomLUDOPlayer(LUDOBoard board)
{
this.board = board;
rand = new Random();
}
public void play() {
board.print("Random player playing");
board.rollDice();
int nr=-1;
double best = 0;
for(int i=0;i<4;i++) // find a random moveable brick
{
if(board.moveable(i)) {
double temp = rand.nextDouble();
if(temp>best) {
best = temp;
nr = i;
}
}
}
if(nr!=-1) board.moveBrick(nr);
//else nothing to do - no moveable bricks
}
public synchronized void delay() {
try {
wait(5000);
} catch (InterruptedException e) {
e.printStackTrace();
56
}
}
}package com.ludo.LUDOSimulator;
import java.util.Random;
/**
* Example of automatic LUDO player
* @author David Johan Christensen
*
* @version 0.9
*
*/
public class SemiSmartLUDOPlayer implements LUDOPlayer {

LUDOBoard board;
Random rand;
public SemiSmartLUDOPlayer(LUDOBoard board)
{
this.board = board;
rand = new Random();
}

public void play() {


board.print("Semi Smart player playing");

int[] myBricksValue = new int[4];


board.rollDice();
float max =-1;
int bestIndex = -1;
for(int i=0;i<4;i++)
{
57
float value = analyzeBrickSituation(i);
if(value>max&&value>0) {
bestIndex = i;
max = value;
}
}
if(bestIndex!=-1) board.moveBrick(bestIndex);
}
public float analyzeBrickSituation(int i) {
if(board.moveable(i)) {
int[][] current_board = board.getBoardState();
int[][] new_board = board.getNewBoardState(i,
board.getMyColor(), board.getDice());

if(hitOpponentHome(current_board,new_board)) {
return 5+rand.nextFloat();
}
else if(hitMySelfHome(current_board,new_board)) {
return (float)0.1;
}
else if(board.isStar(new_board[board.getMyColor()][i])) {
return 4+rand.nextFloat();
}
else if(moveOut(current_board,new_board)) {
return 3+rand.nextFloat();
}
else if(board.atHome(new_board[board.getMyColor()]
[i],board.getMyColor())) {
return 2+rand.nextFloat();
}
58
else {
return 1+rand.nextFloat();
}
}
else {
return 0;
}
}

private boolean moveOut(int[][] current_board, int[][] new_board) {


for(int i=0;i<4;i++) {
if(board.inStartArea(current_board[board.getMyColor()]
[i],board.getMyColor())&&!board.inStartArea(new_board[board.getMyColor()]
[i],board.getMyColor())) {
return true;
}
}
return false;
}

private boolean hitOpponentHome(int[][] current_board, int[][]


new_board) {
for(int i=0;i<4;i++) {
for(int j=0;j<4;j++) {
if(board.getMyColor()!=i) {
if(board.atField(current_board[i][j])&&!
board.atField(new_board[i][j])) {
return true;
}
59
}
}
}
return false; package com.minmax;

import java.util.Random;

public class Helpers implements Comparable {

public static class RandomGenerator {

public static Random generator = new Random((int) System


.currentTimeMillis());
};

private int fitness = 0;


protected double[] mData;
// protected int mLifespan;
protected int mSize, nCount;

public float MutateProbability = 0.5f;

private int[] networkConfig;

public float UniformSeperationProbability = 0.75f;

public Helpers(int[] config) {


networkConfig = config;

mSize = 0;
60
nCount = 0;

for (int i = 1; i < config.length; i++) {


mSize += (config[i - 1] + 1) * (config[i]);
nCount += config[i];
}
mData = new double[mSize];
/*
* mLifespan = 0; while (this.getFitness() == 1) Randomize();
*/
// System.out.println("Chromosome being initialized: mSize= " +
mSize +
// "; nCount = "+ nCount);
Randomize();
}

public int compareTo(Object o) {


Helpers g = (Helpers) o;

int fitnessDifference = g.getFitness() - this.getFitness();

return fitnessDifference;
}

public String getChromosome() {


String chromo = "";
for (double d : mData) {
chromo += Double.toString(d) + "|";
}
return chromo.substring(0, chromo.length() - 1);
61
}

public double getChromosomeElement(int index) {


return mData[index];
}

public int getFitness() {


return fitness;
}

public int[] getNetworkConfig() {


int[] config = new int[networkConfig.length - 1];
for (int i = 0; i < config.length; i++) {
config[i] = networkConfig[i + 1];
}
return config;
}

public int getNetworkInputCount() {


return networkConfig[0];
}

public double[] getNeuronWeight(int index) {


double[] weights;
int layer = -1;
for (int i = 1; i < networkConfig.length; i++) {
if (index < networkConfig[i]) {
layer = i;
break;
} else
62
index -= networkConfig[i];
}

// System.out.println("Found in layer # " + layer);


if (layer == -1)
return null;

int startPos = 0, length = 0;


for (int i = 1; i < layer; i++) {
startPos += (networkConfig[i - 1] + 1) * (networkConfig[i]);
}

startPos += (networkConfig[layer - 1] + 1) * index;


length = (networkConfig[layer - 1] + 1);

weights = new double[length];


// System.arraycopy(array,3,subArray,0,4);
System.arraycopy(mData, startPos, weights, 0, length);
return weights;
}

public void Mutate() {


for (int i = 0; i < nCount; i++) {
if (RandomGenerator.generator.nextFloat() <=
MutateProbability) {
MutateNeuron(i);
}
}
/*
* for (int i = 0; i < mData.length; i++) { if
63
* (RandomGenerator.generator.nextFloat() <= MutateProbability)
{
* mData[i] = 1 - mData[i]; } }
*/
}

private void MutateNeuron(int index) {

int layer = -1;


for (int i = 1; i < networkConfig.length; i++) {
if (index < networkConfig[i]) {
layer = i;
break;
} else
index -= networkConfig[i];
}

if (layer == -1)
return;

int startPos = 0, length = 0;


for (int i = 1; i < layer; i++) {
startPos += (networkConfig[i - 1] + 1) * (networkConfig[i]);
}

startPos += (networkConfig[layer - 1] + 1) * index;


length = (networkConfig[layer - 1] + 1);

for (int i = startPos; i < (startPos + length); i++) {

64
if (RandomGenerator.generator.nextFloat() <=
MutateProbability) {
mData[i] =
RandomGenerator.generator.nextGaussian();
}
}
}

private void Randomize() {


for (int i = 0; i < this.mData.length; i++) {
// this.mData[i] =
(RandomGenerator.generator.nextBoolean()) ? 1 :
// 0;
this.mData[i] = RandomGenerator.generator.nextDouble();
}
}

public Helpers[] Reproduce(Helpers gene)


throws CloneNotSupportedException {
return UniformCrossover(gene);
}

public void setChromosomeElement(int index, double value) {


mData[index] = value;
}

public void setFitness(int value) {


fitness = value;
}

65
public void setNeuronWeight(int index, double[] weights) {
// double[] weights;
int layer = -1;
for (int i = 1; i < networkConfig.length; i++) {
if (index < networkConfig[i]) {
layer = i;
break;
} else
index -= networkConfig[i];
}

if (layer == -1)
return;

int startPos = 0, length = 0;


for (int i = 1; i < layer; i++) {
startPos += (networkConfig[i - 1] + 1) * (networkConfig[i]);
}

startPos += (networkConfig[layer - 1] + 1) * index;


length = (networkConfig[layer - 1] + 1);

for (int i = startPos; i < (startPos + length); i++) {


mData[i] = weights[i - startPos];
}
}

private Helpers[] UniformCrossover(Helpers parent2)


throws CloneNotSupportedException {
Helpers[] c = new Helpers[2];
66
c[0] = new Helpers(this.networkConfig);
c[1] = new Helpers(parent2.networkConfig);

for (int i = 0; i < this.nCount; i++) {


if (RandomGenerator.generator.nextFloat() <=
UniformSeperationProbability) {
c[0].setNeuronWeight(i, this.getNeuronWeight(i));
c[1].setNeuronWeight(i,
parent2.getNeuronWeight(i));
// c[0].mData[i] = this.mData[i];
// c[1].mData[i] = parent2.mData[i];
} else {
c[0].setNeuronWeight(i,
parent2.getNeuronWeight(i));
c[1].setNeuronWeight(i, this.getNeuronWeight(i));
// c[0].mData[i] = parent2.mData[i];
// c[1].mData[i] = this.mData[i];
}
}

return c;
}
}package com.minmax;

public class Move {

public static void main(String[] args) {

System.out.println("Welcome to LUDO by YanIT-04");


int[] config = { 7, 7, 1 };
67
Population p = new Population(100, config);

int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;


int minturn = -1, maxturn = -1;
for (int i = 0; i < 500; i++) {
try {
p.RunEpoch();
System.out.println("Epoch # " + i + ": Score = "
+ p.getBestFitness());
if (p.getBestFitness() < min) {
min = p.getBestFitness();
minturn = i;
}
if (p.getBestFitness() > max) {
max = p.getBestFitness();
maxturn = i;
}
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
System.out.println("Max value attained = " + max + " @ epoch # "
+ maxturn);
System.out.println("Min value attained = " + min + " @ epoch # "
+ minturn);
}

}package com.minmax;

68
import com.ludo.LUDOSimulator.LUDO;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Population {


List<Helpers> mGenes = new ArrayList<Helpers>();
int mSize = 250;
float mutateRatio = 0.25f;
// int mChromeSize = 10;
int[] networkChromeConfig;

public Population(int size, int[] chromosomeSize) {


mSize = size;
networkChromeConfig = chromosomeSize;
ResetPopulation();
}

public Helpers getGene(int index) {


return mGenes.get(index);
}

public void Mutate(int g) {


mGenes.get(g).Mutate();
}

public void Reproduce(int gp1, int gp2) throws


CloneNotSupportedException {
Helpers[] children = null;
69
children = mGenes.get(gp1).Reproduce(mGenes.get(gp2));

mGenes.add(children[0]);
mGenes.add(children[1]);
}

public void ResetPopulation() {


// System.out.println("Creating Population");
mGenes.clear();
for (int i = 0; i < mSize; i++) {
mGenes.add(new Helpers(networkChromeConfig));
}
SortPopulation();
}

public float RunEpoch() throws CloneNotSupportedException {

// Mutate lower % of population


for (int i = (mSize - (int) (mSize * mutateRatio)); i < mSize; i++) {
Mutate(i);
}

// Select Parents from top


int parent1 = -1, parent2 = -1;
if (mGenes.size() >= 2) {
parent1 = 0;
parent2 = 1;
}

70
// Reproduce
if (parent1 != -1 && parent2 != -1) {
Reproduce(parent1, parent2);
}

// Evaluate population
SortPopulation();

// Discard extra and lowest populace


while (mGenes.size() > mSize) {
mGenes.remove(mGenes.size() - 1);
}

float populationFitness = 0;
for (int i = 0; i < mGenes.size(); i++) {
populationFitness += mGenes.get(i).getFitness();
}

/*
* System.out.println("Average Population Fitness = " +
* Float.toString(populationFitness / mGenes.size()));
this.Debug();
*/
return populationFitness / mGenes.size();
}

public void Save(String filename) {


// Write code here to save the chromosome with best fitness as a
neural
// network xml file that can be loaded
71
}

private void SortPopulation() {


// Play and set fitness value before sorting, otherwise it will go
// nowhere
// System.out.println("Finding Population Fitness");
for (int i = 0; i < mGenes.size(); i++) {
LUDO l = new LUDO();
mGenes.get(i).setFitness(l.playMinMax(mGenes.get(i),
100));
// System.out.print(".");
}
// System.out.println("Sorting Population");
Collections.sort(mGenes);

/*for (int i = 0; i < mGenes.size(); i++)


System.out.print(mGenes.get(i).getFitness() + ",");
System.out.println();*/
}

public int getBestFitness() {


return mGenes.get(0).getFitness();
}
}
}
private boolean hitMySelfHome(int[][] current_board, int[][]
new_board) {
for(int i=0;i<4;i++) {

72
if(!board.inStartArea(current_board[board.getMyColor()]
[i],board.getMyColor())&&board.inStartArea(new_board[board.getMyColor()]
[i],board.getMyColor())) {
return true;
}
}
return false;
}
}

3.1.2 Приклади роботи

На рисунках 3.1 і 3.2 показані приклади роботи програми.

73
Рисунок 3.1 –

Рисунок 3.2 –

3.2

74
ВИСНОВОК

В рамках даної лабораторної роботи ми вивчили алгоритм Min-max для


розробки віртуального інтелекту для відеоігор. Реалізували застосунок для гри
в Ludo та візуальну репрезентацію гри

Посилання на github: https://github.com/yan14171/APLAB6

75
КРИТЕРІЇ ОЦІНЮВАННЯ

При здачі лабораторної роботи до 24.12.2020 включно максимальний бал


дорівнює – 5. Після 24.12.2020 максимальний бал дорівнює – 1.
Критерії оцінювання у відсотках від максимального балу:
 програмна реалізація алгоритму – 75%;
 призначений для користувача (десктопний) інтерфейс - 20%;
 висновок – 5%.
+1 додатковий бал можна отримати за реалізацію анімації процесу
жеребкування або роздачі карт.

76

You might also like