DarkGoodWIN - JavaScript. Учебник начального уровня
Для реализации этой функции мы будем использовать ещё один предопределённый объект JavaScript‑Math, а именно, два метода этого объекта: round() и random(). Метод round() округляет число, переданное в качестве параметра до ближайшего целого. Например, raund(2.93) вернёт число 3, а raund(2.45) — число 2. Метод random() возвращает случайное дробное число от 0 до 1.
Предположим, мы вызвали функцию intRand() от 2, тогда (maxVal + 1) * Math.random() будет случайным дробным числом от 0 до 3. Каждое значение равновероятно, причём, при последующем округлении (если мы сразу применим функцию random к этому числу), нам вернётся 0 в случае, если число от 0 до 0.5; 1 если число от 0.5 до 1.5; 2 если число от 1.5 до 2.5 и 3 для числа от 2.5 до 3. Как видно из рассчётов, вероятность того, что вернётся 0 или 3 в два раза ниже, чем вероятность того, что вернётся 1 или 2. При том, что тройка нам не нужна совсем, а вероятность возврата 0 хотелось бы иметь равной вероятности возврата 1 и 2. Можно, конечно, написать условие, что если результат maxVal + 1, то вернуть 0 и это тоже будет формально правильно, однако я перед округлением вычел из дробного числа 0.5, что привело к по сути такому же результату.
Первый класс
Долго думал, стоит ли в рамках этого опуса использовать классы. На практике я часто сталкивался с тем, что очень не просто бывает объяснить зачем они нужны. На первый взгляд, после переделки какой–то простой процедурно–ориентированной программы в объектно ориентированную, ну или попросту после выделения одного–двух классов, программа, как правило, начинает выглядеть даже сложнее. Я всё же попробую. Причём как обычно буду стараться говорить человеческим языком, а если и буду вводить какие–то термины, постараюсь их объяснять.
Собственно преимущества выделения классов должны всплывать и в следующих главах по ходу повествования. Тут я лишь вскользь об этом упомяну.
Перейдём к делу, как я, кажется, уже говорил ранее, класс — это такая особенная переменная, которая может содержать другие переменные (поля), а также собственные функции (методы). В этой главе наша программа не научится делать ничего нового, при запуске произойдёт всё тоже самое, что и при запуске программы из прошлой главы. Изменился лишь сам код. Такое изменение программы называется рефакторингом.
Что же я поменял? Я выделил новый класс «minesClass» и перенёс туда часть переменных и функций. Для чего мне это понадобилось? Я решил отделить логику программы от её интерфейса. То есть класс «minesClass» ничего не будет знать о нашей таблице, однако он сам расставит бомбы при своём создании, а затем останется лишь их нарисовать.
Предлагаю читателю посмотреть на то, что получилось, а затем я всё–таки попытаюсь объяснить ему, что стало лучше.
<html>
<head>
head>
<script>
function minesClass(aRowCount, aColCount, aMinesCount)
{
this.intRand = function(maxVal)
{
return Math.floor((maxVal‑1) * Math.random() + 0.5) — 1;
}
this.fillMines = function()
{
var res = new Array(this.rowCount * this.colCount);
var mines = this.minesCount;
while (mines > 0)
{
var n = this.intRand(this.rowCount * this.colCount‑1);
if (res[n] != 1)
{
res[n] = 1;
mines--;
}
}
return res;
}
this.colCount = aColCount;
this.rowCount = aRowCount;
this.minesCount = aMinesCount;
this.mines = this.fillMines();
}
function initTable()
{
var mines = new minesClass(10, 10, 10);
var tbl = document.getElementById(«tbl»);
for (var i = 0; i < mines.rowCount; i++)
{
var row = tbl.insertRow(i);
for(var j = 0; j < mines.colCount; j++)
{
var cell = row.insertCell(j);
if (mines.mines[i * mines.rowCount + j] == 1)
cell.innerHTML = '*'
else
cell.innerHTML = '.';
}
}
}
script>
<body onLoad = initTable();>
<table ID = «tbl» BORDER = 2 width = 80% height = 80%>
table>
body>
html>
Короче и понятнее, ничего лишнего. Сразу видно, что к чему относится. Представте, что у вас в программе есть таблица для игры mines и одновременно есть таблица для игры в точки. Довольно трудно будет сказать в этом случае, что значит переменная rowCount. А вот если написано mines.rowCount, сразу всё понятно.
Перейдём к функции minesClass. Это по сути и есть наш новый класс. В JavaScript класс — это просто функция, а чтобы создать новый экземпляр классна нужно перед вызовом функции написать слово new.
В этой функции мы инициализируем методы intRand, fillMines, colCount, rowCount, minesCount и mines. В JavaScript методы также могут быть полями. Например, так мы описываем новый метод intRand. По сути переносим его в класс minesClass.
this.intRand = function(maxVal)
{
return Math.floor((maxVal‑1) * Math.random() + 0.5) — 1;
}
Я бы прочитал это так: поле «intRand» соответствует (равно) функции, которая принимает максимальное значение в качестве единственного параметра и возвращает случайное целое число от нуля до этого числа.
Аналогичным образом мы переносим функцию fillMines, делая её методом класса minesClass. Параметры этой функции уже не нужны, так как у метода класса есть доступ к его полям. Следует только не забывать перед обращением к полям класса писать «this.». Например, this.rowCount, this.mines и так далее.
Надеюсь мне хотя бы примерно удалось рассказать про то, как можно создавать и использовать классы в JavaScript и даже показать, что это может сделать программу понятнее. Если не вышло — значит я плохо старался… Однако у меня ещё остаётся надежда, что дальше всё станет понятнее. Тут затрагивались довольно трудные для понимания вещи и если что–то осталось непонятным — ничего удивительного и ничего страшного.
Считаем бомбы
На самом деле в этой главе тоже не будет ничего нового. Всё основное, чтобы реализовать функциональность этой главы я уже рассказал. Но что поделать, надо довести начатое до конца, да и потом, даже если где–то в чём–то я повторюсь, так ведь повторение — мать учения.
В прошлой главе мы остановились на том, что у нас была табличка, в которой рисовались бомбы в виде символа "*" или клетки без бомб в виде точки. Но это не очень–то похоже на сапёр в который мы все привыкли играть. Там вроде как в каждой клетке пишется количество соседних с ней клеток в которых есть бомба.
Ну что же, давайте сделаем это и в нашей программе. Ниже я приведу код, а потом, как обычно, его прокомментирую.
<html>
<head>
head>
<script>
function minesClass(aRowCount, aColCount, aMinesCount)
{
this.intRand = function(maxVal)
{
return Math.floor((maxVal‑1) * Math.random() + 0.5) — 1;
}
this.fillMines = function()
{
var res = new Array(this.rowCount * this.colCount);
var mines = this.minesCount;
while (mines > 0)
{
var n = this.intRand(this.rowCount * this.colCount‑1);
if (res[n] != 1)
{
res[n] = 1;
mines--;
}
}
return res;
}
this.hasMine = function(i, j)
{
if ((i < 0) || (j < 0) || (i >= this.rowCount) || (j >= this.colCount))
return 0;
if (this.mines[i * this.rowCount + j] == 1)
return 1;
return 0;
}
this.checkCell = function(i, j)
{
if (this.hasMine(i, j))
return '*';
return this.hasMine(i - 1, j - 1) + this.hasMine(i - 1, j) + this.hasMine(i - 1, j + 1) +
this.hasMine(i, j - 1) + this.hasMine(i, j + 1) +
this.hasMine(i + 1, j - 1) + this.hasMine(i + 1, j) + this.hasMine(i + 1, j + 1);
Откройте для себя мир чтения на siteknig.com - месте, где каждая книга оживает прямо в браузере. Здесь вас уже ждёт произведение DarkGoodWIN - JavaScript. Учебник начального уровня, относящееся к жанру Науки: разное. Никаких регистраций, никаких преград - только вы и история, доступная в полном формате. Наш литературный портал создан для тех, кто любит комфорт: хотите читать с телефона - пожалуйста; предпочитаете ноутбук - идеально! Все книги открываются моментально и представлены полностью, без сокращений и скрытых страниц. Каталог жанров поможет вам быстро найти что-то по настроению: увлекательный роман, динамичное фэнтези, глубокую классику или лёгкое чтение перед сном. Мы ежедневно расширяем библиотеку, добавляя новые произведения, чтобы вам всегда было что открыть "на потом". Сегодня на siteknig.com доступно более 200000 книг - и каждая готова стать вашей новой любимой. Просто выбирайте, открывайте и наслаждайтесь чтением там, где вам удобно.


