2d1350 programmeringsparadigm

35
2D1350 Programmeringsparadigm Pointers Arrays Structures Artificial intelligence and game playing Lab assignment

Upload: mac

Post on 09-Feb-2016

31 views

Category:

Documents


0 download

DESCRIPTION

2D1350 Programmeringsparadigm. Pointers Arrays Structures Artificial intelligence and game playing Lab assignment. Games as Search Problems. The behavior / actions of the opponent are unpredictable, therefore search for a “worst-case”-plan. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 2D1350 Programmeringsparadigm

2D1350 Programmeringsparadigm Pointers Arrays Structures Artificial intelligence and game playing Lab assignment

Page 2: 2D1350 Programmeringsparadigm

Games as Search Problems The behavior / actions of the opponent are

unpredictable, therefore search for a “worst-case”-plan.

Time limit, therefore complete search is not feasible and an approximation is needed

Algorithm for perfect play (van Neumann 1944)

Finite horizon, approximate evaluation (Zuse 1945, Shannon 1950, Samuel 1952)

Pruning search tree (McCarthy 1956)

Page 3: 2D1350 Programmeringsparadigm

Types of Game

deterministic Stochastic

Perfect information Chess, checkers, connect-4, go, othello

Backgammon, monopoly

Imperfect information

Bridge, poker, scrabble

Page 4: 2D1350 Programmeringsparadigm

Min-Max-Search Optimal strategy for deterministic, perfect-

information game Idea: Choose move that results in position with

highest min-max-value = best achievable payoff against best opponents play

5

3 2

3 12 8

5

5 7 9 4 2 7

Max:

Min:

A11

A2

A3

A13A12

A21 A23A22

A31 A33A32

A1

Page 5: 2D1350 Programmeringsparadigm

Min-Max-SearchFunction MINMAX-DECISION(game state) returns a move

for each move in PossibleMoves(game state) do

value[move] <- MINIMAX-VALUE(apply(move, game state))

end

return the move with the highest value[move]

Function MINMAX-VALUE(game state) returns a utility value

if TERMINAL-TEST(game state) then

return UTILITY(game state)

else if MAX is to move in game state

return the highest MINMAX-VALUE of SUCCESSORS(game state)

else

return the lowest MINMAX-VALUE of SUCCESSORS(game state)

Page 6: 2D1350 Programmeringsparadigm

Min-Max Properties Complete: yes, if search tree is finite Optimal : yes, if opponent plays optimal Time complexity : O(bm) Space complexity : O(bm) depth first search Chess b~35 possible moves in each state,

m~100 moves per game -> exact solution infeasible

Standard solution cutoff test for search (e.g. depth limit) evaluation function : approximates utility of

board position

Page 7: 2D1350 Programmeringsparadigm

Evaluation Scheme For chess for example typically linear weighted

sum of features Utility(s) = w1 f1(s) + w2 f2(s) + …wn fn(s)

w1=9

f1(s)= #white queens - #black queens

w2=5

f2(s) = #white rooks - #black rooks

etc.

Page 8: 2D1350 Programmeringsparadigm

Cutting of Search Min-Max-Search with Cut-Off requires

1. CUTOFF criterion, usually based on search depth

2. UTILITY function needs an evaluation scheme for non-terminal game states

Ply = one half-move (move by one player) Chess:

4-ply = novice 8-ply = PC, human master 12-ply = Deep Blue, Kasparov

Page 9: 2D1350 Programmeringsparadigm

Min-Max-Search with Cut-Off

Function MINMAX-DECISION(game) returns a move

for each move in PossibleMoves(game state) do

value[move] <- MINIMAX-VALUE(apply(move, game state))

end

return the move with the highest value[move]

Function MINMAX-VALUE(game state, depth) returns a utility value

if CUTOFF-TEST(depth) or TERMINAL-TEST(game state)

return UTILITY(game state)

else if MAX is to move in game state

return the highest MINMAX-VALUE(SUCCESSOR(game state),depth+1)

else

return the lowest MINMAX-VALUE(SUCCESSOR(game state), depth+1)

Page 10: 2D1350 Programmeringsparadigm

Connect-4

two player game 7x6 rectangular board placed vertically 21 red, 21 yellow tokens players alternate by dropping a token into one of the

seven columns, the token falls down to the lowest unoccupied square

a player wins if she connects four token vertically, horizontally or diagonally

if the board is filled (42 tokens played) and no player has aligned four tokens the game ends in a draw

Page 11: 2D1350 Programmeringsparadigm

Connect-4

win for yellow win for red

draw

Page 12: 2D1350 Programmeringsparadigm

Connect-4 Utility Function Odd square: is a square belonging to an odd row (1,3,5) Even square: is a square belonging to an even row (2,4,6) Threats: A threat is a group of three tokens of the same

color which has the fourth square empty and also the square below the empty square is empty

Odd threat: is a threat in which the empty square is odd Even threat: is a threat in which the empty square is even If red (moves first) has an odd threat and black cannot

connect four tokens anywhere else red will win. If black (moves second) has an even threat and black

cannot connect four tokens anywhere else black will win. At the beginning of the game it is advantageous to place

tokens in the central columns.

Page 13: 2D1350 Programmeringsparadigm

Lab Assignment Code for connect-4 available in game.h and

game.c Copy files game.h, game.c, Makefile into your

local directory To add gcc to your list of modules type

module add gcc/3.1or add this line to .modules

To compile game.c into executable type make

Page 14: 2D1350 Programmeringsparadigm

Lab Assignment Design and implement a game playing program for the

deterministic two player game Connect-4 Features

The program should be able to play against itself or a human opponent.

The program should visualize the evolution of the game and print out its own estimate of the utility of the current game state.

The program should determine who won or if the game ended in a draw

Implement the min-max-search algorithm Implement a proper utility function for Connect-4 Test the program by letting it play against itself and against a

human opponent

Page 15: 2D1350 Programmeringsparadigm

Connect-4 Game State#define ROWS 6 /* number of rows in connect-4 */

#define COLS 7 /* number of columns in connect-4 */

#define RED -1 /* value for red tokens and red player */

#define BLACK 1 /* value for black tokens and black player */

struct Game

{

int board[ROWS][COLS]; /* -1 token red player, 1 token black player,

0 empty square */

int currentplayer; /* -1 red player, 1 black player */

int tokensonboard; /* counts the number of tokens on the board */

};

Page 16: 2D1350 Programmeringsparadigm

Connect-4 Move

struct Move

{

int row; /* row coordinate of square */

int col; /* column coordinate of square */

int token; /* -1 red token, 1 black token */

};

Page 17: 2D1350 Programmeringsparadigm

void InitGame()void InitGame(struct Game *game) /* pointer reference to game state */

{

int i;

int j;

for (i=0; i < ROWS; i++)

for (j=0; j < COLS; j++)

(*game).board[i][j]=0; /* empty board */

(*game).currentplayer=RED; /* red player to start game */

(*game).tokensonboard=0;

};

Page 18: 2D1350 Programmeringsparadigm

void MakeMove()void MakeMove(struct Game *game, struct Move move)

{

#if DEBUG

assert((*game).board[move.row][move.col]==0); /* assert square is empty */

if (move.row>0)

assert((*game).board[move.row-1][move.col]!=0); /* assert square below is occupied */

assert((*game).currentplayer==move.token); /* assert correct player moves */

#endif

(*game).board[move.row][move.col]=move.token; /* place token at square */

(*game).currentplayer*=-1; /* switch player */

(*game).tokensonboard++; /* increment number of tokens on board */

}

Page 19: 2D1350 Programmeringsparadigm

void UndoMove()void UndoMove(struct Game *game, struct Move move){#if DEBUG assert((*game).board[move.row][move.col]!=0); /* assert square is occupied */ if (move.row<ROWS-1) assert((*game).board[move.row+1][move.col]!=0); /* assert square above is

empty */ assert((*game).currentplayer!=move.token); /* assert correct player moves */#endif (*game).board[move.row][move.col]=0; /* remove token from square */ (*game).currentplayer*=-1; /* switch player */ (*game).tokensonboard--; /* decrement number of tokens on board */}

Page 20: 2D1350 Programmeringsparadigm

int Win()int Win(struct Game *game, int player){ int i; int j; for (j=0;j<COLS;j++) for(i=0;i<ROWS-3;i++) /* check for group of four vertical tokens */ { int count=0; /* counts number of consecutive tokens */

while((count < 4) && ((*game).board[i+count][j]==player)) /* check if token is owned by player and not 4 tokens yet */

count++; if (count==4) /* four tokens in column */

return 1; /* win for player*/ } … /* check for horizontal and diagonal groups of four */

Page 21: 2D1350 Programmeringsparadigm

int Win() for (j=0;j<COLS-3;j++) for(i=0;i<ROWS;i++) /* check for group of four horizontal four tokens */ { int count=0; /* counts number of consecutive tokens */

while((count < 4) && ((*game).board[i][j+count]==player)) /* check if token is owned by player and not 4 tokens yet */

count++; if (count==4) /* four tokens in a row */

return 1; /* win for player */ }

Page 22: 2D1350 Programmeringsparadigm

int Win()

for (j=0;j<COLS-3;j++) for(i=0;i<ROWS-3;i++) /* check for four tokens in an upward diagonal */ { int count=0; /* counts number of consecutive tokens */

while((count < 4) && ((*game).board[i+count][j+count]==player)) /* check if token is owned by player and not 4 tokens yet */

count++; if (count==4) /* four tokens in a diagonal */

return 1; /* win for player */ }

Page 23: 2D1350 Programmeringsparadigm

int Win()

for (j=0;j<COLS-3;j++)

for(i=3;i<ROWS;i++) /* check for four tokens in a downward diagonal */

{

int count=0; /* counts number of consecutive tokens */

while((count < 4) && ((*game).board[i-count][j+count]==player))

/* check if token is owned by player and not 4 tokens yet */

count++;

if (count==4) /* four tokens in a diagonal */

return 1; /* win for player */

}

return 0; /* no win for player */

}

Page 24: 2D1350 Programmeringsparadigm

int Draw()int Draw(struct Game *game)

{

if ((*game).tokensonboard<42)

return 0;

else return (!Win(game,RED) && !Win(game,BLACK));

}

Page 25: 2D1350 Programmeringsparadigm

int Row()

int Row(struct Game *game, int col)

/* computes the row on which token ends when dropped in column col */

{

int row=0;

while((row<ROWS) && (*game).board[row][col]!=0)

row++;

return row;

}

Page 26: 2D1350 Programmeringsparadigm

void PossibleMoves()void PossibleMoves(struct Game *game, int *number_of_moves, struct Move moves[]) /* computes the possible moves , number_of_moves returns the number of available moves, moves[]

contains array of moves */ { int i; *number_of_moves=0; for (i=0;i<COLS;i++) { int row=Row(game,i); /* computes first empty square in col i */ if (row<ROWS) /* column has an empty square */ { moves[*number_of_moves].row=row; moves[*number_of_moves].col=i; moves[*number_of_moves].token=(*game).currentplayer; (*number_of_moves)++; } }}

Page 27: 2D1350 Programmeringsparadigm

int Utility()int Utility(struct Game *game){ if (Draw(game)) return 0; if (Win(game,RED)) return 1000; /* maximum utility for winning */ if (Win(game,BLACK)) return -1000; /* minimum utility for loosing */ /* non-terminal game state */ /* HERE GOES YOUR CODE TO COMPUTE UTILITY OF NON-

TERMINAL BOARD STATES */

return 0;}

Page 28: 2D1350 Programmeringsparadigm

Input / Output Functionsvoid DisplayBoard(struct Game *game); /* print board state on screen */

void DisplayMove(struct Move move); /* print move on screen */

void EnterMove(struct Move *move, struct Game *game);

/* reads in a move from the keyboard */

Page 29: 2D1350 Programmeringsparadigm

int main()

int main(int argc, char *argv[])

{

int i;

struct Game game; /* variable to store the game state */

struct Move moves[COLS]; /* array to store possible moves */

int number_of_moves;

int playagainsthuman=0;

/* computer plays against itself (0) or against human (1) */

Page 30: 2D1350 Programmeringsparadigm

int main() for (i=1; i<argc; i++) /* iterate through all command line arguments */ { if(strcmp(argv[i],"-p")==0) /* if command line argument -p human opponent */ {

playagainsthuman=1; printf("Human player plays black\n");

} if(strcmp(argv[i],"-h")==0) /* if command line argument -h print help */ {

printf("game [-p] [-h]\n-p for play against human player\n-h for help\n"); return 0; /* quit program */ } }

Page 31: 2D1350 Programmeringsparadigm

int main()InitGame(&game); /* set up board */

while( !Draw(&game) && !Win(&game,RED) && !Win(&game,BLACK))

/* no draw or win */

{

int rand;

struct Move move;

DisplayBoard(&game); /* display board state */

PossibleMoves(&game,&number_of_moves,moves);

/* calculate available moves */

rand = (int) (drand48()*number_of_moves); /* pick a random move */

MakeMove(&game,moves[rand]); /* make move */

DisplayMove(moves[rand]); /* display move */

Page 32: 2D1350 Programmeringsparadigm

int main()if (playagainsthuman) /* play against human opponent */

{

DisplayBoard(&game); /* show board state after computer moved */

if (!Draw(&game) && !Win(&game,RED))

/* no draw and no computer win */

{

EnterMove(&move,&game); /* human player enters her move */

MakeMove(&game,move); /* make move */

}

} /* end of human player play */

} /* end of while not draw or win */

Page 33: 2D1350 Programmeringsparadigm

int main() DisplayBoard(&game); /* display board state */

if (Draw(&game))

printf("the game ended in a draw\n");

if (Win(&game, RED))

printf("player red won the game\n");

if (Win(&game, BLACK))

printf("player black won the game\n");

return 0;

} /* end of main */

Page 34: 2D1350 Programmeringsparadigm

MakefileOBJS = game.o

# for gcc compiler ....

CC = gcc

CFLAGS = -g -Wall

#naming executable

EXEC = game

all: $(EXEC)

%.o:%.c

$(CC) $(CFLAGS) -c $<

$(EXEC): $(OBJS)

$(CC) -o $@ $(OBJS)

Page 35: 2D1350 Programmeringsparadigm

Question of the Day

Draw a closed path of four straight lines that connects all nine dots.