/class/iShudan.class.php
PHP | 961 lines | 756 code | 145 blank | 60 comment | 277 complexity | 90e3f60ec3da8de592e45ef7d05cff92 MD5 | raw file
Possible License(s): GPL-3.0
- <?php
- /*
- +---------------------------------------------------------------------------
- |
- | iShudan.class.php (php 4.x)
- |
- | by Benjam Welker
- | http://www.iohelix.net
- | based on works by
- | http://www.sourceforge.com
- |
- +---------------------------------------------------------------------------
- |
- | > PHP Go module
- | > Date started: 2007-01-13
- | > Last edited: 2007-01-13
- |
- | > Module Version Number: 0.8
- |
- | $Id$
- +---------------------------------------------------------------------------
- */
- class iShudan
- {
- var $board; // the board array
- var $oldboard; // the old board array, for ko testing purposes
- var $empty_board; // the empty board for display purposes
- var $boardsize; // the size of the board
- var $handicap; // the black player's handicap
- var $color; // the color of the current move
- var $turn; // (true / false) player's turn ?
- var $history; // the history array
- var $move; // the current move
- var $moves; // the previous moves array
- var $move_count; // the number of moves performed
- var $moved_stone_x; // the moved stone's x position
- var $moved_stone_y; // the moved stone's y position
- var $black_prisoners; // the black prisoners
- var $white_prisoners; // the white prisoners
- var $passes; // the number of consecutive passes
- var $resign; // whether or not the player resigned
- var $dummy; // ???
- var $visited; // the list of visited points
- var $stones_visited; // the list of visited stones
- var $freedoms_visited; // the list of visited freedoms
- var $removed; // the list of removed stones
- var $owner; // the owner of a group with freedoms
- var $freedom; // the number of freedoms in a group
- var $error; // any errors that may be encountered
- function iShudan( )
- {
- // constructor
- }
- function set_board($board)
- {
- $this->board = $board;
- }
- function get_board( )
- {
- return $this->board;
- }
- function set_boardsize($boardsize)
- {
- // make sure the boarsize is valid
- if ((19 < $boardsize) || (9 > $boardsize) || (1 == ($boardsize % 2)))
- {
- $this->error = 'Incorrect boardsize given, boardsize must be an odd number between 9 and 19, inclusive.';
- return false;
- }
- $this->boardsize = $boardsize;
- return true;
- }
- function set_handicap($handicap)
- {
- // make sure the handicap is valid
- if ((9 < $handicap) || (2 > $handicap))
- {
- $this->error = 'Incorrect handicap given, handicap must be between 2 and 9, inclusive.';
- return false;
- }
- $this->handicap = $handicap;
- return true;
- }
- function set_moves($moves)
- {
- $this->moves = $moves;
- $this->move_count = count($this->moves);
- }
- // plays the moves array to the board, used to recreate board from moves array
- function play_moves($until = null)
- {
- $this->black_prisoners = 0;
- $this->white_prisoners = 0;
- $this->passes = 0;
- $this->resign = false;
- $this->history = array( );
- $until = is_null($until) ? $this->move_count + 1 : $until;
- if ($this->handicap > 0)
- {
- $this->board = $this->set_handicap_stones( );
- }
- for ($i = 0; $i < $this->move_count; ++$i)
- {
- for ($j = 0; $j < strlen($this->moves[$i]); $j = $j + 3)
- {
- list($this->color, $y, $x) = stringtocord(substr($this->moves[$i], $j, 3));
- if ('e' == $this->color)
- {
- if ($until > $i)
- {
- $this->insert_empty($y, $x);
- }
- ++$this->white_prisoners;
- }
- else if ('r' == $this->color)
- {
- if ($until > $i)
- {
- $this->insert_empty($y, $x);
- }
- ++$this->black_prisoners;
- }
- else if ((23 == $y) && (23 == $x))
- {
- if (($i == ($this->move_count - 1)) && ($until == ($this->move_count + 1)) || ($i == ($until - 1)))
- {
- $this->moved_stone_x = 0;
- $this->moved_stone_y = 0;
- }
- if ('b' == $this->color)
- {
- $cprint = 'Black';
- }
- if ('w' == $this->color)
- {
- $cprint = 'White';
- }
- ++$this->passes;
- $this->history[$i] = 'P';
- }
- else if ((25 == $y) && (25 == $x))
- {
- if (($i == ($this->move_count - 1)) && ($until == ($this->move_count + 1)) || ($i == ($until - 1)))
- {
- $this->moved_stone_x = 0;
- $this->moved_stone_y = 0;
- }
- if ('b' == $this->color)
- {
- $cprint = 'Black';
- $this->resign = 1;
- }
- if ('w' == $this->color)
- {
- $cprint = 'White';
- $this->resign = 2;
- }
- $this->passes = 0;
- $this->history[$i] = 'R';
- }
- else
- {
- if ((($i == ($this->move_count - 1)) && ($until == ($this->move_count + 1))) || ($i < $until))
- {
- $this->moved_stone_x = $x;
- $this->moved_stone_y = $y;
- }
- if ($until > $i)
- {
- $this->board[$y][$x] = $this->color;
- }
- if ('b' == $this->color)
- {
- $cprint = 'Black';
- }
- if ('w' == $this->color)
- {
- $cprint = 'White';
- }
- $this->history[$i] = strtolower(xtoalt($x)) . ($this->boardsize - $y);
- $this->passes = 0;
- }
- }
- if ($i == ($this->move_count - 2))
- {
- $this->oldboard = $this->board;
- }
- }
- # return array(
- # $board ,
- # $oldboard ,
- # $passes ,
- # $resign ,
- # $bprisoners ,
- # $wprisoners ,
- # $mstonex ,
- # $mstoney ,
- # $history ,
- # $countm ,
- # );
- }
- function set_handicap_stones( )
- {
- if (2 <= $this->handicap)
- {
- if ($this->boardsize >= 13)
- {
- $this->board[3][$this->boardsize - 4] = 'b';
- }
- if ($size_of_the_board < 13)
- {
- $this->board[2][$this->boardsize - 3] = 'b';
- }
- if ($this->boardsize >= 13)
- {
- $this->board[$this->boardsize - 4][3] = 'b';
- }
- if ($this->boardsize < 13)
- {
- $this->board[$this->boardsize - 3][2] = 'b';
- }
- }
- if (3 <= $this->handicap)
- {
- if ($this->boardsize >= 13)
- {
- $this->board[$this->boardsize - 4][$this->boardsize - 4] = 'b';
- }
- if ($this->boardsize < 13)
- {
- $this->board[$this->boardsize - 3][$this->boardsize - 3] = 'b';
- }
- }
- if (4 <= $this->handicap)
- {
- if ($this->boardsize >= 13)
- {
- $this->board[3][3] = 'b';
- }
- if ($this->boardsize < 13)
- {
- $this->board[2][2] = 'b';
- }
- }
- if (5 <= $this->handicap)
- {
- if ($this->boardsize >= 13)
- {
- $this->board[ceil($this->boardsize / 2) - 1][$this->boardsize - 4] = 'b';
- }
- if ($this->boardsize < 13 && $this->boardsize > 7)
- {
- $this->board[ceil($this->boardsize / 2) - 1][$this->boardsize - 3] = 'b';
- }
- }
- if (6 <= $this->handicap)
- {
- if ($this->boardsize >= 13)
- {
- $this->board[ceil($this->boardsize / 2) - 1][3] = 'b';
- }
- if ($this->boardsize < 13 && $this->boardsize > 7)
- {
- $this->board[ceil($this->boardsize / 2) - 1][2] = 'b';
- }
- }
- if (7 <= $this->handicap)
- {
- if ($this->boardsize >= 13)
- {
- $this->board[3][ceil($this->boardsize / 2) - 1] = 'b';
- }
- if ($this->boardsize < 13 && $this->boardsize > 7)
- {
- $this->board[2][ceil($this->boardsize / 2) - 1] = 'b';
- }
- }
- if (8 <= $this->handicap)
- {
- if ($this->boardsize >= 13)
- {
- $this->board[$this->boardsize - 4][ceil($this->boardsize / 2) - 1] = 'b';
- }
- if ($this->boardsize < 13 && $this->boardsize > 7)
- {
- $this->board[$this->boardsize - 3][ceil($this->boardsize / 2) - 1] = 'b';
- }
- }
- if (9 == $this->handicap)
- {
- if ($this->boardsize >= 13)
- {
- $this->board[ceil($this->boardsize / 2) - 1][ceil($this->boardsize / 2) - 1] = 'b';
- }
- if ($this->boardsize < 13 && $this->boardsize > 7)
- {
- $this->board[ceil($this->boardsize / 2) - 1][ceil($this->boardsize / 2) - 1] = 'b';
- }
- }
- }
- // insert an empty field on the given position into the board array
- function insert_empty($y, $x)
- {
- if ($y == 0)
- {
- if ($x == 0)
- {
- $stone = 'lt';
- }
- else if ($x == $this->boardsize - 1)
- {
- $stone = 'rt';
- }
- else
- {
- $stone = 'mt';
- }
- }
- else if ($y == $this->boardsize - 1)
- {
- if ($x == 0)
- {
- $stone = 'lb';
- }
- else if ($x == $this->boardsize - 1)
- {
- $stone = 'rb';
- }
- else
- {
- $stone = 'mb';
- }
- }
- else
- {
- if ($x == 0)
- {
- $stone = 'lm';
- }
- else if ($x == $this->boardsize - 1)
- {
- $stone = 'rm';
- }
- else
- {
- if ($this->boardsize >= 13 && ($y == 3 && ($x == 3 || $x == ceil($this->boardsize / 2) - 1 || $x == $this->boardsize - 4)))
- {
- $stone = 'ko';
- }
- else if ($this->boardsize >= 13 && ($y == ceil($this->boardsize / 2) - 1 && ($x == 3 || $x == ceil($this->boardsize / 2) - 1 || $x == $this->boardsize - 4)))
- {
- $stone = 'ko';
- }
- else if ($this->boardsize >= 13 && ($y == $this->boardsize - 4 && ($x == 3 || $x == ceil($this->boardsize / 2) - 1 || $x == $this->boardsize - 4)))
- {
- $stone = 'ko';
- }
- else if ($this->boardsize < 13 && $this->boardsize > 7 && ($y == 2 && ($x == 2 || $x == ceil($this->boardsize / 2) - 1 || $x == $this->boardsize - 3)))
- {
- $stone = 'ko';
- }
- else if ($this->boardsize < 13 && $this->boardsize > 7 && ($y == ceil($this->boardsize / 2) - 1 && ($x == 2 || $x == ceil($this->boardsize / 2) - 1 || $x == $this->boardsize - 3)))
- {
- $stone = 'ko';
- }
- else if ($this->boardsize < 13 && $this->boardsize > 7 && ($y == $this->boardsize - 3 && ($x == 2 || $x == ceil($this->boardsize / 2) - 1 || $x == $this->boardsize - 3)))
- {
- $stone = 'ko';
- }
- else if ($this->boardsize == 7 && ($y == 2 && ($x == 2 || $x == $this->boardsize - 3)))
- {
- $stone = 'ko';
- }
- else if ($this->boardsize == 7 && ($y == $this->boardsize - 3 && ($x == 2 || $x == $this->boardsize - 3)))
- {
- $stone = 'ko';
- }
- else
- {
- $stone = 'mm';
- }
- }
- }
- $this->board[$y][$x] = $stone;
- }
- // do a move a user requested, take prisoners
- function do_move($y, $x)
- {
- $this->board[$y][$x] = $this->color;
- if ($this->color == 'b')
- {
- $this->dummy = $this->group_runs_out_of_liberties($y, $x, true, 'w');
- }
- else if ($color == 'w')
- {
- $this->dummy = $this->group_runs_out_of_liberties($y, $x, true, 'b');
- }
- else
- {
- $this->error = 'Given color attribute is not known.';
- }
- }
- // return true if the move is ko and therfore not allowed, else return false
- function is_ko($y, $x)
- {
- $backup = $this->board;
- $this->do_move($y, $x);
- for ($i = 0; $i < $this->boardsize; ++$i)
- {
- for ($j = 0; $j < $this->boardsize; ++$j)
- {
- if ($this->board[$i][$j] == $this->oldboard[$i][$j])
- {
- $ko = true;
- }
- else
- {
- $ko = false;
- break;
- }
- }
- if ($ko == false)
- {
- break;
- }
- }
- $this->board = $backup;
- return $ko;
- }
- // return true if the point on the board is a free space
- function is_freedom($y, $x)
- {
- return ((('b' != $this->board[$y][$x]) && ('w' != $this->board[$y][$x])) ? true : false);
- }
- // return true if the move is not a suicide, this function does not check for ko se the is_ko function for this
- function is_legal_move($y, $x)
- {
- if (('b' != $this->board[$y][$x]) && ('w' != $this->board[$y][$x]))
- {
- $backup = $this->board[$y][$x];
- if ($this->color == 'b')
- {
- $this->board[$y][$x] = 'b';
- if ($this->freedom_of_group($y, $x) < 1)
- {
- $this->board[$y][$x] = 'b';
- if ( ! $this->group_runs_out_of_liberties($y, $x, false, 'w'))
- {
- $this->board[$y][$x] = $backup;
- return false;
- }
- else
- {
- $this->board[$y][$x] = $backup;
- return true;
- }
- }
- $this->board[$y][$x] = $backup;
- return true;
- }
- else if ($this->color == 'w')
- {
- $this->board[$y][$x] = 'w';
- if ($this->freedom_of_group($y, $x) < 1)
- {
- if ( ! $this->group_runs_out_of_liberties($y, $x, false, 'b'))
- {
- $this->board[$y][$x] = $backup;
- return false;
- }
- else
- {
- $this->board[$y][$x] = $backup;
- return true;
- }
- }
- $this->board[$y][$x] = $backup;
- return true;
- }
- else
- {
- $this->error = 'Given color attribute is not known.';
- return false;
- }
- }
- }
- function is_move_possible($y, $x)
- {
- return ( ! $this->is_ko($y, $x) && $this->is_legal_move($y, $x));
- }
- // delete the stones last checked by another function
- function delete_current_visited( )
- {
- $pos_to_delete = strtok($this->visited, ',');
- while (strlen($pos_to_delete) >= 1)
- {
- if (strlen($pos_to_delete) >= 1)
- {
- if (intval($pos_to_delete) >= 100)
- {
- $y = floor(intval($pos_to_delete) / 100);
- }
- else
- {
- $y = 0;
- }
- $x = intval($pos_to_delete) - ($y * 100);
- if ($color == 'b')
- {
- $rcolor = 'e';
- }
- else if ($color == 'w')
- {
- $rcolor = 'r';
- }
- else
- {
- echo 'Error';
- die;
- }
- if ( ! strstr($this->removed, $rcolor . chr($y + 97) . chr($x + 97)))
- {
- $this->removed = $this->removed . $rcolor . chr($y + 97) . chr($x + 97);
- }
- $this->board[$y][$x] = $hits->insert_empty($y, $x);
- }
- $pos_to_delete = strtok(',');
- }
- }
- // return all board positions which are connected by lines to the current one
- function is_connected_to($y, $x)
- {
- $connected = array( );
- if ($y == 0)
- {
- if ($x == 0)
- {
- $connected[0] = $y + 1;
- $connected[1] = $x;
- $connected[2] = $y;
- $connected[3] = $x + 1;
- }
- else if ($x == $this->boardsize - 1)
- {
- $connected[0] = $y + 1;
- $connected[1] = $x;
- $connected[2] = $y;
- $connected[3] = $x - 1;
- }
- else
- {
- $connected[0] = $y;
- $connected[1] = $x - 1;
- $connected[2] = $y;
- $connected[3] = $x + 1;
- $connected[4] = $y + 1;
- $connected[5] = $x;
- }
- }
- else if ($y == $this->boardsize - 1)
- {
- if ($x == 0)
- {
- $connected[0] = $y - 1;
- $connected[1] = $x;
- $connected[2] = $y;
- $connected[3] = $x + 1;
- }
- else if ($x == $this->boardsize - 1)
- {
- $connected[0] = $y - 1;
- $connected[1] = $x;
- $connected[2] = $y;
- $connected[3] = $x - 1;
- }
- else
- {
- $connected[0] = $y;
- $connected[1] = $x - 1;
- $connected[2] = $y;
- $connected[3] = $x + 1;
- $connected[4] = $y - 1;
- $connected[5] = $x;
- }
- }
- else
- {
- if ($x == 0)
- {
- $connected[0] = $y - 1;
- $connected[1] = $x;
- $connected[2] = $y + 1;
- $connected[3] = $x;
- $connected[4] = $y;
- $connected[5] = $x + 1;
- }
- else if ($x == $this->boardsize - 1)
- {
- $connected[0] = $y - 1;
- $connected[1] = $x;
- $connected[2] = $y + 1;
- $connected[3] = $x;
- $connected[4] = $y;
- $connected[5] = $x - 1;
- }
- else
- {
- $connected[0] = $y + 1;
- $connected[1] = $x;
- $connected[2] = $y - 1;
- $connected[3] = $x;
- $connected[4] = $y;
- $connected[5] = $x + 1;
- $connected[6] = $y;
- $connected[7] = $x - 1;
- }
- }
- return $connected;
- }
- // return true if group is dead
- function group_runs_out_of_liberties($y, $x, $delete_dead_stones)
- {
- $they_are_dead_jim = false;
- $counter = 0;
- $to_check = $this->is_connected_to($y, $x);
- foreach ($to_check as $number => $coord)
- {
- if ($counter % 2 == 0)
- {
- if ($this->board[$to_check[$counter]][$to_check[$counter + 1]] == $this->color)
- {
- if ($this->freedom_of_group($to_check[$counter], $to_check[$counter + 1]) < 1)
- {
- if ($delete_dead_stones)
- {
- $this->delete_current_visited($this->color);
- }
- $they_are_dead_jim = true;
- }
- }
- }
- ++$counter;
- }
- return $they_are_dead_jim;
- }
- // returns the owner and the number of freedoms grouped together
- function group_of_freedoms($y, $x)
- {
- $this->visited = ',';
- $this->stones_visited = ',';
- $to_visit_string = ',' . strval(($y * 100) + $x) . ',';
- $this->owner = '';
- $this->freedom = 0;
- while (strlen($to_visit_string) > 2)
- {
- $cord_to_visit = strtok(substr($to_visit_string, 1), ',');
- if (intval($cord_to_visit) >= 100)
- {
- $y = floor(intval($cord_to_visit) / 100);
- }
- else
- {
- $y = 0;
- }
- $x = intval($cord_to_visit) - ($y * 100);
- $to_visit_string = str_replace(',' . $cord_to_visit . ',', ',', $to_visit_string);
- $counter = 0;
- $to_check = is_connected_to($y, $x);
- foreach ($to_check as $number => $coord)
- {
- if ($counter % 2 == 0)
- {
- if ( ! strstr($this->stones_visited, ',' . strval((($to_check[$counter]) * 100) + $to_check[$counter + 1]) . ','))
- {
- if ( ! $this->is_freedom($to_check[$counter], $to_check[$counter + 1]))
- {
- if ('' != $this->owner)
- {
- if ($this->owner != $this->board[$to_check[$counter]][$to_check[$counter + 1]])
- {
- $this->owner = 'f';
- }
- }
- else
- {
- $this->owner = $this->board[$to_check[$counter]][$to_check[$counter + 1]];
- }
- $this->stones_visited .= strval((($to_check[$counter]) * 100) + $to_check[$counter + 1]) . ',';
- }
- }
- if ( ! strstr($this->visited, ',' . strval((($to_check[$counter]) * 100) + $to_check[$counter + 1]) . ','))
- {
- if ($this->is_freedom($to_check[$counter], $to_check[$counter + 1]))
- {
- ++$this->freedom;
- $to_visit_string .= strval((($to_check[$counter]) * 100) + $to_check[$counter + 1]) . ',';
- }
- }
- }
- ++$counter;
- }
- $this->visited .= strval(($y * 100) + $x) . ',';
- }
- # return array(
- # $owner ,
- # $freedom ,
- # );
- }
- // how many liberties does a group of stones have
- function freedom_of_group($y, $x)
- {
- $this->visited = ',';
- $this->freedoms_visited = ',';
- $to_visit_string = ',' . strval(($y * 100) + $x) . ',';
- $this->freedom = 0;
- while (strlen($to_visit_string) > 2)
- {
- $cord_to_visit = strtok(substr($to_visit_string, 1), ',');
- if (intval($cord_to_visit) >= 100)
- {
- $y = floor(intval($cord_to_visit) / 100);
- }
- else
- {
- $y = 0;
- }
- $x = intval($cord_to_visit) - ($y * 100);
- $to_visit_string = str_replace(',' . $cord_to_visit . ',', ',', $to_visit_string);
- $counter = 0;
- $to_check = $this->is_connected_to($y, $x);
- foreach ($to_check as $number => $coord)
- {
- if ($counter % 2 == 0)
- {
- if ( ! strstr($this->freedoms_visited, ',' . strval((($to_check[$counter]) * 100) + $to_check[$counter + 1]) . ','))
- {
- if ($this->is_freedom($to_check[$counter], $to_check[$counter + 1]))
- {
- ++$this->freedom;
- $this->freedoms_visited .= strval((($to_check[$counter]) * 100) + $to_check[$counter + 1]) . ',';
- }
- }
- if ( ! strstr($this->visited, ',' . strval((($to_check[$counter]) * 100) + $to_check[$counter + 1]) . ','))
- {
- if ($this->board[$to_check[$counter]][$to_check[$counter + 1]] == $this->color)
- {
- $to_visit_string .= strval((($to_check[$counter]) * 100) + $to_check[$counter + 1]) . ',';
- }
- }
- }
- ++$counter;
- }
- $this->visited .= strval(($y * 100) + $x) . ',';
- }
- return $this->freedom;
- }
- // creates an empty board to start with
- function create_empty_board( )
- {
- $this->board = array( );
- for ($y = 0; $y < $this->boardsize; ++$y)
- {
- for ($x = 0; $x < $this->boardsize; ++$x)
- {
- $this->board[$y][$x] = $this->insert_empty($y, $x);
- }
- }
- }
- function get_empty_board( )
- {
- // save the current board
- $temp_board = $this->get_board( );
- // create a new empty board
- $this->create_empty_board( );
- // save the new empty board
- $return_board = $this->board;
- // replace the original board
- $this->set_board($temp_board);
- // return the empty board to the script
- return $return_board;
- }
- function get_moved_stone_x( )
- {
- return $this->moved_stone_x;
- }
- function get_moved_stone_y( )
- {
- return $this->moved_stone_y;
- }
- } // end of iShudan class
- // other non-class but required functions
- // translate numeric coordinates to alphanumeric coordinates
- function xtoalt($xcord)
- {
- if ($xcord < 8)
- {
- return chr(65 + $xcord);
- }
- else
- {
- return chr(66 + $xcord);
- }
- }
- // translates alphanumeric coordinates to numeric coordinates
- function stringtocord($costring)
- {
- $color = substr($costring, 0, 1);
- $y = ord(substr($costring, 1, 1)) - 97;
- $x = ord(substr($costring, 2, 1)) - 97;
- return array(
- $color ,
- $y ,
- $x ,
- );
- }
- ?>