Sudoku
The script can also be downloaded from GitHub: https://github.com/DHTMLGoodies/SudokuJS.
License
- Script and PHP code: Apache Free License 2.0
- Sudoku Puzzles: Apache License 2.0 for 80 free puzzles,
Commercial license(USD99) for 1600 puzzles.
Purchase commercial License
Price: USD99 (The rights to use the 1600 Sudoku Puzzles in the puzzles folder)
Demo
Restart Try another
The dimension(width and height) of the board is dynamic, based on the CSS dimension specified for the
Usage
Take a look at index.html in the zip file, and use it as a template when implementing the Sudoku Script.
Toggle between commercial and non-commercial use
If you have purchased a commercial license, enable it in sudoku-controller.php with this line: Example: $sudokuReader->useCommercial(); When enabled, the script will pick from the 1600 Sudoku Puzzles available in the puzzles folder. Otherwise it will fetch puzzles from the puzzles-free folder(80 puzzles, 10 for each difficulty).
Comments
Hi: I become interested in your software and I have the next questions: 1.- Can I install in a server? 2.- Is there a procedure for install? I use the index.html ans only appears the grid. 3.- Is there any discount in the price? 4.- Do you have a webpage? That´s all for the moment. I´ll wait for your answers. Regards.
Evaristo Romero Dominguez at 04:28AM, 2015/11/02.
Evaristo,Yes, this is a downloadable script which you can put on your server. There’s a download link at the top of the page. It can also be downloaded from GitHub https://github.com/DHTMLGoodies/SudokuJSTo use the script on your website, your server needs to support the PHP language. The install instruction is simply to copy the files to your web server. You cannot use this script using the file system, example: by opening a page from your local computer in your web browser. The address bar in your web browser will typical start with file:: if this is the case. You need to run it from a web server, i.e. with an address starting with http:/.A blank grid/board means that Sudoku’s are not loaded correctly from the server. It’s difficult to know for sure what’s wrong without seeing it live on your site. If you provide a link, I will probably be able to tell you more. But make sure that* Your web server supports the PHP language* The web address in your web browser(Chrome, Firefox etc) starts with http://
DHTMLGoodies at 08:23PM, 2015/11/07.
Are all these sudoku’s testen so that they only have 1 solution?
And that there is no guess work needed?
Kind regards
Roel
Roel at 08:50AM, 2019/05/22.
https://irongamers.ru/sale/key/2733826
JSorry at 02:29PM, 2021/06/19.
Авторитетное сообщение 🙂 , познавательно.
——
[url=https://global-smm.com/]как сделать ссылку в вк на инстаграм[/url]
Авторитетное сообщение 🙂 , любопытно.
——
[url=https://kriodetal.ru/zapchasti-k-vru/ehkspander-kk-2326-01-003.html]Экспандер КК 2326.01.003[/url]
Авторитетное сообщение 🙂 , заманчиво.
——
[url=https://top-sirop74.ru/siropy/]сироп для молочных коктейлей купить[/url]
А есть похожий аналог?
——
[url=https://mosgor-balkon.ru/price/finishing/]отделка лоджий цена в москве[/url]
А что-нибудь аналогичное есть?
Есть что-нибудь похожее?
Есть что-нибудь аналогичное?
Интересно, а аналог есть?
Любопытно, а аналог есть?
Генератор судоку на JavaScript (13 строчек)
После наплыва постов про реализацию различных игрушек на JavaScript в 30 строчек, решил тоже внести свой вклад в общее дело «30 строчек». Решил немного отойти от игр и реализовать генерацию судоку на JavaScript, но не уложился в 30 строчек. Надеюсь, что это маленькое недоразумение, не омрачит великое соревнование 30 строчек. Раньше доводилось писать скрипты для Corel Draw, которые генерировали 9 судоку на лист и создавали целый журнал. Оставалось только печатать и раздавать всем желающим.
- генерация судоку случайным образом
- ввод чисел (с проверкой на ввод числа) в пустые ячейки
- 13 строчек с учетом html и css
Принцип работы
Для генерации судоку используется подготовленны шаблон, который хранится в виде строки. Раньше я использовал несколько шаблонов, но для данного случая вполне сгодится и один. Немного странным образом организую перемешивание массива с цифрами от 1 до 9. Этот массив потребуется для замены цифр в шаблоне. Далее начинаем формировать таблицу. Используя шаблон и массив для замены цифр формируем ячейки, не забывая создавать текстовые поля для ввода.
Код
Код можно было еще ужать и объединить некоторые строки, но мне кажется такой вариант более удобный для восприятия.
Сам код
#sudoku td #sudoku .l #sudoku input
Генератор судоку на JavaScript (6 строк)
На этой недели Хабрахабр будоражили различные поделки в 30 строчек на JavaScript. Чего только не было. Выкладывали гонки, аркады, космические стрелялки, змейки, тетрис, пианино и многое другое. И если сказать честно, то продолжаю публиковать в песочницу до сих пор. Я слишком поздно предложил свою поделку и она не попала в список тех, которые увидят многие. Может оно и к лучшему, т.к. я смог еще лучше оптимизировать код.
Особенностью реализации является:
- небольшой код (6 строк)
- 2 строчки HTML-кода
- 2 строчки CSS
- возможность разгадывать судоку вводя цифры в свободные поля
- реализована проверка вводимых данных и фильтрация разрешающая вносить только цифры
Выглядит это вот так:

Пример работы скрипта «Генератор судоку на JavaScript (6 строк)»
Генерация основывается на задействовании уже составленного шаблона и замещении его элемента случайными числами. Шаблон задаеся так:
var field = ‘0681594327597283416342671589934157268278936145156842973729318654813465792465729831’;
Ноль в начале шаблона необходим специально для удобства. Кто не поймет зачем это нужно, может задать вопрос в комментариях ниже.
Числа для замещения хранятся в массиве, который формируется следующим образом:
var arr = Array(1,2,3,4,5,6,7,8,9).sort(function()
К сожалению в javaScript нет php функции и поэтому пришлось реализовать перемешивание подобным образом. Можно было использовать другой вариант, тогда случайность была бы более случайной (См. javascript shuffle array). Но для данного примера решил ограничиться такой реализацией.
Случайным образом формирую строку для вывода используя за основу известную цифру или ячейку для ввода.
var st = (Math.random()*10>6) ? ‘
‘ : ‘
Приведу весь код целиком:
#sudoku td
#sudoku input
А вот и рабочий вариант: судоку
Если возникнут вопросы, то с удовольствием отвечу на них в комментариях.
Разработка Судоку

Разработка — создание программного продукта с помощью информационных технологий (IT). В современном мире востребованы разные направления разработки: разработка систем искусственного интеллекта (AI), разработка виртуальной реальности (VR), разработка дополненной реальности (AR), разработка игр (Game Dev), разработка мобильных приложений для Android и iOS (Mobile), разработка веб-приложений для сайтов (Web)… Но начинающим джунам (от англ. Junior), мечтающим связать свою жизнь с высокими технологиями и стать успешными разрабами, прежде чем осваивать полюбившийся многим Python, резонно постичь основы веб-программирования, заложив прочный фундамент технического бэкграунда. Поскольку веб-направление относительно легко освоить, и при этом не нужно искать и устанавливать дополнительное программное обеспечение (ПО). Достаточно наличия простенького компьютера с браузером в операционной системе! Для успешного взаимодействия с кодом разработчикам полезно прокачивать память, логику и образное мышление. Осуществлять это можно посредством регулярной практики кодинга (написания кода), решения логических задач, участия в развивающих играх, проведения мыслительных экспериментов, знакомства с кейсами опытных разработчиков, чтения тематической литературы, просмотра образовательных видеоматериалов, прохождения курсов повышения квалификации и других способов саморазвития… Как говорят мудрецы: «Проживайте дни так, словно завтра вам умирать, стараясь успеть сделать как можно больше! Учитесь так, словно вы собираетесь жить вечно, стараясь познать себя и окружающий мир как можно лучше!» Незнакомые языки программирования эффективней всего изучать на конкретных примерах, стараясь сразу реализовывать на практике приобретённые теоритические знания и оттачивать своё мастерство (подобно филигранному преобразованию алмаза в огранённый бриллиант). В психологии существует теория о том, что информация наилучшим образом воспринимается и запоминается мозгом в моменты, когда испытываются сильные эмоции. И игровые примеры, как потенциальный источник ярких впечатлений, можно считать весьма эффективным обучающим инструментом. Таким образом, чтобы знакомство с особенностями веб-разработки не было утомительно скучным, прокачивать мозг, осваивая новый скилл, резонно именно в игровой форме! К тому же, в разработанную собственными силами игру потом можно будет поиграть! В качестве такого наглядного игрового примера можно использовать Судоку — популярную японскую игру-головоломку, способствующую формированию внимательности, развитию логического мышления и тренировке памяти у детей и взрослых людей! Программирование, по своей сути, является процессом записи идей с помощью специальных служебных слов выбранных языков программирования. Освоить синтаксис незнакомых языков возможно за несколько недель, причём некоторые отличительные особенности построения служебных конструкций могут запомниться после просмотра первого же примера с кодом! В частности, это касается особенностей использования цикла for и условного оператора if, с помощью которых можно реализовывать множество разных задумок. Но при этом важно чётко представлять в голове архитектуру будущего программного продукта и научиться придумывать эффективные алгоритмы (определённые последовательности действий, приводимые к желаемому результату), которые должны быть реализованы средствами языков программирования. Например, для реализации игровой логики Судоку как минимум понадобятся пользовательский интерфейс, обработчики событий для взаимодействия с пользователем и переменные для хранения массива данных.
Мысленные эксперименты
- Вначале М должен перевезти на другой берег козу (тогда на первом берегу останутся капуста и волк, равнодушный к вегетарианству).
- После этого М должен вернуться один к исходному (первому) берегу.
- Затем М должен перевезти на другой берег волка.
- М должен вынужденно вернуться с козой на первый берег (чтобы волк не съел козу).
- Далее М должен перевезти на другой берег капусту.
- М должен вернуться на первый берег за козой (оставив на другом берегу волка с капустой).
- М должен перевезти на другой берег козу.
- Успешно преодолев препятствие благодаря пониманию основ алгоритмизации, М должен продолжить путь на конкурс!
В данном случае очерёдность 3 и 5 пунктов не имеет значения (М может перевезти вместо волка капусту, тем не менее, после этого М всё равно придётся вернуться с козой, чтобы она не съела капусту, а затем М придётся перевезти волка). Но остальные пункты должны выполняться строго в указанном порядке. Подобные задачи можно использовать в качестве тренинга для развития мышления.
Также помимо умения придумывать и реализовывать эффективные алгоритмы программисту важно знать технический английский язык. Поскольку служебные слова, используемые в языках программирования, как правило, имеют английское написание. Убедиться в этом можно на примере синтаксиса гармонично дополняющего друг друга трио: HTML, JavaScript и CSS!
HTML (HyperText Markup Language)
HTML — язык разметки гипертекста, с помощью которого можно создавать специальные инструкции для обработки контента веб-документов. В рамках разработки собственного веб-приложения в первую очередь резонно создать на компьютере отдельную тематическую папку с символическим именем GameDev. Внутри папки следует создать пустой текстовый документ с именем sudoku и расширением .html (для установки расширения файла может потребоваться изменить настройки операционной системы, указав, чтобы в папках отображались расширения для зарегистрированных типов файлов). Затем необходимо открыть файл с помощью встроенного в операционную систему текстового редактора. И скопипастить (от англ. Copy+Paste) код из листинга-1.
Листинг-1. Структура HTML-документа
Титульное название страницы Заголовок первого уровня
Блок информации (дивизион), где может содержаться самостоятельный контент или сгруппированные секции с разным контентом, например:Заголовки второго уровня
Списки, нумерованные буквами
римскими числами
или арабскими числами
Списки с маркером-кругом
маркером-окружностью
или маркером-квадратом
Таблицы с одной двумя или большим числом ячеек Заголовки третьего уровня
Абзацы (параграфы) с текстовым контентом, включая жирный, курсивный или подчёркнутый текст
Ссылки и прочие объекты…
После этого следует сохранить файл (например, в кодировке UTF-8 с помощью команды «Сохранить как…») и открыть обновлённый текстовый документ через браузер, чтобы посмотреть, как HTML-код будет отображаться в программе для просмотра интернет-контента. Для удобства, чтобы не приходилось постоянно переключаться между окнами, окно браузера можно свернуть на половину экрана и расположить его в левой части, а окно текстового редактора с кодом — в правой половине. С таким положением окон можно будет смотреть на визуальный пользовательский интерфейс и параллельно редактировать код.
В данном случае в окне браузера можно заметить, что название вкладки содержит текст из тайтла «Титульное название страницы». А в самом окне находятся большой «Заголовок первого уровня» с полужирным начертанием шрифта, после которого сразу следует блок информации. При этом скрытый текст комментария не отображается (также должно отсутствовать изображение picture.jpg, поскольку этого файла нет в текущей папке GameDev).
Этот простейший пример наглядно иллюстрирует типичную структуру веб-документа. В начале документа принято указывать его тип. Указание подобных инструкций осуществляется с помощью специальных служебных слов, заключённых в угловые скобки (символы «меньше» и «больше»). Такую запись принято называть дескриптором или тегом. Чаще всего HTML-теги представлены в виде парного контейнера: открывающего и закрывающего тегов. Но некоторые теги могут быть одиночными, как специальный тег с объявлением типа документа , отличием которого также является наличие восклицательного знака после первой скобки.
Следом за доктайпом указываются признак начала документа в виде открывающего тега , внутри которого можно определить используемый в документе язык lang=»ru», и признак конца документа в виде закрывающего тега со слэшем (косой чертой). Между ними находятся теги
…, предназначенные для служебных заголовков, и тело документа … для указания видимого пользователю контента. В разделе заголовков традиционно указывают название документа между тегамиВ случаях, когда в документах оказывается много данных для обработки, допустимо добавлять скрытые комментарии с вспомогательными подсказками, облегчающими код-ревью (просмотр) или редактирование кода спустя несколько месяцев с момента разработки. HTML-комментарии пишутся подобно тегам в угловых скобках с добавлением двойных дефисов (минусов) по краям и восклицательного знака после первой скобки . Но для экономии времени и места комментарии можно заменять говорящими идентификаторами (id) внутри тегов. Например, в HTML-коде можно использовать блок
с атрибутом . Такой id (подобно комментарию) способен указать на игровую тематику блока. Кроме того, id позволяет получить доступ к HTML-элементу и считать или изменить его содержимое с помощью JavaScript-сценария!
Листинг-2. HTML-заготовка для игры
IT-проект
Судоку
Загрузка…
В листинге-2 представлена сырая (предварительная) заготовка для будущей игры, которую следует скопипастить в HTML-документ вместо примера из листинга-1. В начале HTML-кода в разделе заголовков помимо тайтла добавлены три мета-тега с указанием кодировки документа, параметров отображения документа на мобильных устройствах и краткого описания содержимого документа. А также добавлен признак подключения внешнего JavaScript-сценария. Далее внутри тега с помощью обработчика события onLoad браузеру сообщается о потребности в автозапуске JavaScript-функции с именем GUI() сразу при открытии веб-документа. В самом теле документа указываются заголовок первого уровня с текстом «Судоку» и игровой блок с текстом-заглушкой «Загрузка…», который будет отображаться до момента загрузки внешнего сценария и запуска JS-функции GUI() для внедрения в блок пользовательского интерфейса приложения.
JS (JavaScript)
JavaScript — объектно-ориентированный язык программирования (с адаптированным синтаксисом языка C++), который можно использовать в frontend-разработке интерактивных веб-приложений, выполняющихся в клиентском браузере пользователя. JS-код небольшого объёма допустимо располагать в произвольном месте документа между тегами . Но для удобочитаемости код сценариев традиционно выносят в отдельные текстовые файлы, которые подключают к нужным документам (лучше в разделе заголовков после мета-тегов), как показано в примере из листинга-2. Для этого в папке GameDev необходимо создать новый текстовый документ с именем script и расширением .js, который также следует открыть с помощью текстового редактора (и расположить открывшееся окно в правой части экрана). Затем можно приступить к программированию, начав с создания функции для формирования пользовательского интерфейса.
Листинг-3. Графический пользовательский интерфейс
function GUI() var ui='
document.getElementById('game').innerHTML=ui
>
/* Фрагмент внедрённого HTML-кода
В листинге-3 приведён пример внедрения HTML-кода в блок с из JS-функции с символическим именем GUI (от англ. Graphical User Interface), объявленной в начале кода с помощью предшествующего служебного ключевого слова function. Как и в случае с id, имена JS-функций и всех используемых переменных резонно подбирать таким образом, чтобы они чётко соответствовали своему назначению и были понятны даже сторонним кодерам при просмотре кода.
После функции GUI() представлен JS-комментарий с примером того, как браузер будет воспринимать содержимое обновлённого контейнера
в документе после выполнения операторов функции и внедрения фрагмента HTML-кода. Данный пример показывает, что написание всего нескольких строк JS-кода может сэкономить байтовое пространство (объём), позволяя быстрее загружать документ с лёгким весом и, следовательно, быстрее начинать выполнение кода, а также время разработчика, избавляя от рутинного ввода большого объёма информации. Иными словами, JS-сценарии можно использовать не только для чистого программирования, но и для редактирования исходного HTML-кода.
В приведённом примере текст закомментирован с помощью одиночных косых черт и звёздочек /*…*/. Такую конструкцию принято использовать для многострочных комментариев, но для небольшого однострочного текста допустимо использовать парные слэши // перед комментарием. В отличие от HTML-комментариев, без которых можно обойтись, в тело функций уместно добавлять JS-комментарии, поясняющие отдельные фрагменты выполняемого кода (поскольку в некоторых случаях легко понять, ЧТО делает конкретная строчка кода, но сложно понять, ЗАЧЕМ она это делает). Также в ряде случаев может возникнуть необходимость закомментировать неиспользуемые фрагменты кода (например, при отладке сценария). Но в данном случае комментарий приводится в качестве наглядного примера, демонстрирующего, как несколько строчек JS-кода могут заменить большой HTML-фрагмент!
После формирования игровой таблицы резонно предусмотреть ограничения на ввод чисел в текстовые поля. По правилам Судоку в ячейках должны находиться только натуральные числа от 1 до 9. Поэтому в функции GUI() для полей ввода логично указать максимальную длину в 1 символ с помощью атрибута maxLength=1 в теге . Дополнительно можно добавить проверку на соответствие вводимых символов правилам игры, чтобы удалять все некорректные символы. Для реализации такой проверки достаточно прописать всего одну строчку JS-кода!
Листинг-4. Проверка вводимых символов
function InpChk(el) /* Если значение не число или 0, тогда очистить поле */
if(isNaN(el.value) || el.value==0)
>
В листинге-4 приведён пример функции с аргументом — специальным параметром для передачи дополнительных значений. В данном примере для хранения такого параметра используется переменная el, которой будет передаваться ссылка на проверяемый элемент при вызове этой функции в обработчике события. Несмотря на краткость, название переменной el (от англ. Element) и название самой функции InpChk (от англ. Input+Check) чётко отражают назначение кода!
Для запуска функции InpChk() необходим триггер — наступление особого события, инициируемого пользователем. Учитывая назначение функции, подходящим событием является ввод символа с клавиатуры в любое текстовое поле. Поэтому для вызова функции InpChk() внутрь каждого тега из листинга-3 следует добавить обработчик события onKeyUp=»InpChk(this)», через который с помощью служебного слова this функции в качестве параметра будет передаваться ссылка на активный элемент.
В теле функции для считывания содержимого элемента используется свойство value, связанное с аргументом el через точку. Проверка значения активного текстового поля осуществляется в условном операторе if. В данном случае с помощью служебной JS-функции isNaN (от англ. is Not a Number), логического «или» || и оператора сравнения == (читается «равно») выполняется проверка одновременно двух условий: если значение не является числительным или равняется 0, текстовому полю присваивается новое значение в виде пустой строки.
Таким образом, благодаря простой проверке в одну строчку кода можно удостовериться, что после пользовательского ввода в ячейках будут находиться корректные данные, обработка которых в дальнейшем не должна привести к программному сбою! И можно смело заводить переменные для хранения данных!
Учитывая размер игрового поля, для хранения и обработки данных из ячеек 9×9-таблицы потребуется 81 переменная. Такое количество переменных удобно представить в формате массива вида НазваниеМассива[индекс] или в формате двумерного массива вида НазваниеМассива[индекс1][индекс2]. Для этого в коде сценария необходимо объявить глобальную переменную с именем A (от англ. Array), указав, что она будет использоваться для хранения массива данных.
Листинг-5. Создание двумерного массива
/* i — номер строки,
j — номер столбца */
var A=new Array();
for(i=1;i <10;i++)<
A[i]=new Array();
//for(j=1;j<10;j++)
>
A[1][1]=3;A[1][2]=6;A[1][3]=7;A[1][4]=5;A[1][5]=4;A[1][6]=2;A[1][7]=1;A[1][8]=8;A[1][9]=9;
A[2][1]=1;A[2][2]=4;A[2][3]=5;A[2][4]=3;A[2][5]=9;A[2][6]=8;A[2][7]=7;A[2][8]=2;A[2][9]=6;
A[3][1]=2;A[3][2]=9;A[3][3]=8;A[3][4]=6;A[3][5]=7;A[3][6]=1;A[3][7]=4;A[3][8]=3;A[3][9]=5;
A[4][1]=6;A[4][2]=5;A[4][3]=4;A[4][4]=1;A[4][5]=2;A[4][6]=7;A[4][7]=8;A[4][8]=9;A[4][9]=3;
A[5][1]=8;A[5][2]=3;A[5][3]=9;A[5][4]=4;A[5][5]=5;A[5][6]=6;A[5][7]=2;A[5][8]=7;A[5][9]=1;
A[6][1]=7;A[6][2]=1;A[6][3]=2;A[6][4]=9;A[6][5]=8;A[6][6]=3;A[6][7]=6;A[6][8]=5;A[6][9]=4;
A[7][1]=4;A[7][2]=7;A[7][3]=6;A[7][4]=8;A[7][5]=3;A[7][6]=5;A[7][7]=9;A[7][8]=1;A[7][9]=2;
A[8][1]=9;A[8][2]=8;A[8][3]=3;A[8][4]=2;A[8][5]=1;A[8][6]=4;A[8][7]=5;A[8][8]=6;A[8][9]=7;
A[9][1]=5;A[9][2]=2;A[9][3]=1;A[9][4]=7;A[9][5]=6;A[9][6]=9;A[9][7]=3;A[9][8]=4;A[9][9]=8;
В листинге-5 представлен фрагмент JS-кода с созданием массива A, содержащего 81 переменную с числовыми значениями. В JS глобальные переменные можно объявлять в произвольном месте кода по мере необходимости (например, перед функциями, в которых они должны использоваться). Но для экономии места резонно перечислять все глобальные переменные через запятую в самом начале сценария!
В начале кода приведён пример двухстрочного комментария внутри конструкции /*…*/. Затем с помощью служебных слов var и new Array() объявляется пустой массив с именем A. При помощи цикла for с шагом i++ (краткая запись i++ соответствует записи i=i+1 и увеличивает счётчик на 1) создаётся 9 элементов массива с индексами от 1 до 9, каждый из которых также становится массивом. Таким образом, массив A[i] преобразовывается в двумерный (двойной) массив вида A[i][j], в котором первый индекс [i] соответствует табличной строке, а второй индекс [j] — табличному столбцу. Строчка кода for(j=1;j <10;j++)с присваиванием элементам массива изначальных нулевых значений во втором (внутреннем) цикле for является избыточной, поскольку после первого (внешнего) цикла for всем элементам массива присваиваются новые значения (поэтому она представлена в виде однострочного комментария, демонстрирующего, как можно обращаться к элементам массива по их индексам).
После формирования массива данных можно приступить к выводу его значений на экран. Для этого некоторым изначально пустым текстовым полям нужно присвоить числовые значения переменных, хранящихся в массиве. При этом резонно внедрить в код генератор случайных чисел, помогающий подбирать разные текстовые поля при каждом запуске игры (чтобы игра не получилась скучной).
Листинг-6. Генератор случайных чисел
function rnd(hi) var r=Math.floor(Math.random()*hi)+1;
return r
>
В листинге-6 приведён пример функции с возвращаемым значением. В теле функции создаётся локальная переменная r (от англ. Random) для хранения случайного числа. С помощью метода random() объекта Math, применяемого в JS при математических операциях, генерируется случайное число с плавающей точкой в диапазоне от 0 до 1. Затем число умножается на аргумент функции hi (от англ. High), представляющий собой верхнюю границу генерируемого числа. При помощи метода floor() объекта Math от результата умножения отсекается дробная часть после запятой. И к полученному целому числу прибавляется 1, символизирующая нижнюю границу генерируемого числа. Итоговый результат присваивается переменной r и возвращается в качестве значения функции с помощью служебного слова return. Для использования полученного генератора и заполнения полей необходимо усовершенствовать код функции GUI().
Листинг-7. Пользовательский интерфейс 2.0
function GUI() var n,ui='
| if(j==n) else ui+='> | '
document.getElementById('game').innerHTML=ui
>
В листинге-7 представлен обновлённый вариант функции GUI() с добавленной переменной n для хранения случайных чисел. В начале второго цикла for были добавлены три условных оператора if для генерации чисел с помощью функции rnd() при первой, четвёртой и седьмой итерациях (чтобы выбрать номер открытой ячейки в каждой из трёх малых 3×3-квадратных секций). В конце второго цикла for добавлен ещё один if, проверяющий, совпадает ли номер столбца ячейки со случайным числом. Если условие выполняется, к переменной ui внутрь тега с помощью атрибута value добавляется значение из массива данных A[i][j] и признак недоступности с помощью атрибута disabled. Если условие не выполняется, внутрь тега добавляется обработчик события со ссылкой на функцию для проверки вводимых символов.
После внесённых изменений в код функции GUI() получился полноценный игровой уровень. При каждом запуске полученной игры изначально будут открываться ячейки с разными номерами. Но, учитывая, что значения берутся из одного массива A, числа в каждой из 81 ячейки всегда будут одинаковыми. Чтобы этого избежать, можно создать базу данных из 10 или 100 разных массивов. Тогда при запуске новой игры загружались бы разные массивы. Но и в этом случае количество уровней всё равно было бы ограничено количеством массивов. Поэтому вместо создания альтернативных массивов для новых уровней резонно перемешивать числа в единственном массиве A.
Судоку по сути представляет собой квадратную алгебраическую матрицу, в которой можно менять местами строки и столбы. Главное, чтобы в строках, в столбцах и в 3×3-секциях Судоку не было повторяющихся чисел. С точки зрения разработчика это означает, что сумма чисел от 1 до 9 в каждой строке, в каждом столбце и в каждой секции должна равняться 45 (1+2+3+4+5+6+7+8+9=45). А, как известно из школьного курса элементарной математики, от перестановки мест слагаемых сумма не меняется! Следовательно, в соседних горизонтальных и вертикальных малых 3×3-квадратах можно поменять местами строки или столбцы. Например, в первой строке первой секции первый, второй и третий столбцы можно поставить шестью разными способами: , , , , или . То же касается и расположения первых трёх строк в первом столбце, и расположения самих 3×3-секций. Иными словами, можно создать специальную функцию, которая бы перемешивала значения трёх сгруппированных элементов.
Листинг-8. Триады
function tri() var sw=rnd(6),t=new Array();
switch(sw) case 1:t[1]=1;t[2]=3;t[3]=2;break;
case 2:t[1]=2;t[2]=1;t[3]=3;break;
case 3:t[1]=2;t[2]=3;t[3]=1;break;
case 5:t[1]=3;t[2]=2;t[3]=1;break;
default:t[1]=3;t[2]=1;t[3]=2
>
return t
>
В листинге-8 приведён пример функции tri(), которая возвращает массив данных из трёх чисел от 1 до 3, представленных в произвольном порядке. В теле функции объявляются локальная переменная sw (от англ. Switch), которой с помощью функции rnd() присваивается случайное число в диапазоне от 1 до 6, и пустой массив t (от англ. Triad). Затем вместо привычного условного оператора if используется оператор переключения switch, который сравнивает значение sw с числовыми вариантами, указанными после служебного слова case, и включает выполнение соответствующих действий (расположенных между двоеточием и служебным словом break). При этом, если переменная sw будет равна 4 или 6, выполнятся действия, указанные после служебного слова default. Таким образом, после выполнения оператора switch в массиве t окажутся три числа в произвольном порядке. Для перемешивания сгруппированных троек можно создать отдельную функцию или дополнить код в начале функции GUI().
Листинг-9. Обмен данных массива
function mix() var col,m=new Array(),row;
for(i=0;i <7;i+=3)// Генерация столбцов
col=tri();
for(j=1;j <10;j++)// Считывание столбцов
m[1]=A[j][1+i];
m[2]=A[j][2+i];
m[3]=A[j][3+i];
// Перемешивание столбцов
A[j][1+i]=m[col[1]];
A[j][2+i]=m[col[2]];
A[j][3+i]=m[col[3]]
>
// Генерация строк
row=tri();
for(j=1;j <10;j++)// Считывание строк
for(l=1;l<4;l++)
// Перемешивание строк
for(l=1;l<4;l++)>>>
В листинге-9 представлен пример использования функции tri() для перемешивания столбцов и строк игровой таблицы. В начале кода объявляются локальные переменные col (от англ. Column) для хранения массива номеров перемешиваемых столбцов, m (от англ. Mixer) для временного хранилища обновляемых данных и row (от англ. Row) для хранения массива номеров перемешиваемых строк. Затем внутри первого цикла for с шагом i+=3 (i=i+3) переменой col с помощью функции tri() присваивается массив из трёх чисел, причём по задумке при каждой итерации цикла порядок чисел должен меняться. Во втором цикле for с привычным шагом j++ (j=j+1) создаются три элемента массива m, которым присваиваются значения из глобального массива A. Далее данные выбранной тройки элементов глобального массива A обновляются на новые значения из временного хранилища m в порядке, определяемом тройкой перемешанных чисел из массива col (например, если при вызове функции tri() будет сформирован порядок , вместо первого столбца должен оказаться второй, вместо второго — третий, а вместо третьего — первый). Аналогичным образом перемешиваются тройки строк, но в данном примере в третьем цикле for для считывания и обмена данных между массивами m и A создаются дополнительные вложенные циклы for с шагом l++ (l=l+1), позволяющие сделать запись более компактной и сэкономить объём документа. Для активации перемешивания чисел в начало функции GUI() следует добавить вызов созданной функции mix() либо скопипастить туда весь код.
После внесённых изменений при каждом запуске функции GUI() должен формироваться новый уровень со случайными числами-подсказками. Но при этом сами уровни будут весьма сложными (особенно для новичков), поскольку в коде функции GUI() для каждой игры изначально предусмотрено открытие лишь 27 ячеек из 81. Упростить игровой процесс для начинающих игроков можно с помощью внедрения дополнительной опции с подсказками, открывающими закрытые ячейки. Реализовать это можно, придерживаясь разной логики: открыть все угловые ячейки, полностью открыть одну из строк, полностью открыть столбец, открыть одну из 3×3 секций, открыть ячейку, выбранную пользователем. Но для поддержания эффекта неожиданности резонно вновь воспользоваться генератором случайных чисел!
Листинг-10. Игровые подсказки
var HN=0;
function hint() /* Если счётчик меньше 15, выполнить код */
if(HN <15)var col=new Array(),n=0,row=new Array();
for(i=1;i <10;i++)for(j=1;j <10;j++)if(document.getElementById('i'+i+j).value=='')
>>
if(n>0) if(n>1)
document.getElementById('i'+row[n]+col[n]).value=A[row[n]][col[n]];
document.getElementById('i'+row[n]+col[n]).disabled=1
>else
>>
В листинге-10 приведён пример реализации игровых подсказок, которыми можно воспользоваться до 15 раз. Перед использованием функции необходимо объявить глобальную переменную HN (от англ. Hint+Number) для отслеживания количества запрошенных подсказок, значение которой проверяется в начале кода. Если при вызове функции значение HN будет меньше 15, счётчик увеличивается на 1. Далее внутри if объявляются параллельные массивы col и row для хранения номеров столбцов и строк ячеек и переменная n для хранения количества элементов этих массивов. Внутри двух циклов for с помощью if проверяются значения всех текстовых полей из игровой таблицы. Если проверяемая ячейка оказывается пустой, счётчик n увеличивается на 1, а в массивы row и col записываются номера строки и столбца пустой ячейки.
После выполнения циклов for в if проверяется значение счётчика n. Если была зафиксирована хотя бы одна пустая ячейка, во вложенном if уточняется количество таких ячеек. Если количество пустых ячеек окажется больше 1, при помощи функции rnd() генерируется случайное число в диапазоне от 1 до n, и это число присваивается переменной n, перезаписывая её старое значение. Затем в пустое текстовое поле записывается значение из глобального массива A с индексами row[n] и col[n]. А само поле становится заблокированным для изменений с помощью активации свойства disabled, значение которого меняется на 1 (булеву истину).
Внедрение в код алгоритма с подсказками позволит дополнительно открыть 15 чисел-подсказок в начале каждой игры (и останется заполнить меньше половины ячеек), что должно помочь начинающим игрокам в поисках успешного решения Судоку! А, чтобы игрок мог убедиться в правильности решения Судоку, необходимо добавить финальную проверку всех введённых данных.
Листинг-11. Проверка по массиву
function chk() var err=0;
for(i=1;i <10;i++)for(j=1;j <10;j++)if(document.getElementById('i'+i+j).value!=A[i][j])
>>
/* if(err>0)else */
err=(err>0)?'Количество ошибок: '+err:'Судоку решена!';
alert(err)
>
В листинге-11 представлена реализация самой простой проверки решения Судоку — сравнение значений ячеек игровой таблицы со значениями данных из глобального массива A. В начале функции с именем chk (от англ. Check) объявляется локальная переменная err (от англ. Error) для мониторинга ошибок. Внутри двух циклов for с помощью if и оператора сравнения != (читается «не равно») проверяются значения текстовых полей. Если значение проверяемой ячейки не совпадает со значением элемента массива A с теми же индексами i и j, счётчик err увеличивается на 1. Далее err присваивается строковое значение с помощью сокращённой формы условного оператора if…else (для наглядности привычная форма записи представлена в комментарии). Если в ходе проверки была зафиксирована хотя бы одна ошибка, err присваивается строка «Количество ошибок:» с добавлением старого значения счётчика err. Иначе err присваивается строка «Судоку решена!». В конце функции при помощи служебной функции alert() вызывается всплывающее диалоговое окно с текстовым сообщением из обновлённой переменной err, передаваемым в качестве параметра.
Такая проверка проста в реализации, но она может принять правильное решение за ошибочное, если порядок введённых чисел не будет в точности соответствовать значениям массива A. А это совсем не комильфо и даже полный моветон, поскольку, как известно, некоторые задачи могут иметь несколько решений! В ряде случаев в строках/столбцах из соседних секций Судоку встречаются симметричные ячейки, которые можно заполнить, например, числами и либо и . И оба таких решения будут верным, но проверка по массиву засчитает лишь тот вариант, который будет совпадать со значениями из массива. Поэтому алгоритм проверки решения Судоку резонно реализовать в соответствии с иной логикой, сравнивая суммы чисел из строк, столбцов и малых 3×3-квадратов с 45 (1+2+3+4+5+6+7+8+9=45). Также, чтобы не раздражать пользователя, вынуждая совершать дополнительные действия, закрывая диалоговые окна после каждой проверки, в качестве альтернативы можно внедрить в пользовательский интерфейс дисплей для отображения сообщений!
Листинг-12. Универсальная проверка
function chk() var col=0,err=0,row=0,s9=0,sc,sr;
for(i=1;i <10;i++)for(j=1;j <10;j++)// Сумма в строках
sr+=1*document.getElementById('i'+i+j).value;
// Сумма в столбцах
sc+=1*document.getElementById('i'+j+i).value
>
if(sc!=45||sr!=45)
>
// Сумма в 3x3-секциях
if(!err) for(i=1;i <4;i++)for(j=1;j<4;j++)
if(i==3) if(s9!=45)
s9=0;col+=3;
if(col>6)
if(row<7)
>>>
// Формирование сообщения
document.getElementById('scr').innerHTML=(err)?'Эпик-фэйл!':'Судоку решена!';
// Цвет текста сообщения
document.getElementById('scr').style.color=(err==1)?'#bb0000':'#009900'
>
В листинге-12 приведён пример реализации универсальной проверки, учитывающей все возможные варианты решения Судоку. В начале усовершенствованной функции chk() помимо переменной err объявляются локальные переменные col для перехода между столбцами 3×3-секций, row для перехода между строками 3×3-секций, s9 (от англ. Sum+9) для вычисления суммы чисел в каждой из девяти 3×3-секций, sc (от англ. Sum+Column) для вычисления суммы чисел в столбцах и sr (от англ. Sum+Row) для вычисления суммы чисел в строках. Внутри двух циклов for одновременно вычисляются суммы чисел в строках и столбцах. Для этого в первом цикле for переменным sc и sr присваиваются 0. Затем во втором цикле for к значениям sc и sr прибавляются значения текстовых полей, умноженные на 1, с разными комбинациями индексов (i и j, j и i).
По умолчанию значения текстовых полей относятся к строковому типу данных String. А умножение значений на 1 переводит строковый тип в числовой Number. И если забыть изменить тип данных, при сложении двух строковых значений вместо суммы чисел получится строка из двух элементов (например, ‘1’+’2’=’12’, но ‘1’*1+’2’*1=1+2=3).
После завершения итераций второго цикла for в if проверяются суммы строк и столбцов. Если одна или обе суммы будут отличны от 45, переменной err присвоится 1, а выполнение циклов for досрочно прервётся служебным словом break. После вычисления сумм всех строк и столбцов в if проверяется истинность переменной err.
В JS числовые значения 0 и 1 соответствуют булевым false и true. Поэтому в случаях, когда переменные в условии if равняются только 0 или 1, допустимо относить их числовые значения к условному типу Boolean. При этом, если в условии такие значения должны быть равны true, можно не указывать оператор сравнения и использовать краткую запись. В примере краткая запись в условии !err соответствует записи !err==true (читается «не err истина»). Но чтобы не запутаться, можно использовать привычное условие err==0.
Таким образом, если проверка строк и столбцов не выявит ошибок и в переменной err останется 0 (булева ложь), будут выполнены вложенные циклы for для проверки суммы чисел в девяти 3×3-секциях. Для этого во внутреннем цикле for с шагом j++ к переменной s9 добавляются значения текстовых полей с индексами [i+row] и [j+col], умноженные на 1. Далее в if производится перехват третьей итерации внешнего цикла for (при i==3). С помощью вложенного if проверяется сумма чисел первой 3×3-секции. Если эта сумма будет отлична от 45, переменной err присвоится 1, а выполнение циклов for досрочно прервётся служебным словом break. Иначе переменная s9 обнулится, а к переменной col прибавится 3 для горизонтального перехода к соседней группе 3×3-секций. Затем в if проверяется значение col. Если это значение окажется больше 6, переменная col обнулится, а переменная row увеличится на 3 для вертикального перехода к соседней группе 3×3-секций. После этого в if проверяется значение row. Если это значение окажется меньше 7, произойдёт обнуление счётчика i внешнего цикла for, и итерации циклов повторятся ещё несколько раз (до тех пор, пока переменная row не окажется больше или равна 7 либо сумма s9 не станет отличной от 45).
В конце функции с помощью краткой записи условия (err) формируется сообщение, которое записывается в элемент с (от англ. Screen), выступающий в роли дисплея. Если в переменной err находится булева истина (err==1), на дисплей выводится забавная строка «Эпик-фэйл!» (от англ. Epic+Fail). Иначе, если ошибок зафиксировано не было (err==0), на дисплей выводится строка «Судоку решена!». Затем для дисплея указывается шестнадцатеричный номер цвета текста (в диапазоне от 0 до 255). Причём во втором случае используется привычная форма записи условия (err==1), но можно опустить указание оператора сравнения == и использовать краткую запись (err). Если при проверке были выявлены ошибки и в переменной err находится 1, с помощью объекта style и свойства color переопределяется настройка стиля оформления элемента с , меняя цвет шрифта текста на #bb0000 (оттенок красного). Иначе, если ошибок выявлено не было (err==0), цвет шрифта меняется на #009900 (оттенок зелёного).
Для активации функций chk() и hint() нужно усовершенствовать код функции GUI(), добавив в пользовательский интерфейс дисплей для вывода оповещений и кнопки с обработчиками событий для вызова этих функций. Также для разнообразия в интерфейс можно добавить секундомер или часы!
Листинг-13. Пользовательский интерфейс 3.0
function GUI() var n,ui='
Обыграй ИИ | ||||||||
! | ► | ✓ | ||||||
// Отображение пользовательского интерфейса
document.getElementById('game').innerHTML=ui;
// Переопределение цвета шрифта на дисплее
document.getElementById('scr').style.color='#ffffff'
>
Учитывая, что на кнопках представлены символьные обозначения, после игровой таблицы резонно добавить краткое описание приложения.
Листинг-14. Обновлённое тело HTML-документа
…Судоку
Загрузка…Описание приложения
! — запрос подсказки;
► — новая игра;
✓ — проверка решения.
Веб-приложение для игры и обучения детей и взрослых людей!
© Мазаяки

