Skip to content

Commit

Permalink
исправление и упрощение
Browse files Browse the repository at this point in the history
  • Loading branch information
Geksanit committed Dec 22, 2017
1 parent 09b9188 commit 7d716b6
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 153 deletions.
36 changes: 14 additions & 22 deletions frontend/mvc/controller/Controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,14 @@
import Board from '../model/Board';
import Painter from '../view/Painter';

const autobind = (self) => {
Object.getOwnPropertyNames(self.constructor.prototype).forEach((key) => {
const val = self[key];
if (key !== 'constructor' && typeof val === 'function') self[key] = val.bind(self);
});
return self;
};

class Controller {
constructor() {
this.model = new Board(10, 10);
this.view = new Painter(this.model);
this.running = false;
this.fps = 1;
this.setSubscription();
this.view.newTable(this.model.matrix);// начальная отрисовка
this.view.initTable(this.model.matrix);// начальная отрисовка
this.setRunning(false);
}
setSubscription() {
Expand All @@ -34,7 +26,6 @@ class Controller {
toggleCell({ target }) {
const cell = target.cellIndex;
const row = target.parentElement.sectionRowIndex;
this.view.toggleCell(target);
this.model.toggleCell(row, cell);
}
setRunning(value) {
Expand All @@ -44,20 +35,21 @@ class Controller {
}
anim(callback) {
// останавливается и вызывет аргумент callback(для тестов), когда матрица перестает меняться
function loop() {
const self = this;
const loop = function loop() {
setTimeout(() => {
if (this.running) {
requestAnimationFrame(loop.bind(this));
const flag = this.model.worker();
if (!flag) { // изменилась ли матрица ?
this.setRunning(false);
if (self.running) {
requestAnimationFrame(loop);
const flag = self.model.calculateMatrix();
if (flag) { // повторилась ли матрица ?
self.setRunning(false);
}
} else if (callback) {
callback();
}
}, 1000 / this.fps);
}
loop.call(this);
}, 1000 / self.fps);
};
loop();
}
handlerButtons({ target }) {
switch (target.innerHTML) {
Expand All @@ -69,7 +61,7 @@ class Controller {
this.setRunning(false);
break;
case 'clear':
this.model.clear();
this.model.clearMatrix();
this.setRunning(false);
}
}
Expand All @@ -81,11 +73,11 @@ class Controller {
break;
case 'width':
this.setRunning(false);
this.model.resize(this.model.rows, value);
this.model.resizeMatrix(this.model.rows, value);
break;
case 'height':
this.setRunning(false);
this.model.resize(value, this.model.columns);
this.model.resizeMatrix(value, this.model.columns);
}
}
}
Expand Down
133 changes: 36 additions & 97 deletions frontend/mvc/model/Board.js
Original file line number Diff line number Diff line change
@@ -1,141 +1,80 @@
class Event {
constructor(sender) {
this.sender = sender;
this.listeners = [];
}
attach(listener) {
this.listeners.push(listener);
}
notify(args) {
this.listeners.forEach((listener) => {
listener(this.sender, args);
});
}
}
import Event from '../utils/Event';

class Board {
constructor(rows = 10, columns = 10) {
// матрица m на n заполненная false
this.matrix = [];
this.initMatrix(rows, columns);
this.rows = rows;
this.columns = columns;
this.listOldMatrix = [];
this.matrixChanged = new Event(this);
this.cellToggled = new Event(this);
}
initMatrix(rows, columns) {
this.matrix = [];
for (let i = 0; i < rows; i += 1) {
const row = [];
let row = [];
for (let j = 0; j < columns; j += 1) {
row.push(false);
}
this.matrix.push(row);
}
}
resize(m, n) {
const { matrix } = this;
const o = matrix.length;
const p = matrix[0].length;
// убираем столбцы
if (p > n) {
for (let i = 0; i < o; i += 1) {
matrix[i].splice(n - 1, p - n);// изменить length?
}
}

// добавляем столбцы
if (p < n) {
for (let i = 0; i < o; i += 1) {
for (let j = p; j < n; j += 1) {
matrix[i].push(false);
}
}
}

// убираем строки
if (o > m) matrix.splice(m - 1, o - m);// изменить length?

// добавляем строки
if (o < m) {
const line = [];
for (let j = 0; j < n; j += 1) {
line.push(false);
}

for (let i = o; i < m; i += 1) {
matrix.push(line.slice());
}
}

this.rows = m;
this.columns = n;
resizeMatrix(rows, columns) {
this.initMatrix(rows, columns);
this.rows = rows;
this.columns = columns;
this.listOldMatrix = [];
this.matrixChanged.notify({ matrix: this.matrix, resized: true });
}
clear() {
this.matrix.forEach((row) => {
row.forEach((item, i, arr) => {
arr[i] = false;
});
});
clearMatrix() {
this.initMatrix(this.rows, this.columns);
this.listOldMatrix = [];
this.matrixChanged.notify({ matrix: this.matrix, clear: true });
this.matrixChanged.notify({ matrix: this.matrix });
}
worker() {
calculateMatrix() {
// обход всех ячеек с записью нового состояния
const newMatrix = [];
let flag = false;// изменилась ли матрица?
this.matrix.forEach((row, i) => {
const newRow = [];
row.forEach((cell, j) => {
const newCell = this.calculateCell(i, j);
newRow.push(newCell);
if (newCell !== cell) flag = true;
});
newMatrix.push(newRow);
});

if (flag) { // изменилась ли матрица в сравнении с предыдущей ?
this.matrix = newMatrix;
flag = !this.isRepeat(newMatrix); // а в сравнении со всеми предыдущими ?
}
this.matrixChanged.notify({ matrix: this.matrix, isChanged: !flag });
const newMatrix = this.matrix.map((row, i) => row.map((cell, j) => this.calculateCell(i, j)));
const flag = this.isRepeatMatrix(newMatrix); // повторилась ли матрица?
this.matrixChanged.notify({ matrix: this.matrix });
this.matrix = newMatrix;
return flag;
}
isRepeat(newMatrix) {
isRepeatMatrix(newMatrix) {
const flag = this.listOldMatrix.some((matrix) => {
if (matrix.length !== newMatrix.length) return false;
if (matrix[0].length !== newMatrix[0].length) return false;
return matrix.every((row, i) => row.every((cell, j) => (cell === newMatrix[i][j])));
});
this.listOldMatrix.push(newMatrix);
if (flag) this.listOldMatrix = [];
else this.listOldMatrix.push(newMatrix);
return flag;
}
calculateCell(i, j) {
calculateCell(row, column) {
// соседи за пределами поля считаются мертвыми
let count = 0;// живые соседи
let newCell = this.matrix[i][j];
let newCell = this.matrix[row][column];

if (this.matrix[i - 1]) {
if (this.matrix[i - 1][j - 1]) count += 1;
if (this.matrix[i - 1][j]) count += 1;
if (this.matrix[i - 1][j + 1]) count += 1;
if (this.matrix[row - 1]) {
if (this.matrix[row - 1][column - 1]) count += 1;
if (this.matrix[row - 1][column]) count += 1;
if (this.matrix[row - 1][column + 1]) count += 1;
}

if (this.matrix[i][j - 1]) count += 1;
if (this.matrix[i][j + 1]) count += 1;
if (this.matrix[row][column - 1]) count += 1;
if (this.matrix[row][column + 1]) count += 1;

if (this.matrix[i + 1]) {
if (this.matrix[i + 1][j - 1]) count += 1;
if (this.matrix[i + 1][j]) count += 1;
if (this.matrix[i + 1][j + 1]) count += 1;
if (this.matrix[row + 1]) {
if (this.matrix[row + 1][column - 1]) count += 1;
if (this.matrix[row + 1][column]) count += 1;
if (this.matrix[row + 1][column + 1]) count += 1;
}

if (count < 2 || count > 3) newCell = false;
else if (count === 3) newCell = true;
return newCell;
}
toggleCell(i, j) {
this.matrix[i][j] = !this.matrix[i][j];
this.cellToggled.notify(i, j);
toggleCell(row, column) {
this.matrix[row][column] = !this.matrix[row][column];
this.matrixChanged.notify({ matrix: this.matrix });
}
}
export default Board;
15 changes: 15 additions & 0 deletions frontend/mvc/utils/Event.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Event {
constructor(sender) {
this.sender = sender;
this.listeners = [];
}
attach(listener) {
this.listeners.push(listener);
}
notify(args) {
this.listeners.forEach((listener) => {
listener(this.sender, args);
});
}
}
export default Event;
56 changes: 22 additions & 34 deletions frontend/mvc/view/Painter.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,24 @@
class Event {
constructor(sender) {
this.sender = sender;
this.listeners = [];
}
attach(listener) {
this.listeners.push(listener);
}
notify(args) {
this.listeners.forEach((listener) => {
listener(this.sender, args);
});
}
}
import Event from '../utils/Event';

class Painter {
constructor(model) {
this.model = model;
this.initDOMElements();
this.initEvents();
this.initHandlers();
this.initSubscription();
}
initDOMElements() {
this.table = document.getElementById('board');
this.controls = document.getElementById('controls');
this.buttons = this.controls.querySelectorAll('button');
}
initEvents() {
this.tableClicked = new Event(this);
this.buttonClicked = new Event(this);
this.sliderChanged = new Event(this);
this.setHandlers();
this.setSubscription();
}
setHandlers() {
initHandlers() {
this.table.onclick = (event) => {
if (event.target.tagName === 'TD') {
this.tableClicked.notify(event);
Expand All @@ -42,22 +35,20 @@ class Painter {
}
};
}
setSubscription() {
initSubscription() {
this.model.matrixChanged.attach((sender, obj) => {
if (obj.resized) this.newTable(obj.matrix);
else this.repaintTable(obj.matrix);
if (obj.resized) this.initTable(obj.matrix);
else this.changeTable(obj.matrix);
});
}
setButtons(running) {
if (!this.buttons) return;
this.buttons.forEach((button) => {
if (button.innerHTML === 'start') {
if (running) button.disabled = true;
else button.disabled = false;
button.disabled = running;
}
if (button.innerHTML === 'pause') {
if (running) button.disabled = false;
else button.disabled = true;
button.disabled = !running;
}
});
}
Expand All @@ -67,18 +58,15 @@ class Painter {
if (running) status.classList.remove('status_stopped');
else status.classList.add('status_stopped');
}
toggleCell(target) {
target.classList.toggle('live');
}
paintTbody(matrix, tableWidth) {
getNewTbody(matrix, tableWidth) {
// заполнение тела таблицы
const columns = matrix[0].length;
const size = tableWidth / columns;
const tbody = document.createElement('tbody');
let tbody = document.createElement('tbody');
matrix.forEach((row) => {
const tr = document.createElement('tr');
let tr = document.createElement('tr');
row.forEach((cell) => {
const td = document.createElement('td');
let td = document.createElement('td');
this.setTdClass(td, cell);
td.style.width = `${size}px`;
td.style.height = `${size}px`;
Expand All @@ -88,14 +76,14 @@ class Painter {
});
return tbody;
}
newTable(matrix) {
initTable(matrix) {
// для создания и ресайза таблицы
const { table } = this;
const tbody = this.paintTbody(matrix, table.clientWidth);
const tbody = this.getNewTbody(matrix, table.clientWidth);
if (table.children.length) table.replaceChild(tbody, table.children[0]);
else table.appendChild(tbody);
}
repaintTable(matrix) {
changeTable(matrix) {
// изменение класса у ячеек таблицы
const { table } = this;
const tbody = table.children[0];
Expand Down

1 comment on commit 7d716b6

@Geksanit
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.