<?php
require 'expire.inc';
?>
<?php
class Level { 
	var $EMPTY = 1;
	var $TARGET = 2;
	var $BOX = 4;
	var $PLAYER = 8;

	var $width;
	var $height;
	var $working;

	# Current x-position of the player.
	var $playerX;

	# Current y-position of the player.
	var $playerY;

	# Start x-position of the player.
	var $playerXStart;

	# Start y-position of the player.
	var $playerYStart;

	# Number of boxes.
	var $boxCount;

	var $targetCount;

	function Level($data)
	{
		$this->width = $w + 2;
        $h = count($data);
		$this->height = $h + 2;
        $w = 0;
        for ($i = 0; $i < $h; $i++) {
            $l = strlen($data[$i]);
            if ($l > $w) $w = $l;
        }
        $this->width = $w + 2;
		$this->boxCount = 0;
		$this->targetCount = 0;
		for ($y = 0; $y < $this->height; $y++) {
			$row = 0;
			if ($y > 0 && $y < $this->height - 1) $row = $data[$y - 1];
			for ($x = 0; $x < $this->width; $x++) {
				$this->working[$x][$y] = 0;
				if ($row != 0 && $x > 0 && $x < $this->width - 1 && strlen($row) > $x - 1) {
					$b = substr($row, $x - 1, 1);
                    if ($b != ' ') {
						if ($b == '0') $b = 10; else $b = ord($b) - ord('0');
						if ($y != 0 && $y != $this->height - 1 && $x != 0 && $x != $this->width - 1 && $b != ' ') {
							$r = 0;
							if (($b & $this->EMPTY) > 0) $r |= $this->EMPTY;
							if (($b & $this->TARGET) > 0) {
								if (($b & $this->BOX) > 0) $this->targetCount++;
								$r |= $this->TARGET;
							}
							if (($b & $this->BOX) > 0) {
								$this->boxCount++;
								$r |= $this->BOX;
							}
							if (($b & $this->PLAYER) > 0) {
								$this->playerX = $x;
								$this->playerY = $y;
							}
							$this->working[$x][$y] = $r;
						}
					}
				}
			}
		}
	}
	
    function move($moves)
	{
        for ($i = 0; $i < strlen($moves); $i++) {
            switch (substr($moves, $i, 1)) {
                case 'l':
                    $dx = -1;
                    $dy = 0;
                    break;
                case 'r':
                    $dx = 1;
                    $dy = 0;
                    break;
                case 'u':
                    $dx = 0;
                    $dy = -1;
                    break;
                case 'd':
                    $dx = 0;
                    $dy = 1;
                    break;
                default:
                    return 0;
            }
		    $fromX = $this->playerX + $dx;
		    $fromY = $this->playerY + $dy;
            $b = $this->working[$fromX][$fromY];
            $move = 0;
		    if (($b & $this->BOX) == 0) {
			    if (($b & $this->EMPTY) > 0 || ($b & $this->TARGET) > 0)
			    {
				    # set the move flag
				    $move = 1;
			    }
		    } else {
			    $toX = $this->playerX + 2 * $dx;
			    $toY = $this->playerY + 2 * $dy;
			    $b = $this->working[$toX][$toY];
			    if ($b == $this->EMPTY || $b == $this->TARGET)
			    {
				    # move the box
				    $this->working[$fromX][$fromY] ^= $this->BOX;
				    $this->working[$toX][$toY] |= $this->BOX;
				    if (($this->working[$fromX][$fromY] & $this->TARGET) > 0) $this->targetCount--;
				    if (($this->working[$toX][$toY] & $this->TARGET) > 0) $this->targetCount++;

				    # set the move flag
				    $move = 1;
			    }
		    }
            if ($move == 1)
            {
                # move the player
                $this->playerX = $fromX;
                $this->playerY = $fromY;
            } else
            {
                return 0;
            }
        }
        return 1;
	}

	function isEnd()
	{
		return $this->targetCount == $this->boxCount;
	}

    function p()
    {
        for ($y = 0; $y < $this->height; $y++) {
            for ($x = 0; $x < $this->width; $x++) {
                print($this->working[$x][$y]);
            }
            print("<br>");
        }
    }
    
}

function saveName($level, $name)
{
    $highscoredb = dba_open("highscoredb", "c", "gdbm");
    if (dba_exists($level, $highscoredb)) {
        dba_replace($level, $name, $highscoredb);
    } else {
        dba_insert($level, $name, $highscoredb);
    }
    dba_close($highscoredb);
}

function saveMoveCount($level, $moveCount)
{
    $movecountdb = dba_open("movecountdb", "c", "gdbm");
    if (dba_exists($level, $movecountdb)) {
        dba_replace($level, $moveCount, $movecountdb);
    } else {
        dba_insert($level, $moveCount, $movecountdb);
    }
    dba_close($movecountdb);
}

$name = $HTTP_GET_VARS['name'];
$level = $HTTP_GET_VARS['level'];
$moves = $HTTP_GET_VARS['moves'];

# zu prüfenden Level laden
$level++;
$leveldb = dba_open("leveldb", "r", "gdbm");
$d = dba_fetch($level, $leveldb);
dba_close($leveldb);
$l = new Level(split("/", $d));

# prüfen, ob alle Züge möglich sind
$invalid = 1;
if ($l->move($moves)) {
    # prüfen, ob der Level gelöst wurde
    if ($l->isEnd()) {
        $solutiondb = dba_open("solutiondb", "c", "gdbm");
        if (dba_exists($level, $solutiondb)) {
            $solution = dba_fetch($level, $solutiondb);
            # nur wenn keine bessere Lösung gespeichert ist
            if (strlen($solution) > strlen($moves) || strlen($solution) == 0) {
                dba_replace($level, $moves, $solutiondb);
                saveName($level, $name);
                saveMoveCount($level, strlen($moves));
                $invalid = 0;
            }
        } else {
            dba_insert($level, $moves, $solutiondb);
            saveName($level, $name);
            saveMoveCount($level, strlen($moves));
            $invalid = 0;
        }
        dba_close($solutiondb);
    }
}

# Ausgabe der Prüfungen
print("save.php result: ");
if ($invalid) {
    print("invalid");
} else {
    print("ok");
}
?>

