URL to challenge:
Quite an easy one, it must be said. Basically you just have to write an engine to intelligently play the game Reversi.Code:http://corp.gaiaonline.com/careers/puzzle
My solution:
Spoiler:I wrote mine a while ago in PHP. I decided to write a complete class and engine as I actually made a presentable game out of it, which is above the scope.
I used a minimax function (although technically I think I implemented a variation on a negamax function, since minimax seemed to be a bit redundant). Can be further optimised via using an a/b pruning technique, or a similar alternative. I think in the example they provide, there are 12 moves to the end, whereas I was only able to go 11 nodes deep. If you wanted to go 12 and beyond you'd have to improve on this function.
I also used a terribly greedy evaluation function :p It just uses the amount of pieces on the board - it doesn't consider the position of the game (i.e. it's more advantageous to have a piece on the edge/corner than middle of the board).
reversi.engine.class.php - the brains of the operation
reversi.class.php - the interface between the AI class and end userPHP Code:
<?php
/**
* Reversi Artificial Intelligence class
*
* @author Alex Roxon
* @file reversi.engine.class.php
*/
class ReversiAI extends Reversi {
/**
* Public data values - poor design, sure, but I know what I'm doing, so let's
* just grant permission to these values.
*/
public $gameBoard = array();
public $possibleMoves = array();
// Who the active player is
private $activePlayer = 'w';
// The path to the correct solution
private $treePath = array();
// How many nodes deep we should search
private $nodes = 5;
// Debug purposes
private $outString = '';
// Possible moves
private $moves = array();
/**
* Evaluate the score
*
* Fairly weak evaluation function. Proper AI engine should have a function
* significantly smarter. As we're approaching the endgame though, I think this
* should be fine.
*
* @param $gameBoard
* The gameboard to evaluate a position
* @param $player
* The player we're looking for
*
* @return
* The score of the game relative to the $player
*/
public function evaluateScore( $gameBoard, $player ) {
// Fetch amount of coloured discs
$scores = $this->calculateScore( $gameBoard );
// Use the difference as our score (score will change depending on who is fetching the max & min score)
$score = ( $player == 'w' ) ? $scores['w'] - $scores['b'] : $scores['b'] - $scores['w'];
return $score;
}
/**
* Let's run the AI algorithm
*
* @param $gameboard
* The gameboard to run on
*/
public function runAi( $gameboard ) {
$this->possibleMoves = array();
$this->gameBoard = $gameboard;
// Run the minmax algorithm
$this->minmax( $gameboard, $this->possibleMoves, 1, $this->getNodes(), $this->getActivePlayer() );
}
/**
* Set the node
*
* @param $node
* The amount of nodes deep to search
*/
public function setNodes( $node = 5 ) {
if ( ! is_int( $node ) ) {
throw new Exception( "Please enter a valid amount of nodes." );
}
if ( $node < 1 || $node > 14 ) {
throw new Exception( "Node must be within the range 0 < node < 15" );
}
$this->nodes = $node;
}
/**
* Get the amount of nodes
*/
public function getNodes() {
return $this->nodes;
}
/**
* Returns the possible moves
*/
public function getPossibleMovesProperty() {
$scoreObj = new stdClass;
$scoreObj->value = $this->possibleMoves;
return $scoreObj;
}
/**
* Loops throughs the scores to find the best path
*
* @param $scores
* An array of scores
* @param $score
* An individual score
*/
public function loopScores( $scores, $score ) {
foreach( $scores as $ide => $val ) {
if( is_array( $val ) && isset( $val['score'] ) && $val['score'] == $score ) {
// call recursive function
$this->treePath[] = $ide;
$this->loopScores( $val, $score, $path );
break;
}
}
}
/**
* Makes the moves
*/
public function makeMoves( $debug = false ) {
$player = $this->getActivePlayer();
$gameboard = $this->gameBoard;
$this->outString = '';
$this->moves = array();
// Let's go through each branch
foreach( $this->treePath as $id ) {
$moves = $this->getPossibleMoves( $gameboard, $player );
// Go through each set of possible moves on said branch
foreach( $moves as $ide => $move ) {
if( $ide == $id ) {
list( $x, $y, $whereToMove ) = $move;
// Make the move
$gameboard = $this->commitMove( $whereToMove, $player, $gameboard );
// Append to the moves array
$this->moves[] = $gameboard;
// Some simple output
if( $debug == true ) {
$this->outString .= "\n";
$this->outString .= "$player moved at: $x,$y. " . ( ( $player == 'w' ) ? 'b' : 'w' ) . " to move.\n";
$this->outString .= $this->outputBoard( $gameboard, true );
$this->outString .= print_r( $this->calculateScore( $gameboard ), true );
$this->outString .= "\n";
}
// Swap the player
$player = ( $player == 'w' ) ? 'b' : 'w';
}
}
}
}
/**
* Set the active player
*/
public function setActivePlayer( $player ) {
if( ! is_string( $player ) || ! in_array( $player, array( 'w', 'b' ) ) ) {
throw new Exception( 'Active player must be either \'w\' or \'b\'' );
}
$this->activePlayer = $player;
}
/**
* Get the active player
*/
public function getActivePlayer() {
return $this->activePlayer;
}
/**
* Get the output
*/
public function getOutput() {
return $this->outString;
}
/**
* Get moves
*/
public function getMoves() {
$obj = new stdClass;
foreach( $this->moves as $id => $move ) {
$obj->move[ $id ] = $move;
}
return $obj;
}
/**
* Minimax function (really a variation of a negamax function)
*
* @param $gameboard
* The gameboard to perform the calculations on
* @param $searchArr
* Array of scores to search through
* @param $node
* The current node we're in
* @param $depth
* The amount of nodes deep to search
* @param $player
* The player to evaluate the score for.
*
* @return
* the score we should take
*/
private function minmax( $gameboard, &$searchArr, $node = 1, $depth = 3, $player = 'w' ) {
// >: We've reached our maximum depth. Let's just treat these child nodes as leaves and end it here.
if( $node > $depth ) {
$searchArr['score'] = $this->evaluateScore( $gameboard, $this->getActivePlayer() ); // Always evaluate the score for the active player
return $searchArr['score'];
}
// Get the next mover
$nextMover = ( $player == 'w' ) ? 'b' : 'w';
// Otherwise, let's look for all possible moves on the gameboard
$moves = $this->getPossibleMoves( $gameboard, $player );
// We've got a leaf, signalling an end to the game, meaning a definite winner.
if( sizeOf( $moves ) == 0 ) {
// Check to see if the opponent can move - if they can, we have to hand over to them (and forego our own turn - only just realised this)
$opponentsMoves = $this->getPossibleMoves( $gameboard, $nextMover );
// If the opponent can move, let's just give them a go (WIP)
if( sizeOf( $opponentsMoves ) > 0 && 1 == 2 ) {
$searchArr[] = array();
//$activeScore = 123;
$activescore = $this->minmax( $gameboard, $searchArr[ sizeOf( $searchArr ) - 1 ], $node + 1, $depth, $nextMover );
}
// Otherwise, the opponent can't move, meaning the game has well and truly ended
else if( sizeOf( $opponentsMoves ) == 0 ||*1 == 1 ) {
// We can't actually use an infinite value, so let's just use +-999
$score = $this->evaluateScore( $gameboard, $this->getActivePlayer() );
if( $score == 0 ) $activeScore = 0; // It's a draw.
else if( $player == $this->getActivePlayer() ) $activeScore = ( $score > 0 ) ? 999 : -999;
else $activeScore = ( $score < 0 ) ? 999 : -999;
}
}
// Otherwise loop through the child nodes
foreach( $moves as $id => $move ) {
list( $x, $y, $moves ) = $move;
$newGameBoard = $this->commitMove( $moves, $player, $gameboard );
$searchArr[] = array();
$score = $this->minmax( $newGameBoard, $searchArr[ sizeOf( $searchArr ) - 1 ], $node + 1, $depth, $nextMover );
// Set the score?
if( ! isset( $activeScore ) ) {
$activeScore = $score;
}
// Else, apply min/max
else {
if( $node % 2 == 0 && (int) $score > (int) $activeScore ) $activeScore = $score;
else if( $node % 2 <> 0 && (int) $score < (int) $activeScore ) $activeScore = $score;
}
}
$searchArr['score'] = $activeScore;
return $activeScore;
}
/**
* Get possible moves
*
* @param $gameBoard
* The gameboard we should evaluate
* @param $player
* Retrieve scores relative to $player
*
* @return
* Array of possible moves
*/
private function getPossibleMoves( $gameBoard, $player ) {
// Return array
$return = array();
// Loop through the gameboard, look for empty squares
foreach( range( 0, sizeOf( $gameBoard ) - 1 ) as $x ) {
foreach( range( 0, sizeOf( $gameBoard ) - 1 ) as $y ) {
// If we've found a blank space, let's try and find the possible moves for that pt(x,y)
if( $gameBoard[ $x ][ $y ] == '.' ) {
$possibleMoves = $this->testMove( $x, $y, $player, $gameBoard );
// We've found some possible moves
if( sizeOf( $possibleMoves ) > 0 ) {
$possibleMoves[] = array( $x, $y );
$return[] = array( $x, $y, $possibleMoves );
}
}
}
}
return $return;
}
}
misc.php - think I was going to build on thisPHP Code:
<?php
class Reversi {
// Private variables. Use the setter/getter functions to access.
private $board = array();
private $rows = 8;
private $nextTurn = 'black';
private $reversiAi;
// Constants
const NL = PHP_EOL;
public function __construct() {
$this->reversiAi = new ReversiAI;
}
// Start the game
public function newGame() {
// Let's initialise the game board.
$this->initialiseBoard();
}
// Let's test out a move - is it valid, how many will we reverse?
public function testMove( $x, $y, $move, $board = null ) {
// What gameboard are we using? Current gameboard is default, or user supplied gameboard (for AI analysis)
$gameBoard = ( $board == null ) ? $this->getGameBoard() : $board;
// Out of bounds?
if( $x > ( $this->getRows( $gameBoard ) - 1 ) || $x < 0 || $y > ( $this->getRows( $gameBoard ) - 1 ) || $y < 0 ) {
throw new Exception( 'x/y coordinates out of bounds.' );
}
// Current position already taken?
if( $this->getPiece( $x, $y, $gameBoard ) != '.' ) {
throw new Exception( 'x/y coordinate is not available to move on.' );
}
// Four ranges to test for horizontal/vertical axes
$ranges = array(
array( array( $x, $y ), array( 0, $y ) ),
array( array( $x, $y ), array( $this->getRows( $gameBoard ) - 1, $y ) ),
array( array( $x, $y ), array( $x, 0 ) ),
array( array( $x, $y ), array( $x, $this->getRows( $gameBoard ) - 1 ) ),
);
// Let's test each of the ranges
$availableMoves = array();
foreach( $ranges as $range ) {
$availableMoves = array_merge( $availableMoves, $this->reverseXYBlocks( $range[0], $range[1], $move, $gameBoard ) );
}
// Loop through diagonal coordinates and test each for squares to reverse
foreach( $this->diagonalCoordinates( array( $x, $y ) ) as $diag ) {
$availableMoves = array_merge( $availableMoves, $this->testDiag( $diag, $move, $gameBoard ) );
}
return $availableMoves;
}
// Commit move - should be called after testMove.
public function commitMove( $testResults, $colour, $board = null ) {
// Data checks
if( ! is_array( $testResults ) ) {
throw new Exception( 'Invalid format for commitMove. $testResults must be an array.' );
}
if( ! in_array( $colour, array( 'w', 'b' ) ) ) {
throw new Exception( 'Invalid colour supplied for $colour paramater.' );
}
// Let's loop through the moves
foreach( $testResults as $coords ) {
if( ! is_array( $coords ) || sizeOf( $coords ) <> 2 ) {
throw new Exception( 'Invalid format for coordinates in $testResults array.' );
}
// Set the piece
list( $x, $y ) = $coords;
// Actually committing, or making a virtual commit (AI)?
if( $board == null ) $this->setPiece( array( $x, $y, $colour ) );
else $board[ $x ][ $y ] = $colour;
}
if( $board !== null ) return $board;
}
// Let's calculate the score for a gameboard
public function calculateScore( $gameBoard ) {
if( ! is_array( $gameBoard ) || ! isset( $gameBoard[0] ) || ! is_array( $gameBoard[0] ) ) {
throw new Exception( 'Invalid $gameBoard' );
}
// Blank score array
$scores = array(
'w' => 0,
'b' => 0
);
// Let's loop through the gameboard and increment the scores.
foreach( range( 0, sizeOf( $gameBoard ) - 1 ) as $x ) {
foreach( range( 0, sizeOf( $gameBoard[0] ) - 1 ) as $y ) {
$block = $gameBoard[ $x ][ $y ];
if( isset( $scores[ $block ] ) ) $scores[ $block ] += 1;
}
}
return $scores;
}
// Reversi AI class
public function aiClass() {
return $this->reversiAi;
}
// Set a piece
public function setPiece( $piece ) {
// Data checks
if( ! is_array( $piece ) || sizeOf( $piece ) == 0 ) {
throw new Exception( 'You have attempted to assign an invalid piece.' );
}
// Are we dealing with an array of pieces, or a single piece?
if( is_array( $piece[0] ) ) {
foreach( $piece as $addPiece ) {
$this->_setPiece( $addPiece );
}
}
// Otherwise we only want to add a single piece
else $this->_setPiece( $piece );
}
// Retrieve a piece
public function getPiece( $x, $y, $board = null ) {
// Numeric x, y within propery range?
if( ! is_numeric( $x ) || ! is_numeric( $y ) || $x >= $this->rows || $y >= $this->rows ) {
throw new Exception( 'x, y paramaters must be numeric and within the range 0 <= x/y <= ' . ( $this->rows - 1 ) );
}
return ( $board == null ) ? $this->board[ $x ][ $y ] : $board[ $x ][ $y ];
}
// Set the active gameboard
public function setGameBoard( $board ) {
// Some data integrity checks
if( ! is_array( $board ) || sizeOf( $board ) !== $this->getRows() ) {
throw new Exception( 'Invalid gameboard.' );
}
foreach( $board as $subBoard ) {
if( ! is_array( $subBoard ) || sizeOf( $subBoard ) !== $this->getRows() ) {
throw new Exception( 'Invalid gameboard #2' );
}
}
// Otherwise it appears to be okay, so let's overwrite the existing gameboard.
$this->board = $board;
}
// Fetch the active gameboard
public function getGameBoard() {
return $this->board;
}
// Set the next turn.
public function setNextTurn( $next ) {
// Valid data?
if( ! is_string( $next ) || ! in_array( $next, array( 'b', 'w' ) ) ) {
throw new Exception( 'Invalid config setting for next move. Must be either \'b\' or \'w\'' );
}
$this->nextTurn = $next;
}
// Get the user to make the next turn.
public function getNextTurn() {
return $this->nextTurn;
}
// Set the amount of rows to use
public function setRows( $rows ) {
// Valid data?
if( ! is_numeric( $rows ) ) {
throw new Exception( 'The amount of rows must be a valid integer.' );
}
// Let's just impose some limits.
if( $rows < 4 || $rows > 12 ) {
throw new Exception( 'That\'s a bit ambitious! Let\'s keep the game simple, shall we?' );
}
$this->rows = $rows;
}
// Get the amount of rows we're using
public function getRows( $gameBoard = null ) {
return ( $gameBoard == null ) ? $this->rows : sizeOf( $gameBoard );
}
// Initialise the game board
private function initialiseBoard() {
// Create an empty game board.
foreach( range( 0, $this->rows - 1 ) as $x ) {
foreach( range( 0, $this->rows - 1 ) as $y ) {
$this->board[ $x ][ $y ] = '.';
}
}
// Set the default pieces
$startCoord = ceil( $this->rows / 2 );
$pieces = array(
array( $startCoord - 1, $startCoord, 'w' ),
array( $startCoord, $startCoord, 'b' ),
array( $startCoord - 1, $startCoord - 1, 'b' ),
array( $startCoord, $startCoord - 1, 'w' )
);
$this->setPiece( $pieces );
}
// Set a piece
private function _setPiece( $piece ) {
// Do we have an array and is it the correct amount of arguments?
if( ! is_array( $piece ) || sizeOf( $piece ) <> 3 ) {
throw new Exception( '$piece argument must be in the form of array( x, y, [ w, b ] )' );
}
// Let's fetch the values now we know the arguments have been correctly passed through.
list( $x, $y, $colour ) = $piece;
// Numeric x, y within propery range?
if( ! is_numeric( $x ) || ! is_numeric( $y ) || $x >= $this->rows || $y >= $this->rows ) {
throw new Exception( 'x, y paramaters must be numeric and within the range 0 <= x/y <= ' . ( $this->rows - 1 ) );
}
// Correct colour?
if( ! in_array( strtolower( $colour ), array( 'w', 'b' ) ) ) {
throw new Exception( 'Colour paramater must be either \'x\' or \'y\'' );
}
// Passed all of the checks, let's add it to the game board
$this->board[ $x ][ $y ] = strtolower( $colour );
}
// Retrieve all of the diagonal coordinates for a pt(x,y)
private function diagonalCoordinates( $coord, $board = null ) {
$arr = array();
$counter = 0;
$gameBoard = ( $board == null ) ? $this->getGameBoard() : $board;
list( $x, $y ) = $coord;
// Loop through until we've exhausted all options
while( true ) {
++$counter;
if( $x - $counter >= 0 && $y - $counter >= 0 ) $arr[0][] = array( $x - $counter, $y - $counter );
if( $x + $counter <= ( $this->getRows( $gameBoard ) - 1 ) && $y + $counter <= ( $this->getRows( $gameBoard ) - 1 ) ) $arr[1][] = array( $x + $counter, $y + $counter );
if( $x + $counter <= ( $this->getRows( $gameBoard ) - 1 ) && $y - $counter >= 0 ) $arr[2][] = array( $x + $counter, $y - $counter );
if( $x - $counter >= 0 && $y + $counter <= ( $this->getRows( $gameBoard ) - 1 ) ) $arr[3][] = array( $x - $counter, $y + $counter );
if( $x - $counter < 0 && $x + $counter > ( $this->getRows( $gameBoard ) - 1 ) && $y - $counter < 0 && $x + $counter > ( $this->getRows( $gameBoard ) - 1 ) ) break;
}
return $arr;
}
// Test diagonal ranges for squares to reverse
private function testDiag( $range, $move, $board = null ) {
// Gameboard
$gameBoard = ( $board == null ) ? $this->getGameBoard() : $board;
// If we don't have enough coordinates (<=2), let's just return an empty array.
if( sizeOf( $range ) <= 2 ) return array();
// Return array
$return = array();
// Who is our opponent? Opposite of $move
$opponent = ( $move == 'w' ) ? 'b' : 'w';
// Loop through the ranges
$res = array();
foreach( $range as $coords ) {
// Retrieve x/y values
list( $xOrd, $yOrd ) = $coords;
// If we've found a valid piece.
if( $this->getPiece( $xOrd, $yOrd, $gameBoard ) == $opponent ) {
$res[] = array( $xOrd, $yOrd );
}
// Otherwise, we've found our own piece! Do what we gotta do, and then let's break out!
else if( $this->getPiece( $xOrd, $yOrd, $gameBoard ) == $move ) {
// If we've found anything, let's append it to the results
if( sizeOf( $res ) > 0 ) $return = array_merge( $res, $return );
break;
}
// Otherwise we've found empty space, return empty every time
else if( $this->getPiece( $xOrd, $yOrd, $gameBoard ) == '.' ) {
break;
}
}
return $return;
}
// Calculate the pieces to turn between two points.
private function reverseXYBlocks( $start, $end, $move, $board = null ) {
// If the two co-ordinates are the same, just return.
if( $start == $end ) return array();
// Return array
$return = array();
// Who is our opponent? Opposite of $move
$opponent = ( $move == 'w' ) ? 'b' : 'w';
// Default x/y values
list( $x, $y ) = $start;
// What gameboard to use?
$gameBoard = ( $board == null ) ? $this->getGameBoard() : $board;
// Horizontal axis
$xy = ( $start[0] <> $end[0] ) ? 0 : 1; // Should we use the x or y oordinate (changes depending on axis to search) 0 = horizontal 1 = vertical
$startLoop = ( $start[ $xy ] > $end[ $xy ] ) ? 0 : $start[ $xy ] + 1;
$endLoop = ( $start[ $xy ] > $end[ $xy ] ) ? $start[ $xy ] - 1 : $this->getRows( $gameBoard ) - 1;
// Let's loop through
foreach( range( $startLoop, $endLoop ) as $coord ) {
if( $start[ $xy ] > $end[ $xy ] ) $coord = $endLoop - $coord; // If going left, we need to account for that.
// What x/y should we use? Changes depending on horizontal/vertical. Use the active loop count or revert to default.
$xOrd = ( $xy == 0 ) ? $coord : $x;
$yOrd = ( $xy == 1 ) ? $coord : $y;
// If we've found a valid piece.
if( $this->getPiece( $xOrd, $yOrd, $gameBoard ) == $opponent ) {
$res[] = array( $xOrd, $yOrd );
}
// Otherwise, we've found our own piece! Do what we gotta do, and then let's break out!
else if( $this->getPiece( $xOrd, $yOrd, $gameBoard ) == $move ) {
// If we've found anything, let's append it to the results
if( sizeOf( $res ) > 0 ) $return = array_merge( $res, $return );
break;
}
// Otherwise we've found empty space, return an empty array every time
else if( $this->getPiece( $xOrd, $yOrd,$gameBoard ) == '.' ) {
break;
}
}
return $return;
}
// Output the board
public function outputBoard( $board = null, $return = false ) {
$gameBoard = ( $board == null ) ? $this->getGameBoard() : $board;
// Loop through the board array to output
foreach( range( 0, sizeOf( $gameBoard ) - 1 ) as $y ) {
foreach( range( 0, sizeOf( $gameBoard ) - 1 ) as $x ) {
$yCoord = ( sizeOf( $gameBoard ) - 1 ) - $y;
$piece = $this->getPiece( $x, $yCoord, $gameBoard );
// Output or append to return string?
if( $return == false ) echo $piece . ' ';
else $returnString .= $piece . ' ';
}
// Output new line or append to return string?
if( $return == false ) echo self::NL;
else $returnString .= self::NL;
}
if( $return === true ) return $returnString;
}
}
simulation.php - runs the simulation to meet their requirementsPHP Code:
<?php
// Misc class
function getInput( ) {
$handle = fopen ( 'php://stdin', 'r' );
return trim( fgets( $handle ) );
}
PHP Code:
<?php
// Includes
require_once( 'reversi.class.php' );
require_once( 'reversi.engine.class.php' );
// Let's just keep her running for a while.
set_time_limit( 1800 );
ini_set( 'memory_limit', '1024M' );
echo "<pre>Reversi AI engine example\nAlex Roxon <alex@redacted.com>\n\n";
// Constants
define( 'GAMEFILE', 'game.txt' );
define( 'NODES', 5 );
define( 'DEBUG', true );
// Instantiate the Reversi class.
$Reversi = new Reversi;
// Let's play reversi!
try {
// Let's load the game data
if( ! file_exists( GAMEFILE ) || ! is_readable( GAMEFILE ) ) {
throw new Exception( 'Unable to load game config file: ' . GAMEFILE );
}
// Data -> lower case array + remove white space.
$config = array_map( 'strtolower', array_map( 'trim', file( GAMEFILE ) ) );
// Let's check the validity of some of the user data and toggle game settings
if( ! is_array( $config ) || sizeOf( $config ) <= 1 ) {
throw new Exception( 'Invalid format for game config file.' );
}
// Let's set next move. After we've done it, don't need that line anymore, so let's just remove it from the array so we can easily loop through.
$Reversi->setNextTurn( substr( $config[0], 0, 1 ) ); // Only needs first letter.
unset( $config[0] );
// Let's set the amount of rows
$Reversi->setRows( sizeOf( $config ) );
// Let's start a new game!
$Reversi->newGame();
// Loop through the gameboard and retrieve necessary character values. Want to create a gameboard as set by Gaiaonline.
foreach( $config as $lineNum => $vals ) {
// Sort out the y oordinate.
$y = $Reversi->getRows() - $lineNum;
foreach( range( 0, strlen( $vals ) - 1 ) as $x ) {
// If it's black or white, let's append it to our game board. If it's not, we can just ignore it.
if( in_array( $vals[ $x ], array( 'b', 'w' ) ) ) {
$Reversi->setPiece( array( $x, $y, $vals[ $x ] ) );
}
}
}
// Output the board
$Reversi->outputBoard();
// Run the AI engine
$Reversi->aiClass()->setActivePlayer( $Reversi->getNextTurn() );
$Reversi->aiClass()->setNodes( NODES );
$Reversi->aiClass()->runAi( $Reversi->getGameBoard() );
// Loop through the scores to produce our tree path
$Reversi->aiClass()->loopScores( $Reversi->aiClass()->getPossibleMovesProperty()->value, $Reversi->aiClass()->getPossibleMovesProperty()->value['score'] );
// Make the moves!
$Reversi->aiClass()->makeMoves( DEBUG );
// Output
print $Reversi->aiClass()->getOutput();
} catch( Exception $e ) {
echo 'Caught exception: ', $e->getMessage();
exit;
}
echo "</pre>";
Results 1 to 3 of 3
- 10 Dec. 2011 01:55am #1
Gaia Online Careers Puzzle - Reversi
Last edited by Artificial; 10 Dec. 2011 at 01:57am.
- 10 Dec. 2011 03:08am #2
Didnt you already post this arti?
Gaiaonline Exploit Log:
http://d8silo.b1.jcink.com/index.php?act=Pages&pid=12
The day I re-wrote gaias homepage:
http://rankmyhack.com/userview.php?user=Nirvash
- 17 Dec. 2011 10:17pm #3
Possibly - not too sure. However, it's more relevant in this forum, hence I thought I'd post it.