Skip to content

Instantly share code, notes, and snippets.

@efosong
Last active January 22, 2016 17:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save efosong/e773a30e6fa5aa6f3e3a to your computer and use it in GitHub Desktop.
Save efosong/e773a30e6fa5aa6f3e3a to your computer and use it in GitHub Desktop.
// 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