Шеста задача
- Краен срок:
- 20.12.2011 23:59
- Точки:
- 6
Срокът за предаване на решения е отминал
Game of Life
Задачата ви на това домашно ще бъде да имплементирате Conway’s Game of Life. Правилата на играта са прости и целта ви ще е да създадете клас, отговарящ на безкрайния двуизмерен свят на играта и имплементиращ въпросните правила.
Правила
Светът, в който се развива действието, е безкрайна двуизмерна координатна система. Ще го наричаме игрална дъска. На всяка координата съответства клетка. Всяка клетка има точно две състояния — жива или мъртва. Освен състояния, клетката има и осем съседа — това са обграждащите я клетки (лява, дясна, горна, долна, горе-ляво, горе-дясно, долу-ляво и долу-дясно). Поколение ще наричаме моментното състояние на игралната дъска — т.е. координатите на живите в момента клетки. От текущото поколение можем да поискаме да еволюира в следващо, прилагайки следните правила:
- Всяка жива клетка с по-малко от два живи съседа, умира (underpopulation).
- Всяка жива клетка с два или три живи съседа продължава да живее и в следващото поколение.
- Всяка жива клетка с повече от три живи съседа, умира (overpopulation).
- Всяка мъртва клетка с точно три живи съседа, се ражда (reproduction).
Докато "генерирате" следващото поколение, текущото не се променя и правилта се прилагат само над текущото.
Обикновено играта започва с някакво ръчно зададено, първоначално състояние. За координати ще използваме цели числа.
Реализация
За да имплементирате гореописаните правила, ще искаме от вас да създадете клас Board
, който има няколко определени метода.
Конструктор
За да можем да зададем началното състояние на игралната дъска, е необходимо да можем да конструираме инстанции на класа Board
, подавайки на конструктора му нула или повече двойки координати на живите клетки в следния формат: [x1, y1], [x2, y2], …
Например:
board = GameOfLife::Board.new [1, 2], [1, 3], [5, 6]
Индексиране на живите клетки
Класът Board
трябва да отговаря на #[]
и при подадени две координати — x и y, да връща истина, ако клетката на въпросната координата е жива и лъжа, ако не е.
Например:
board = GameOfLife::Board.new [1, 2], [1, 3], [5, 6]
board[1, 2] # true
board[0, 2] # false
Итериране по живите клетки
Класът Board
трябва да бъде Enumerable
. Посредством Board#each
трябва да може да се итерира по двойката координати [x, y]
на живите в текущото поколение клетки. Освен стандартното итериране, Board
трябва да поддържа и всички останали методи от Enumerable
, с изключение на методите, изискващи наредба. Редът на обхождане на живите клетки не е от значение.
Примерно извикване:
board = GameOfLife::Board.new [1, 2], [1, 3]
board.each do |x, y|
puts "The cell at (#{x}, #{y}) is alive"
end
Брой живи клетки
Както всеки Enumerable
, всяка инстанция на Board
трябва да отговаря и на метода #count
, който да връща цяло число — броя на живите клетки в поколението.
Еволюция на поколението
Класът Board
трябва да предоставя метод #next_generation
, който връща нова инстанция на същия клас, подходящо инициализирана със следващото поколение (базирано на текущото).
Например:
board = GameOfLife::Board.new [1, 2], [1, 3], [1, 4]
next_gen = board.next_generation
next_gen[1, 2] # false
next_gen[0, 3] # true
next_gen[2, 3] # true
Дизайн
За вътрешното представяне на игралната дъска може да използвате каквото прецените за удачно. Изисквания към публичното ви API:
- Да имате клас
Board
, който се намира в собствено именовано пространство, кръстеноGameOfLife
- Конструктор, имплементиран по гореописания начин
- Да имате метод
Board#next_generation
, връщащ нова дъска (инстанция наBoard
) със следващото поколение, без да мутира състоянието на текущата - Индексиращ метод
Board#[]
със семантиката, описана по-горе - Методи
Board#each
,#count
и прочее, отговарящи наEnumerable
-интерфейса
Примерен тест
Малък примерен тест може да намерите в GitHub репозиторията с домашните. Тъй като задачата е лека и условието е много просто, оставяме на вас да допълните примерния тест с каквото прецените.
Ограничения
Тази задача има следните ограничения:
- Най-много 100 символа на ред
- Най-много 4 реда на метод
- Най-много 2 нива на влагане
Ако искате да проверите дали задачата ви спазва ограниченията, следвайте инструкциите в описанието на хранилището за домашните.
Няма да приемаме решения, които не спазват ограниченията. Изпълнявайте rubocop
редовно, докато пишете кода. Ако смятате, че rubocop
греши по някакъв начин,
пишете ни на fmi@ruby.bg, заедно с прикачен код или линк към такъв като
private gist. Ако пуснете кода си публично (например във форумите), ще смятаме
това за преписване.