Новости из Блогов Генерируем Сапера на PHP

Discussion in 'Мировые новости. Обсуждения.' started by d3l3t3, 8 Apr 2012.

  1. d3l3t3

    d3l3t3 Banned

    Joined:
    3 Dec 2010
    Messages:
    1,771
    Likes Received:
    98
    Reputations:
    10
    Генерируем Сапера на PHP


    Всем привет. Вчера было нечем заняться и в голову пришла идея — почему бы не написать генератор поля для игры в сапер? (мысль может показаться ненормальной, просто люблю генерировать что нибудь, будь это поле для игры, или что-нибудь другое).

    Также было поставлено четкое условие – I will not use Google. Я уверен что все дописано до меня, но это писалось для саморазвития, а не для продакшена. Спустя 20 минут первый сапер был сгенерирован, еще спустя 20 — был оформлен, с возможностью настройки поля.

    Результат генерации стандартного поля (9х9, 10 мин):

    [​IMG]

    Исправив первые 3 строчки скрипта, можно генерировать поля любого размера.

    Прокомментировал код, чтобы было хоть что-то понятно. Но так как статья из одного кода – не статья, то один кусок, а точнее самый сложный момент — поиск мин вокруг клетки — я вынес на объяснение сюда.

    Если вам понятно, что скрывается за строками:

    Code:
            if ($minefield[$x - 1][$y - 1] === 'X')
                $mCounter++;
            if ($minefield[$x][$y - 1] === 'X')
                $mCounter++;
            if ($minefield[$x + 1][$y - 1] === 'X')
                $mCounter++;
     
            if ($minefield[$x - 1][$y] === 'X')
                $mCounter++;
            if ($minefield[$x + 1][$y] === 'X')
                $mCounter++;        
     
            if ($minefield[$x - 1][$y + 1] === 'X')
                $mCounter++;
            if ($minefield[$x][$y + 1] === 'X')
                $mCounter++;
            if ($minefield[$x + 1][$y + 1] === 'X')
                $mCounter++;
    , то дальше можете не читать, я думаю вы без труда сделали бы такой же скрипт.

    Для тех кто не понял — объясню.
    Все поле у нас выполнено в виде матрицы, каждая клетка имеет свои координаты $x и $y. $x — ордината (длина), $y — ось (высота).
    Нам необходимо определить, сколько мин находится вокруг клетки, чтобы поставить это число в текущую клетку.
    Каждый раз мы проверяем клетку [$x, $y]. Как определить что находится в клетке справа снизу? Все это можно сделать с помощью манипуляций над $x и $y. Для большей наглядности, вставлю картинку:

    [​IMG]

    По этой табличке сразу видно, что правый нижний угол это [$x+1, $y+1]. А теперь посмотрите на кусок кода выше, я думаю все стало понятно. Если все-таки нет, и очень хочется разобраться — можете написать мне в личку.

    Ну и то, для чего все сюда пришли: полный код.

    Code:
    <?php
    // Minesweeper by bafoed
    // http://bafoed.net
     
    $mines = 10; // количество мин на поле
    $fx    = 9;  // ширина поля (в клетках)
    $fy    = 9;  // высота поля (в клетках)
     
    ####
    // заполнение начального поля нулями
    for ($y = 1; $y <= $fy; $y++) {
        for ($x = 1; $x <= $fx; $x++) {
            $minefield[$x][$y] = '0';
        }
    }
    // заполнение поля минами
    for ($i = 0; $i < $mines; $i++) {
        $randx = rand(1, $fx);  // генерируем случайные координаты
        $randy = rand(1, $fy);  // 
     
        if ($minefield[$randx][$randy] == 'X') { // координаты совпали и мина уже есть
            $i--; // тогда не ставим мину, а скажем попробовать лишний раз 
        } else {
            $minefield[$randx][$randy] = 'X'; // ставим мину
        }
    }
     
    echo <<<HEAD
    <DOCTYPE !html>
    <html>
    <head>
        <title>Minesweeper ($fx x $fy) by bafoed</title>
        <style type="text/css">
        table,tr {
            background: #C4C4C4;
            border: 1px solid #808080;
            border-collapse: collapse; 
            font-weight: bold;
            font-size: 14px;
            text-align: center;
        } 
     
        td {
            border: 1px solid #808080;
            padding: 0.5px;
            width:16px;
            height:16px;
        }
     
        .i1 {
            color: #0000ff;
        }
     
        .i2 {
            color: #1D751F;
        }
     
        .i3 {
            color: #ff0000;
        }
     
        .i4 {
            color: #0D0485;
        }
     
        .i5 {
            color: #520E0F;
        }
     
        .i6 {
            color: #0F877E;
        }
        </style>
    </head>
     
    <body>
    HEAD;
     
    echo '<pre><tt>
    <table>
    ';
    for ($y = 1; $y <= $fy; $y++) {
        echo '<tr>
        ';
        for ($x = 1; $x <= $fx; $x++) {
            echo '<td>';
            $mCounter = 0; // счетчик мин для клетки
     
            if ($minefield[$x][$y] == 'X') { // если текущая клетка -- мина
                echo '<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAA7EAAAOxAGVKw4bAAABUElEQVR42pWSS26CUBRAH6ho0jqijBpHdkhIjCtgDXbGzI7ZBVOURPegMagYmZAwFZdh0iWwgfb0vYZQYNKbYO7n3J/vivP5nCTJ4XA4Ho+JFJSVlLoHAAVYXC4X7DzP0zRF2e12RVG8SkHBxEkIQOULUjF8399ut1mW3W63IAiepKBg4iQEABbHseC7Xq+bzcZ13fV6PZ/Px+OxrutCiNFoNJvNcBICADudTkKNSJkoikBFS3ASAvgdiY9Bae04DuHp29TzvMX7QjXp9/v82rYNAPaTQN79fmdcy7KILT+WX1IMw1Ader2eaZoAYMAiDMPJZKIqIdQuy/Lx+RgMBvXBAMD2+/2fBE3TmGQ4HFblOxKqkehL9/bSzZGqpdms2rJeuLn0v//WxsPxUryXQrsfrvM0nqV0n0b7+FjuRQpKx/Gp88agXf2Y6wdPSOnA3/AoQ71G5naTAAAAAElFTkSuQmCC" /></td>
            '; // выведем и перейдем на следущую клетку
                continue;
            }
            // тут магия, ищем мины вокруг клетки
    		// распишу в статье
            if ($minefield[$x - 1][$y - 1] === 'X')
                $mCounter++;
            if ($minefield[$x][$y - 1] === 'X')
                $mCounter++;
            if ($minefield[$x + 1][$y - 1] === 'X')
                $mCounter++;
     
            if ($minefield[$x - 1][$y] === 'X')
                $mCounter++;
            if ($minefield[$x + 1][$y] === 'X')
                $mCounter++;        
     
            if ($minefield[$x - 1][$y + 1] === 'X')
                $mCounter++;
            if ($minefield[$x][$y + 1] === 'X')
                $mCounter++;
            if ($minefield[$x + 1][$y + 1] === 'X')
                $mCounter++;
     
    		// если нет мин вокруг глетки -- выводим пустую, а не с цифрой 0
            $minefield[$x][$y] = ($mCounter == 0) ? '&nbsp;&nbsp;' : $mCounter;
     
    		// выводим клетку с классом
            echo '<span class="i' . $mCounter . '">' . $minefield[$x][$y] . '</span></td>
            ';
        }
        echo '</tr>
        ';
    }
    echo '</table></tt></pre >
    </body>
    </html>'; 
    ?>
    

    bafoed.net
    http://bafoed.net/blog/post2126