Работающее приложение: http://ruby-game-life.cloudfoundry.com/
Попробуем запрограммировато известную игру Жизнь (придуманную Джоном Конвеем в 1970 году)
Выполним в 3 шага:
- Собственно постановка на игру - разработка ядра игры, с использованием тестирования (TDD) - Ruby, RSpec
- Разработка веб приложения для визуализации игры - Sinatra
- Разворачивание игры на внешнем хостинге - CloudFondry
Правила очень простые, из Википедии:
- Место действия этой игры — "вселенная" — это размеченная на клетки поверхность или плоскость — безграничная, ограниченная, или замкнутая (в пределе — бесконечная плоскость).
- Каждая клетка на этой поверхности может находиться в двух состояниях: быть "живой" или быть "мёртвой" (пустой). Клетка имеет восемь соседей (окружающих клеток).
- Распределение живых клеток в начале игры называется первым поколением.
Каждое следующее поколение рассчитывается на основе предыдущего по
таким правилам:
- пустая (мёртвая) клетка, рядом с которой ровно три живые клетки, оживает;
- если у живой клетки есть две или три живые соседки, то эта клетка продолжает жить; в противном случае (если соседей меньше двух или больше трёх) клетка умирает (от "одиночества" или от "перенаселённости").
- Игра прекращается, если на поле не останется ни одной "живой" клетки, или если при очередном шаге ни одна из клеток не меняет своего состояния (складывается стабильная конфигурация).
Выбираем основное:
- Есть матрица ячеек, ROWS и COLS
- Ячейка может быть заполена либо не заполнена
- У каждой ячейки есть соседние ячейки (8 шт)
- Есть начальное заполнение
- Есть шаг
- На следующем шаге:
- В пустой ячейке появляется жизнь если рядом есть 3 живые ячейки
- Живая ячейка продолжает жить, если у неё 2 или 3 соседа
- Если соседей меньше 2-х или больше 3-х тогда живая ячейка "погибает".
Создаём папку lib в ней класс game_life.rb
class GameLife end
А сейчас начнём описывать спецификации нашего класса
rspec --init
Создаём
require 'spec_helper'
require 'game_life'
describe GameLife do
it "указывается размер карты - столбцы и ячейки, получаем поле" do
game = GameLife.new :cols=>3, :rows=>2, :empty_cell=>'.'
game.screen.should == <<END_MAP
...
...
END_MAP
end
end
Теперь редактируем наш класс Жизни:
class GameLife
NL = "\n"
def initialize(options)
@rows = options[:rows]
@cols = options[:cols]
@empty_cell = options[:empty_cell]
end
def screen
ret = ''
@rows.times do
line = ''
@cols.times do
line << @empty_cell
end
ret << line << NL
end
ret
end
end
Тесты прошли. Пишем следующую спецификацию
Что должно выполнять наше веб приложение?
При заходе - мы должны увидеть некое начальное состояние игры Жизнь.
Отображение можно сделать просто текстовым, например:
.......
.......
.***...
...***.
.......
Где:
- '.' - пустая ячейка
- '*' - живая ячейка
Кнопка "Следующий шаг", Кнопка "Редактировать".
При нажатии на "Следующий шаг" - происходит обновление страницы - согласно правилам Жизни - появление и исчезновение клеток.
При нажатии на "Редактировать" - открывается формы где в простом текстовом виде можно отредактировать где у нас пустые ячейки, а где живые.
gem install sinatra
Создаём скрипт приложения app.rb
:
# web application
require 'rubygems'
require 'sinatra'
require 'lib/game_life'
INIT_GENERATION = \
".......\n" +
".......\n" +
".***...\n" +
"...***.\n" +
".......\n"
get '/' do
game = GameLife.new :empty_cell=>'.', :life_cell=>'*'
game.first_generation = INIT_GENERATION
@screen = game.screen
erb :index
end
post '/' do
game = GameLife.new :empty_cell=>'.', :life_cell=>'*'
game.first_generation = params[:g]
game.do_step
@screen = game.screen
erb :index
end
__END__
@@ layout
<html>
<head>
<title>Life</title>
</head>
<body>
<%= yield %>
</body>
</html>
@@ index
<form action="/" method="post">
<pre><%= @screen %></pre>
<input type="hidden" name="g" value="<%= @screen %>">
<input type="submit" value="Step">
</form>
Запускаем командой:
ruby app.rb
Открываем браузером http://localhost:4567
Для разорачивания игры на внешнем хостинге мы воспользуемся сервисом CloudFoundry http://cloudfoundry.org/ .
Это PaaS платформа (OpenSource), которая поддерживает Ruby, Java, NodeJS и др.
Создаём аккаунт на http://www.cloudfoundry.com/
Указываем email, после регистрации мы должны получить пароль.
Для работы нам потребуется гем vmc
. Устанавливаем:
gem install vmc
После установки посмотрим список команд:
vmc --help
Для начала нам нужно указать "целевое" облако, где мы хотим размещать наше приложение.
Так как мы используем cloudfoundry.com
сервис, то укажим:
vmc target api.cloudfoundry.com
После этого нам нужно авторизоваться в облаке, для этого используем команду login
:
vmc login [email protected]
Где вместо [email protected]
- указываем емейл на который мы создали аккаунт при регистрации
в cloudfoundry.com, и далее указываем пароль, который мы должны были получить после
регистрации.
В случае успешной авторизации на сервере, мы можем попробовать команду:
vmc info
Которая должна отобразить что-то вроде:
VMware's Cloud Application Platform
For support visit http://support.cloudfoundry.com
Target: http://api.cloudfoundry.com (v0.999)
Client: v0.3.10
User: [email protected]
Usage: Memory (896.0M of 2.0G total)
Services (3 of 16 total)
Apps (6 of 20 total)
Теперь нам надо разместить наше приложение на сервисе, каждое приложение имеет имя, и это имя будет доменом 3го уровня для cloudfoundry.com
Для первоначального размещения, и старта используется команда push, и указывается имя приложения.
vmc push ruby-game-life
Внимание ruby-game-life
- уже вероятно занят, поэтому при тестировании - укажите другое
имя - чтобы домен 3го уровня был создан.
При выполнении этой команды мы должны находиться в папке с нашим приложением.
VMC будет спрашивать некоторые вопросы, но для начала можно отвечать на них по умолчанию.
В случае успешного разворачивания, мы можем открыть браузер http://ruby-game-life.cloudfoundry.com
и увидеть наше работающее приложение.
Если какой-либо файл в нашем приложении изменился, то нам неоходимо внести это изменение на сервер, где крутится Облако, и перезапустить приложение.
Делается это одной командой:
vmc update ruby-game-life
Здесь ruby-game-life
- это название, которые вы дали своему приложению.
По этой команде система сама определит те файлы что изменились, или были добавлены. Сформирует пакет - запишет этот пакет на сервис, там распакует, и переезапустит приложение.
И соответственно после выполения мы сможет увидеть эти изменения.