#!/usr/bin/php -q
<?php

/*
 *  Server kontroluje:
 *    pocet konekci na server
 *    duplicitu jmen hracu
 *    pripustnost tahu
 *    kdo je na tahu
 *    spotrebovany cas
 */

// Jeste to davkovy spousteni

ini_set(register_globals"1");

set_time_limit(0);

global 
$game_state$pile$part$player$client$first$turn$time_start$time_stop$think_time;
$player = array();
$think_time = array();

// Konfigurace serveru

define('MAXLINE'1024);        // kolik se toho precte ze socketu
define('LISTENQ'10);          // listening queue...
define('PORT'9000);          // standardni port
define('FD_SETSIZE'2);        // maximum pripojenych hracu
                // 2 hraci + jeden spectacor (resp. monitoring vsech her pres sit) -> spectacora casem
$min_pile =  500;
$max_pile 1000;


##################################################
##################################################
##################################################

function addplayer($addp)
{
    global 
$player$think_time$client$game_state$first$turn;

    
$nop sizeof($player);
#    if ((sizeof($player) < FD_SETSIZE) AND (!in_array($addp, $player))){
      
if ((sizeof($player) < FD_SETSIZE)){
      
$player[$nop] = $addp;
      
$think_time[$nop] = 60;
      print 
"Player $nop has been registered.\n";
    }
    else{
      print 
"Server full or name already used.\n";
    }
    if (
sizeof($player) == FD_SETSIZE){
      print 
"\nPlayers:\n\n";
      for (
$i=0$i<sizeof($player); $i++){
        print 
"Player[$i]: $player[$i]\n";
      }

      
// Mame vsechny hrace, tak poslem prvnimu pokyn k zahajeni hry
      // Prvni hru vzdycky zacina hrac 0 pro jednoduchost.
      
$msg "ACCEPT $game_state[0]\n";
      for (
$i 0$i FD_SETSIZE$i++)
      {
        if (
$client[$i] != null)
        {
          
socket_write($client[$i], $msgstrlen($msg));
        }
      }

      
// Prvni hrac muze zacit:
      
$first 0;
      
socket_write($client[0], "PLAY\r\n");
      
start_timer(0);
    }
}

##################################################

// Mereni casu premysleni

function start_timer($player_t)
{
    global 
$time_start;

    
$tmp        substr(microtime(),0,8);
    
$time_start time()+$tmp;
}

function 
stop_timer($player_t)
{
    global 
$think_time$time_start$time_stop;

    
$tmp       substr(microtime(),0,8);
    
$time_stop time()+$tmp;
    
$think_time[$player_t] = $think_time[$player_t]-($time_stop-$time_start);
    if (
$think_time[$player_t] <= 0){
      
$msg "YOU LOST\n";
      
socket_write($client[$player_t], $msgstrlen($msg));
      if (
$player_t == 0){
        
$msg "YOU WON\n";
        
socket_write($client[1], $msgstrlen($msg));
      }
      if (
$player_t == 1){
        
$msg "YOU WON\n";
        
socket_write($client[0], $msgstrlen($msg));
      }
    }
}

##################################################

// Generovani pocatecniho stavu hry

function gen_state($min$max)
{
global 
$game_state;
$cislo rand($min$max);
$game_state = array($cislo);
print 
"Game state: $game_state[0] sticks.\n\n";
#return $game_state;

}

##################################################

// Kontrola pripustnosti tahu a odeslani druhemu hraci.

function check_move($from_player$pile$part)
{

global 
$game_state$client$player$think_time;

$position array_search($pile$game_state);

if (((
$pile $part) != $part) AND ($pile >= 3) AND ($pile $part)){

  if (
in_array($pile$game_state)){

    
stop_timer($from_player);

    
$msg "MOVE $pile $part\n";

    if (
$from_player == 0){
      
socket_write($client[1], $msgstrlen($msg));
      
start_timer(1);
    }
    if (
$from_player == 1){
      
socket_write($client[0], $msgstrlen($msg));
      
start_timer(0);
    }

  }
  else{
    print 
"Wrong move, pile of this cardinality not found on the table.\n";
  }

  unset (
$game_state[$position]);
  
array_push($game_state, ($pile-$part), $part);

  print 
"Player[$from_player] ($player[$from_player]), PILE: $pile, PART:$part, Time: $think_time[$from_player]\n";
  
rsort($game_state);
}
else{
  print 
"Player[$from_player] ($player[$from_player]): Wrong move!\n";
  
$msg "WRONG MOVE\n";
  
socket_write($client[$from_player], $msgstrlen($msg));
}

}

##################################################

// Shutdown daemona

function killDaemon()
{
    global 
$listenfd$client;


    
// Asi by to chtelo funkci na broadcast zpravy vsem klientum a pak spec. pro jednoho, 
    // ale to pocka...

    
socket_close($listenfd);
    
$msg "Daemon going down!\n";
    for (
$i 0$i FD_SETSIZE$i++)
    {
        if (
$client[$i] != null)
        {
            
socket_write($client[$i], $msgstrlen($msg));
            
socket_close($client[$i]);
        }
    }

    print 
"Shutting down the daemon...\n";
    exit;
}

##################################################

// "Cistka" pri odpojeni klienta...

function closeClient($i)
{
    global 
$client$remote_host$remote_port;

    print 
"Closing client[$i] ({$remote_host[$i]}:{$remote_port[$i]})\n";

    
socket_close($client[$i]);
    
$client[$i] = null;
    unset(
$remote_host[$i]);
    unset(
$remote_port[$i]);
}

##################################################
##################################################
##################################################


print "NimCup server v0.1 - Cybernetics And Artificial Intelligence\n\nJosef Stach <stach@proof.cz>\n\n";

$listenfd socket_create(AF_INETSOCK_DGRAM0);
if (
$listenfd)
    print 
"Listening on port " PORT "\n";
else
    die(
"Shit -- socket died!\n");

socket_setopt($listenfdSOL_SOCKETSO_REUSEADDR1);
if (!
socket_bind($listenfd"0.0.0.0"PORT))
{
    
socket_close($listenfd);
    die(
"Ooops -- Couldn't bind!\n");
}
socket_listen($listenfdLISTENQ);

$maxi = -1;
for (
$i 0$i FD_SETSIZE$i++)
    
$client[$i] = null;


gen_state($min_pile$max_pile);

// Hlavni smycka, porad dokola posloucham...

while(1)
{
    
$rfds[0] = $listenfd;

    for (
$i 0$i FD_SETSIZE$i++)
    {
        if (
$client[$i] != null)
            
$rfds[$i 1] = $client[$i];
    }


    
$nready socket_select($rfds$null$nullnull);


    if (
in_array($listenfd$rfds))
    {
        for (
$i 0$i FD_SETSIZE$i++)
        {
            if (
$client[$i] == null)
            {
                
$client[$i] = socket_accept($listenfd);
                
socket_setopt($client[$i], SOL_SOCKETSO_REUSEADDR1);
                
socket_getpeername($client[$i], $remote_host[$i], $remote_port[$i]);
                print 
"Accepted {$remote_host[$i]}:{$remote_port[$i]} as player[$i].\n";
                break;
            }

            if (
$i == FD_SETSIZE 1)
            {
                
trigger_error("Too many clients!"E_USER_ERROR);
                exit;
            }
        }
        if (
$i $maxi)
            
$maxi $i;

        if (--
$nready <= 0)
            continue;
    }

    
// Neposilaj klienti neco?

    
for ($i 0$i <= $maxi$i++)
    {
        if (
$client[$i] == null)
            continue;

        if (
in_array($client[$i], $rfds))
        {
            
$n trim(socket_read($client[$i], MAXLINE));

            if (!
$n)
                
closeClient($i);
            else
            {
                
// Klient neco posila, tak se na to mrknem...

        
$exn explode(" ",$n);
        
// V $exn[0] je prikaz

                
if ($exn[0] == "/KILL")
                    
killDaemon();
                elseif (
$exn[0] == "/QUIT")
                    
closeClient($i);
        elseif (
$exn[0] == "INIT")
            
addplayer($exn[1]);
        elseif (
$exn[0] == "/STATE"){
                    
print_r(array_values($game_state));
        }
        elseif (
$exn[0] == "MOVE"){
            if (
check_move($i$exn[1], $exn[2]))
            {
                
send_move($exn[1], $exn[2]);
            }
        }
                else
                {
                    
// Neco vypisem na konzoli, neco se posle klientum, neco se loguje....

                    
print "From {$remote_host[$i]}:{$remote_port[$i]}, client[$i] ($player[$i]): $n\n";
                    for (
$j 0$j <= $maxi$j++)
                    {
                        if (
$client[$j] != null)
                            
socket_write($client[$j], "From player[$i] ($player[$i]): $n\r\n");
                    }
                }
            }

            if  (--
$nready <= 0)
                break;
        }
    }
}

?>