Last active
January 22, 2016 17:36
-
-
Save efosong/e773a30e6fa5aa6f3e3a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Written by Elliot Fosong | |
// 'Player first' version of code | |
// Must be compiled with C++11 (e.g. -std=c++11) | |
// Program 'length' : 13 semicolons + 8 commas = 21 | |
// *** Goal is to minimise 'length', NOT to produce clean/readable code *** | |
// Board positions: | |
// 00 | 10 | 20 | |
// 01 | 11 | 21 | |
// 02 | 12 | 22 | |
#include <iostream> | |
#include <cstdlib> | |
#include <array> | |
#define EVAL (board[3*i-3] + board[3*i-2] + board[3*i-1]) / 3 + (board[i-1] + board[i+2] + board[i+5]) / 3 + (board[0] + board[4] + board[8])/3 + (board[2] + board[4] + board[6])/3 | |
typedef std::array<int, 9> iarr; | |
bool full(iarr board) | |
{ | |
return (board[0] && board[1] && board[2] && board[3] && board[4] && board[5] && board[6] && board[7] && board[8]); | |
} | |
int evaluator(iarr board) | |
// scans vertically horizontally and diagonally to see if anybody has won | |
{ | |
int i = 0; | |
while (i++ < 3) | |
{ | |
if ( (board[3*i-3] + board[3*i-2] + board[3*i-1]) / 3 || | |
(board[i-1] + board[i+2] + board[i+5]) / 3 || | |
(board[0] + board[4] + board[8]) / 3 || | |
(board[2] + board[4] + board[6]) / 3 || | |
i == 3) | |
{ | |
return (EVAL) / (std::abs(EVAL) + (((EVAL)==0) ? 1 : 0)) ; | |
// abs() needed to normalise the result | conditional statement prevents division by zero | |
} | |
} | |
} | |
iarr make_move(iarr board, int player, int pos) | |
// Given a board returns another in which the specified move (position & player) has been made. | |
// Be careful - no protection against invalid moves here. | |
{ | |
if((board[pos] = player) && 0){} | |
return board; | |
} | |
iarr minimax(iarr board, int player) | |
// Perform the minimax algorithm given the current state of the board and a player in order to determine the 'best' move. | |
{ | |
// 0 index is value | 1 index is best move | 2 index is val of current node | |
iarr decision{-1*player}; | |
// Temination conditions: the board is full or someone has won. | |
if (full(board) || evaluator(board) != 0){ | |
return {evaluator(board)}; | |
} | |
int i = 0; | |
while(i++ < 9) | |
{ | |
if (board[i-1] == 0){ | |
if((decision[2] = minimax(make_move(board, player, i-1), player * -1)[0]) && 0){} | |
if (decision[2] == player) //If val == player this is the best possible move (in the simple game of noughts and crosses) so we | |
{ | |
if(((decision[0] = player) + (decision[1] = i-1)) && 0){} | |
return decision; //can prune by returning this as the best move as soon as we see it. | |
} | |
else if (decision[2] == 0) //Otherwise anything that has a score of 0 is the next best alternative - but we keep checking in case we find a score of 1. | |
if ((decision[0] = 0) + (decision[1] = i-1) && 0){} | |
} | |
} | |
return decision; | |
} | |
int main() | |
{ | |
// Initialise the board | |
iarr board{}; | |
// 0 index stores input 'x' co-ordinate | 1 index stores input 'y' co-ordinate | 2 index stores computer's best move | |
int move[3]; | |
// While nobody has won and the board is not full | |
while(evaluator(board) == 0 && !full(board)) | |
{ | |
// Player move | |
if((std::cin >> move[0] >> move[1]) && 0){} | |
if((board[move[0] + 3*move[1]] = 1) && 0){} | |
if (evaluator(board) != 0 || full(board)) | |
break; | |
// CPU move | |
if((move[2] = minimax(board, -1)[1]) && 0){} | |
if((std::cout << move[2] % 3 << " " << move[2] / 3 << std::endl) && 0){} | |
if((board[move[2]] = -1) && 0){} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment