,
+}
+```
+
+Чтобы получить клетку по строке и столбцу, переводим их в индекс вектора `cells`, как описано ранее:
+
+```rust
+impl Universe {
+ fn get_index(&self, row: u32, column: u32) -> usize {
+ (row * self.width + column) as usize
+ }
+
+ // ...
+}
+```
+
+Чтобы вычислить следующее состояние клетки, нужно посчитать, сколько ее соседей живы. Напишем для этого метод `live_neighbor_count`!
+
+```rust
+impl Universe {
+ // ...
+
+ fn live_neighbor_count(&self, row: u32, column: u32) -> u8 {
+ let mut count = 0;
+ for delta_row in [self.height - 1, 0, 1].iter().cloned() {
+ for delta_col in [self.width - 1, 0, 1].iter().cloned() {
+ if delta_row == 0 && delta_col == 0 {
+ continue;
+ }
+
+ let neighbor_row = (row + delta_row) % self.height;
+ let neighbor_col = (column + delta_col) % self.width;
+ let idx = self.get_index(neighbor_row, neighbor_col);
+ count += self.cells[idx] as u8;
+ }
+ }
+ count
+ }
+}
+```
+
+Метод `live_neighbor_count` использует смещения и операцию modulo, чтобы не писать специальные `if` для краев вселенной. При смещении `-1` мы _прибавляем_ `self.height - 1` и позволяем modulo сделать свою работу вместо вычитания `1`. `row` и `column` могут быть равны `0`, и если бы мы попытались вычесть `1`, получили бы underflow беззнакового целого.
+
+Теперь у нас есть все, чтобы вычислить следующее поколение из текущего! Каждое правило игры прямо переводится в условие внутри выражения `match`. Дополнительно, поскольку мы хотим, чтобы момент тика контролировался из JavaScript, поместим этот метод внутрь блока `#[wasm_bindgen]`, чтобы он экспортировался в JavaScript.
+
+```rust
+/// Public methods, exported to JavaScript.
+#[wasm_bindgen]
+impl Universe {
+ pub fn tick(&mut self) {
+ let mut next = self.cells.clone();
+
+ for row in 0..self.height {
+ for col in 0..self.width {
+ let idx = self.get_index(row, col);
+ let cell = self.cells[idx];
+ let live_neighbors = self.live_neighbor_count(row, col);
+
+ let next_cell = match (cell, live_neighbors) {
+ // Rule 1: Any live cell with fewer than two live neighbours
+ // dies, as if caused by underpopulation.
+ (Cell::Alive, x) if x < 2 => Cell::Dead,
+ // Rule 2: Any live cell with two or three live neighbours
+ // lives on to the next generation.
+ (Cell::Alive, 2) | (Cell::Alive, 3) => Cell::Alive,
+ // Rule 3: Any live cell with more than three live
+ // neighbours dies, as if by overpopulation.
+ (Cell::Alive, x) if x > 3 => Cell::Dead,
+ // Rule 4: Any dead cell with exactly three live neighbours
+ // becomes a live cell, as if by reproduction.
+ (Cell::Dead, 3) => Cell::Alive,
+ // All other cells remain in the same state.
+ (otherwise, _) => otherwise,
+ };
+
+ next[idx] = next_cell;
+ }
+ }
+
+ self.cells = next;
+ }
+
+ // ...
+}
+```
+
+Пока состояние вселенной представлено вектором клеток. Чтобы сделать его удобным для чтения человеком, реализуем простейший текстовый рендерер. Идея в том, чтобы построчно выводить вселенную как текст: для живой клетки печатать Unicode-символ `◼` («черный средний квадрат»), для мертвой — `◻` («белый средний квадрат»).
+
+Реализовав трейт [`Display`](https://doc.rust-lang.org/1.25.0/std/fmt/trait.Display.html) из стандартной библиотеки Rust, мы добавим способ форматировать структуру в пользовательском виде. Это также автоматически даст нам метод [`to_string`](https://doc.rust-lang.org/1.25.0/std/string/trait.ToString.html).
+
+```rust
+use std::fmt;
+
+impl fmt::Display for Universe {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ for line in self.cells.as_slice().chunks(self.width as usize) {
+ for &cell in line {
+ let symbol = if cell == Cell::Dead { '◻' } else { '◼' };
+ write!(f, "{}", symbol)?;
+ }
+ write!(f, "\n")?;
+ }
+
+ Ok(())
+ }
+}
+```
+
+Наконец, определим конструктор, который инициализирует вселенную интересным паттерном живых и мертвых клеток, а также метод `render`:
+
+```rust
+/// Public methods, exported to JavaScript.
+#[wasm_bindgen]
+impl Universe {
+ // ...
+
+ pub fn new() -> Universe {
+ let width = 64;
+ let height = 64;
+
+ let cells = (0..width * height)
+ .map(|i| {
+ if i % 2 == 0 || i % 7 == 0 {
+ Cell::Alive
+ } else {
+ Cell::Dead
+ }
+ })
+ .collect();
+
+ Universe {
+ width,
+ height,
+ cells,
+ }
+ }
+
+ pub fn render(&self) -> String {
+ self.to_string()
+ }
+}
+```
+
+На этом Rust-часть реализации нашей «Игры жизни» готова!
+
+Пересоберите ее в WebAssembly, выполнив `wasm-pack build` в директории `wasm-game-of-life`.
+
+## Рендеринг с JavaScript
+
+Сначала добавим элемент `` в `wasm-game-of-life/www/index.html`, в который будем рисовать вселенную, прямо над тегом `
+ |