theorethisch, aber npraktisch doch nicht funktionierender MiniMax
Algorithmus
This commit is contained in:
parent
903e559856
commit
4dd39b5e79
3 changed files with 125 additions and 44 deletions
|
@ -7,12 +7,13 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <mcp.h>
|
#include <mcp.h>
|
||||||
|
|
||||||
#include "playerlib.h"
|
#include "playerlib.h"
|
||||||
|
|
||||||
static int
|
static int
|
||||||
send_move(int row, int col)
|
send_move(int row, int col)
|
||||||
{
|
{
|
||||||
FILE *f = fdopen(dup(CHILD_OUT_FD), "w");
|
FILE *f = fdopen(dup(CHILD_OUT_FD), "w");
|
||||||
|
@ -21,44 +22,104 @@ send_move(int row, int col)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int*
|
int
|
||||||
numNextMoves(cell (*field)[fieldSize], movesList *moves) {
|
buildTree(gameTree *currentNode, cell (*field)[fieldSize], movesList *moves, int depth, char enemyc) {
|
||||||
|
if (depth == 0 || moves->movesNumber == 0)
|
||||||
|
return 0;
|
||||||
|
currentNode->numChildMoves = moves->movesNumber;
|
||||||
|
currentNode->childMove = new gameTree[maxMoves]();
|
||||||
//switch stone char
|
//switch stone char
|
||||||
char tmpown = ownc, tmpenemy = enemyc;
|
ownc = getEnemyChar(enemyc);
|
||||||
char enemyc = getEnemyChar(tmpenemy);
|
|
||||||
char ownc = getEnemyChar(tmpown);
|
//#ifdef debugprint
|
||||||
#ifdef debugprint
|
// printf("Depth %d: enemy: %c\n", depth, enemyc);
|
||||||
printf("Own: %c Enemy: %c\n", ownc, enemyc);
|
//#endif
|
||||||
#endif
|
for(size_t i=0; i<moves->movesNumber; ++i)
|
||||||
unsigned int *numberOfEnemyMoves= new unsigned int[maxMoves]();
|
|
||||||
for (size_t moveNum=0; moveNum < moves->movesNumber; ++moveNum)
|
|
||||||
{
|
{
|
||||||
|
currentNode->childMove[i].nodeMove = moves->list[i];
|
||||||
size_t fieldMemSize = fieldSize*fieldSize*sizeof(cell);
|
size_t fieldMemSize = fieldSize*fieldSize*sizeof(cell);
|
||||||
//cell (*futureField)[fieldSize] = (cell (*)[fieldSize]) malloc(fieldMemSize);
|
|
||||||
auto futureField = new cell[fieldSize][fieldSize]();
|
auto futureField = new cell[fieldSize][fieldSize]();
|
||||||
memcpy(futureField, field, fieldMemSize);
|
memcpy(futureField, field, fieldMemSize);
|
||||||
futureField[(moves->list[moveNum].turnRow-1)][(moves->list[moveNum].turnCol-1)].content=enemyc;
|
futureField[(moves->list[i].turnRow-1)][(moves->list[i].turnCol-1)].content=enemyc;
|
||||||
printf("--------------------\nfutureField\n");
|
|
||||||
#ifdef debugprint
|
|
||||||
for(size_t n=0;n<fieldSize;++n)
|
|
||||||
{
|
|
||||||
for(size_t m=0; m<fieldSize; ++m)
|
|
||||||
{
|
|
||||||
printf("%c ", futureField[n][m].content);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
movesList *futureMoves = new movesList();
|
movesList *futureMoves = new movesList();
|
||||||
findMoves(futureField, futureMoves);
|
findMoves(futureField, futureMoves);
|
||||||
numberOfEnemyMoves[moveNum] = futureMoves->movesNumber;
|
buildTree(&(currentNode->childMove[i]), futureField, futureMoves, depth-1, getEnemyChar(enemyc));
|
||||||
delete [] futureMoves;
|
delete [] futureMoves;
|
||||||
delete [] futureField;
|
delete [] futureField;
|
||||||
//free(futureField);
|
|
||||||
}
|
}
|
||||||
return numberOfEnemyMoves;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
move
|
||||||
|
maxEvalMove(std::vector<evalMove> *curMoves) {
|
||||||
|
evalMove maxM;
|
||||||
|
maxM.evaluation = -9;
|
||||||
|
#ifdef debugprint
|
||||||
|
printf("Foo\n");
|
||||||
|
#endif
|
||||||
|
for(size_t i = 0; i < curMoves->size(); ++i)
|
||||||
|
{
|
||||||
|
#ifdef debugprint
|
||||||
|
printf("bar %d %d\n", maxM.evaluation, curMoves->at(i).evaluation);
|
||||||
|
#endif
|
||||||
|
if(curMoves->at(i).evaluation > maxM.evaluation)
|
||||||
|
{
|
||||||
|
#ifdef debugprint
|
||||||
|
printf("baz\n");
|
||||||
|
#endif
|
||||||
|
maxM.evaluation = curMoves->at(i).evaluation;
|
||||||
|
maxM.m = curMoves->at(i).m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxM.m;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
maxInt(std::vector<int> *evaluations) {
|
||||||
|
int maxE = -10;
|
||||||
|
for(size_t i = 0; i<evaluations->size(); ++i)
|
||||||
|
{
|
||||||
|
if(evaluations->at(i) > maxE)
|
||||||
|
{
|
||||||
|
maxE = evaluations->at(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//MiniMax Algorithmus
|
||||||
|
int
|
||||||
|
eval(gameTree *currentNode, int depth) {
|
||||||
|
if (depth == 0 || !currentNode->numChildMoves)
|
||||||
|
{
|
||||||
|
//gut: hohe Mobilität, Eckzüge. Schlecht: Züge auf Felder direkt vor der Ecke
|
||||||
|
return ((-1)+currentNode->numChildMoves + 5*isCornerField(currentNode->nodeMove) - 2*isCOrXField(currentNode->nodeMove));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> curEvals;
|
||||||
|
for(size_t i = 0; i < currentNode->numChildMoves; ++i)
|
||||||
|
{
|
||||||
|
int curEval = -1 * eval(&(currentNode->childMove[i]), depth-1);
|
||||||
|
curEvals.push_back(curEval);
|
||||||
|
}
|
||||||
|
return maxInt(&curEvals);
|
||||||
|
}
|
||||||
|
|
||||||
|
move
|
||||||
|
findBestMove(gameTree *currentNode, int depth) {
|
||||||
|
std::vector<evalMove> curMoves;
|
||||||
|
for(size_t i = 0; i < currentNode->numChildMoves; ++i)
|
||||||
|
{
|
||||||
|
evalMove m;
|
||||||
|
m.evaluation = -1 * eval(&(currentNode->childMove[i]), depth-1);
|
||||||
|
m.m = currentNode->childMove[i].nodeMove;
|
||||||
|
#ifdef debugprint
|
||||||
|
printf("findBest %d: %d, %d\n", m.evaluation, m.m.turnRow, m.m.turnCol);
|
||||||
|
#endif
|
||||||
|
curMoves.push_back(m);
|
||||||
|
}
|
||||||
|
return maxEvalMove(&curMoves);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
|
@ -103,39 +164,44 @@ int main(void)
|
||||||
|
|
||||||
findMoves(field, moves);
|
findMoves(field, moves);
|
||||||
|
|
||||||
unsigned int *numOfEnemyMoves = numNextMoves(field, moves);
|
// unsigned int *numOfEnemyMoves = numNextMoves(field, moves);
|
||||||
|
|
||||||
for(size_t i=0; i<moves->movesNumber; ++i)
|
// for(size_t i=0; i<moves->movesNumber; ++i)
|
||||||
{
|
// {
|
||||||
printf("Moves %d %d -> %d enemy moves\n", moves->list[i].turnRow, moves->list[i].turnCol, numOfEnemyMoves[i]);
|
// printf("Moves %d %d -> %d enemy moves\n", moves->list[i].turnRow, moves->list[i].turnCol, numOfEnemyMoves[i]);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if(!(moves->movesNumber))
|
if(!(moves->movesNumber))
|
||||||
{
|
{
|
||||||
turn_row=0;
|
turn_row=0;
|
||||||
turn_col=0;
|
turn_col=0;
|
||||||
|
#ifdef debugprint
|
||||||
|
printf("Nope\n");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
int r = rand() % moves->movesNumber;
|
if((numX+numO)>5*fieldSize*fieldSize/6)
|
||||||
turn_row=moves->list[r].turnRow;
|
endgame = 1;
|
||||||
turn_col=moves->list[r].turnCol;
|
gameTree *treeRoot = new gameTree();
|
||||||
|
treeRoot->nodeMove.turnRow = 0;
|
||||||
|
treeRoot->nodeMove.turnCol = 0;
|
||||||
|
buildTree(treeRoot, field, moves, 3, getEnemyChar(enemyc));
|
||||||
|
move finalMove = findBestMove(treeRoot, 3);
|
||||||
|
|
||||||
|
turn_row=finalMove.turnRow;
|
||||||
|
turn_col=finalMove.turnCol;
|
||||||
|
#ifdef debugprint
|
||||||
|
printf("Getätigter Zug: %d,%d\n", turn_row, turn_col);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef debugprint
|
|
||||||
printf("numX: %d, numO: %d\n", numX, numO);
|
|
||||||
printf("%d %d\n", sizeof(field), sizeof(cell[fieldSize][fieldSize]));
|
|
||||||
move te;
|
|
||||||
te.turnRow=2;
|
|
||||||
te.turnCol=1;
|
|
||||||
printf("IsCorner? %d\n", isCOrXField(te));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 3. Return result
|
// 3. Return result
|
||||||
send_move(turn_row, turn_col);
|
send_move(turn_row, turn_col);
|
||||||
|
|
||||||
|
//free(numOfEnemyMoves);
|
||||||
delete [] field;
|
delete [] field;
|
||||||
delete [] moves;
|
delete [] moves;
|
||||||
/* END PLAYER-SPECIFIC CODE */
|
/* END PLAYER-SPECIFIC CODE */
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//#define debugprint
|
//#define debugprint
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "playerlib.h"
|
#include "playerlib.h"
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ int findDiagonalTopRightMoves(cell (*)[fieldSize], movesList *);
|
||||||
|
|
||||||
|
|
||||||
char enemyc = 0, ownc = 0;
|
char enemyc = 0, ownc = 0;
|
||||||
|
unsigned int endgame=0;
|
||||||
|
|
||||||
char
|
char
|
||||||
getEnemyChar(char c) {
|
getEnemyChar(char c) {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define PLAYERLIB_H
|
#define PLAYERLIB_H
|
||||||
|
|
||||||
const int fieldSize=8, maxMoves=100; // =fieldHeight=fieldWidth
|
const int fieldSize=8, maxMoves=100; // =fieldHeight=fieldWidth
|
||||||
|
extern unsigned int endgame;
|
||||||
|
|
||||||
extern char enemyc; //initially 0, contains char of enemy's stone
|
extern char enemyc; //initially 0, contains char of enemy's stone
|
||||||
extern char ownc;
|
extern char ownc;
|
||||||
|
@ -19,6 +20,18 @@ struct movesList {
|
||||||
move *list = new move[maxMoves](); //eigentlich maximal 8*8-4 Lösungen, aber manche doppelt? -> Reserve
|
move *list = new move[maxMoves](); //eigentlich maximal 8*8-4 Lösungen, aber manche doppelt? -> Reserve
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct gameTree{
|
||||||
|
int evaluation;
|
||||||
|
move nodeMove;
|
||||||
|
gameTree *childMove = NULL;
|
||||||
|
unsigned int numChildMoves=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct evalMove{
|
||||||
|
int evaluation;
|
||||||
|
move m;
|
||||||
|
};
|
||||||
|
|
||||||
//returns the character used for the enemy's stones
|
//returns the character used for the enemy's stones
|
||||||
extern char getEnemyChar(char);
|
extern char getEnemyChar(char);
|
||||||
//reads the stateBuffer string into a 2d matrix
|
//reads the stateBuffer string into a 2d matrix
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue