Ultimate Tic-Tac-Toe Challenge

Это моя попытка выполнить Окончательный вызов кода Tic-Tac-Toe .

Он использует jQuery для построения сетки игр и поиска состояний всех «кнопок» (фактически <div> s) при расчете независимо от того, выиграл ли кто-то отдельную доску или всю игру.

Эта версия следует за рекомендацией, что заполненная доска, которая является ничейкой, не учитывается ни для одного из игроков.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
    <meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
    <title>Ultimate Tic-Tac-Toe</title>
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.0.min.js"> </script>
    <style type="text/css">
        body { text-align: center; }
        div { display: inline-block; }
        .grid { padding: 5px; border: solid 1px #300; }
        .current-grid { background-color: #ff0; }
        .button { background-color: #eee; width: 25px; height: 25px; margin: 5px;
                  text-align: center; vertical-align: middle; font-size: 25px; }
        .X-won { background-color: #cfc; }
        .O-won { background-color: #cdf; }
        .no-win { background-color: #ccc; }
        .X-selected { color: #080; }
        .O-selected { color: #008; }
        #game { position: absolute; left: 0px; right: 0px; }
    </style>
    <script type="text/javascript">
<!--
        var isXTurn = true;
        var currentGrid = -1;

        $(function() {
            $('body').append('<div id="game"></div>');
            for (var i = 0; i < 9; i++) {
                $('#game').append('<div class="grid" id="grid' + i + '"></div>');
                if (i % 3 == 2) {
                    $('#game').append('<br />');
                }
                for (var j = 0; j < 9; j++) {
                    $('#grid' + i).append('<div class="button" id="button' + i + '-' + j + '"></div>');
                    if (j % 3 == 2) {
                        $('#grid' + i).append('<br />');
                    }
                }
            }
            $('.button').click(function() {
                var parent = $(this).parent();
                var me = isXTurn ? 'X' : 'O';

                if ($(this).is('.X-selected, .O-selected') || parent.is('.X-won, .O-won') ||
                    (currentGrid >= 0 && parent.attr('id') != 'grid' + currentGrid)) {
                    return;
                }
                $(this).addClass(me + '-selected').html(me);
                if (checkForWin($(this), ('.' + me + '-selected'))) {
                    parent.addClass(me + '-won');
                    if (checkForWin(parent, ('.' + me + '-won'))) {
                        window.alert(me + ' won!');
                        resetGame();
                        return;
                    }
                    else if ($('.grid.X-won, .grid.O-won, .grid.no-win').length == 9) {
                        window.alert('The game is a draw!');
                        resetGame();
                        return;
                    }
                }
                else if (parent.children('.X-selected, .O-selected').length == 9) {
                    parent.addClass('no-win');
                }
                currentGrid = +($(this).attr('id').slice(-1));
                $('.grid').removeClass('current-grid');
                if ($('#grid' + currentGrid).is('.X-won, .O-won, .no-win')) {
                    currentGrid = -1;
                }
                else {
                    $('#grid' + currentGrid).addClass('current-grid');
                }
                isXTurn = !isXTurn;
            });

            function checkForWin(elem, match) {
                var index = +(elem.attr('id').slice(-1));
                var prefix = '#' + (elem.hasClass('button') ? elem.attr('id').slice(0, 8) : 'grid');
                // Check rows
                if (elem.nextUntil('br').add(elem.prevUntil('br')).filter(match).length == 2) {
                    return true;
                }
                // Check columns
                if ($(prefix + (index % 3)).add($(prefix + (index % 3 + 3))).add($(prefix + (index % 3 + 6))).filter(match).length == 3) {
                    return true;
                }
                // Check diagonals
                if ($(prefix + 0).add($(prefix + 4)).add($(prefix + 8)).filter(match).length == 3) {
                    return true;
                }
                if ($(prefix + 2).add($(prefix + 4)).add($(prefix + 6)).filter(match).length == 3) {
                    return true;
                }
                return false;
            }
        });

        function resetGame() {
            isXTurn = true;
            currentGrid = -1;
            $('div').removeClass('X-won O-won no-win current-grid X-selected O-selected');
            $('.button').html('');
        }
//-->
    </script>
</head>
<body>
    <h1>Ultimate Tic-Tac-Toe!</h1>
    <p><a href="#" onclick="resetGame()">Restart</a></p>
</body>
</html>

Он также передает валидаторы W3C для HTML и CSS, что является бонусом, теплым нечетким.

11 голосов | спросил Cameron 6 FebruaryEurope/MoscowbThu, 06 Feb 2014 10:03:52 +0400000000amThu, 06 Feb 2014 10:03:52 +040014 2014, 10:03:52

3 ответа


10
  • Вы создаете несколько элементов DOM с jQuery, и это нормально. Однако вместо неприятных строк, таких как:

       $('#game').append('<div class="grid" id="grid' + i + '"></div>');
    

    Рассмотрите возможность создания элементов и изменения атрибутов с помощью функций jQuery, а затем добавьте их в на игровое поле.

    $('<div id="grid>')
      .addClass('grid' + i)
      .appendTo('#game');
    

    Я считаю, что это почти всегда более разборчиво и понятнее, когда вы используете appendTo, а не append

  • Вы повторно используете несколько селекторов jQuery. Всегда лучше хранить элементы, чем искать их из DOM каждый раз. var $game = $('#game');

  • Ваша функция возврата включает этот драгоценный камень: $('div'). Это один из худших селекторов! Он выберет каждый div на странице! Поскольку вы только хотите выбрать те, которые есть в вашей игре, используйте селектор с контекстом: $('div', $game). Или еще лучше, используйте класс.

ответил Jivings 6 FebruaryEurope/MoscowbThu, 06 Feb 2014 23:12:17 +0400000000pmThu, 06 Feb 2014 23:12:17 +040014 2014, 23:12:17
10

От одного раза:

  • Я бы использовал теги HTML 5, они были более чистыми и более подходящими:
    <!DOCTYPE html>
    <html>
    Ваш код отлично проверяется как HTML5
  • Настройка пользовательского интерфейса, вероятно, заслуживает собственной функции.
  • В вашем обработчике click отсутствует разделение проблем (точнее логика и пользовательский интерфейс), также вы используете пользовательский интерфейс как ваш модель данных, которая является iffy.
  • Мне нравится, как короткий resetGame есть
  • Многие цифры жестко закодированы, вы, кажется, , поэтому , чтобы сделать любое количество плат, если вы еще раз отполируете этот код, я бы предложил вам изучить, что

Для удовольствия я сделал это на jsbin: http://jsbin.com/rohe/3

ответил konijn 6 FebruaryEurope/MoscowbThu, 06 Feb 2014 17:47:53 +0400000000pmThu, 06 Feb 2014 17:47:53 +040014 2014, 17:47:53
6

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

Прикрепление обработчика событий к каждому элементу кнопки очень неэффективно (и довольно распространенная ошибка, допущенная программистами jQuery). Вместо этого вы должны использовать делегирование событий. Единственный обработчик событий, прикрепленный к самой плате, - это все, что вам нужно, чтобы захватывать события на элементах-потомках.

Использование JavaScript для создания разметки неэффективно: чем больше вы можете генерировать фронт, тем лучше. Если бы ваше намерение не позволяло пользователям решать, сколько плиток должно иметь плата ...

Подтверждение HTML довольно легко сделать, когда ваша страница практически не имеет разметки. Семантически говоря, сформированная доска довольно бедна. Нет причин когда-либо использовать <br /> между элементами уровня блока. Если вам нужно принудительно обернуть (потому что вы сделали их inline-bock), измените ширину родительского элемента.

ответил cimmanon 6 FebruaryEurope/MoscowbThu, 06 Feb 2014 19:19:47 +0400000000pmThu, 06 Feb 2014 19:19:47 +040014 2014, 19:19:47

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132