Решение на Втора задача от Илия Беличев

Обратно към всички решения

Към профила на Илия Беличев

Резултати

  • 5 точки от тестове
  • 0 бонус точки
  • 5 точки общо
  • 17 успешни тест(а)
  • 3 неуспешни тест(а)

Код

def move(snake, direction)
mutable_snake = snake.clone
mutable_snake.shift()
extract_new_snake(mutable_snake, direction,
extract_snake_last_coordinates(mutable_snake))
end
def extract_snake_last_coordinates(snake)
next_x = snake[snake.length - 1][0]
next_y = snake[snake.length - 1][1]
[next_x, next_y]
end
def next_coordinates(direction, last_coordinates)
if direction == [0, 1]
last_coordinates[1] += 1
elsif direction == [0, -1]
last_coordinates[1] -= 1
elsif direction == [1, 0]
last_coordinates[0] += 1
else
last_coordinates[0] -= 1
end
last_coordinates
end
def extract_new_snake(snake, direction, last_coordinates)
snake.push(next_coordinates(direction, last_coordinates))
snake
end
def grow(snake, direction)
mutable_snake = snake.clone
next_x = mutable_snake[mutable_snake.length - 1][0]
next_y = mutable_snake[mutable_snake.length - 1][1]
extract_new_snake(mutable_snake, direction, [next_x, next_y])
end
def new_food(food, snake, dimensions)
r = Random.new
random_coordinates = [r.rand(1..dimensions[:width]),
r.rand(1..dimensions[:height])]
collapse_coordinates = snake.select { |each| each == random_coordinates }
if collapse_coordinates.length == 0 and random_coordinates != food
return random_coordinates
end
new_food(food, snake, dimensions)
end
def obstacle_ahead?(snake, direction, dimensions)
mutable_snake = snake.clone
future_coordinates = next_coordinates(direction,
extract_snake_last_coordinates(mutable_snake))
if dimensions[:width] <= future_coordinates[0] or
dimensions[:height] <= future_coordinates[1] or
mutable_snake.any? {|coordinates| coordinates == future_coordinates }
return true
end
false
end
def danger?(snake, direction, dimensions)
snake_move_ahead = move(snake, direction)
obstacle_ahead?(snake_move_ahead, direction,
dimensions)
end

Лог от изпълнението

.F....F.F...........

Failures:

  1) #move moves one-position-sized snake
     Failure/Error: expect(move([[2, 2]], [-1, 0])).to eq([[1, 2]])
     NoMethodError:
       undefined method `[]' for nil:NilClass
     # /tmp/d20151026-15631-br0gca/solution.rb:9:in `extract_snake_last_coordinates'
     # /tmp/d20151026-15631-br0gca/solution.rb:5:in `move'
     # /tmp/d20151026-15631-br0gca/spec.rb:12:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  2) #new_food generates food on empty position
     Failure/Error: expect(empty_positions).to include(next_food)
       expected [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]] to include [3, 3]
     # /tmp/d20151026-15631-br0gca/spec.rb:53:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  3) #new_food does not generate food outside of borders (height)
     Failure/Error: expect(next_food[1]).to be_between(0, dimensions[:height].pred)
       expected between?(0, 2) to return true, got false
     # /tmp/d20151026-15631-br0gca/spec.rb:61:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.01503 seconds
20 examples, 3 failures

Failed examples:

rspec /tmp/d20151026-15631-br0gca/spec.rb:11 # #move moves one-position-sized snake
rspec /tmp/d20151026-15631-br0gca/spec.rb:49 # #new_food generates food on empty position
rspec /tmp/d20151026-15631-br0gca/spec.rb:60 # #new_food does not generate food outside of borders (height)

История (3 версии и 2 коментара)

Илия обнови решението на 13.10.2015 19:19 (преди над 9 години)

+# -*- coding: utf-8 -*-
+
+def move(snake, direction)
+ snake_ready_for_change = copy_array(snake)
+ snake_ready_for_change.shift()
+ move_helper(snake_ready_for_change, direction,
+ extract_last_snake_coordinates(snake_ready_for_change))
+end
+
+def extract_last_snake_coordinates(snake)
+ next_x = snake[snake.length - 1][0]
+ next_y = snake[snake.length - 1][1]
+ [next_x, next_y]
+end
+
+def next_coordinates(direction, last_coordinates)
+ if direction == [0, 1]
+ last_coordinates[1] += 1
+ elsif direction == [0, -1]
+ last_coordinates[1] -= 1
+ elsif direction == [1, 0]
+ last_coordinates[0] += 1
+ else
+ last_coordinates[0] -= 1
+ end
+ last_coordinates
+end
+
+def move_helper(snake, direction, last_coordinates)
+ next_coordinates = next_coordinates(direction, last_coordinates)
+ snake.push(next_coordinates)
+ return snake
+end
+
+def copy_array(array)
+ result = []
+ array.map { |each| result.push(each) }
+ return result
+end
+
+def grow(snake, direction)
+ snake_ready_for_change = copy_array(snake)
+ next_x = snake_ready_for_change[snake_ready_for_change.length - 1][0]
+ next_y = snake_ready_for_change[snake_ready_for_change.length - 1][1]
+
+ move_helper(snake_ready_for_change, direction, [next_x, next_y])
+end
+
+def new_food(food, snake, dimensions)
+ r = Random.new
+ random_coordinates = [r.rand(1..dimensions[:width]),
+ r.rand(1..dimensions[:height])]
+ collapse_coordinate = snake.select { |each| each == random_coordinates }
+ if collapse_coordinate.length == 0 and random_coordinates != food
+ return random_coordinates
+ else
+ new_food(food, snake, dimensions)
+end
+end
+
+def set_up_mutable_snake(snake)
+ snake_ready_for_change = copy_array(snake)
+ snake_ready_for_change.shift()
+ next_x = snake_ready_for_change[snake_ready_for_change.length - 1][0]
+ next_y = snake_ready_for_change[snake_ready_for_change.length - 1][1]
+ [next_x, next_y]
+end
+
+def obstacle_ahead?(snake, direction, dimensions)
+ mutable_snake = copy_array(snake)
+ next_coordinates = next_coordinates(direction,
+ extract_last_snake_coordinates(mutable_snake))
+ if dimensions[:width] >= next_coordinates[0] or
+ dimensions[:height] >= next_coordinates[1] or
+ mutable_snake.any? {|coordinate| coordinate == next_coordinates }
+ return true
+ end
+ false
+end
+
+def danger?(snake, direction, dimensions)
+ mutable_snake = move(snake, direction)
+ points = next_coordinates(direction,
+ mutable_snake[mutable_snake.length - 1])
+ already_in_snake = snake.any? {
+ |coordinate| coordinate == points
+ }
+ out_scope = points[0] > dimensions[:width] or points[1] > dimensions[:height]
+ already_in_snake or out_scope
+end

Значи знам, че последната е грешна :) просто исках feedback, понеже съм я писал от горе, от долу и ще я поправя малко де :)

Имам един въпрос във връзка с return, когато не става много ясно от метода какво се връща, ок ли е да го ползваме ?

Освен това, понеже изискване беше да не променяме аргументите, аз го разбирам, че трябва да правим копие на референтният аргумент, примерно Snake и да боравим с неги, тоест да си имаме друга променлива, която да сочи към друго място в паметта и да боравим с този обект, а първоначалният въобще да не го пипаме, може ли малко feedback и тук ? :) Ами това е, мерси.

Относно първият ти въпрос - Може ли да използваме return, ако не е ясно какво връща метода? - не съм сигурен, че те разбирам напълно. Какво имаш предвид?

  1. Методът има някакъв произволен елемент в него и не е детерминистичен? Тогава да - стига от името на метода да е достатъчно ясно, че това е така.
  2. Методът е някакви пълни спагети, и ми трябваше за да преобразувам тези спагети, които имам тук в тези спагети, който искам да подам там? Ако това е случаят, проблемът не е в самия return statement. Трябва да се помисли как да се оправи самия метод (или заобикалящите го такива).

За втория въпрос - правилно си го разбрал - трябва да се направи копие и да се мутира/връща него.


Малко насоки за подобрение на началната версия - главното нещо е, че доста преоткриваш колелото. Главната цел на тази задача беше да се поровите сред безкрайните методи на Array, понеже няма време (и смисъл) да ги минем един по един на лекциите. Разглеждайки документацията на Object, на Array и на Enumerable ще откриеш методи за

  • Правене на копие
  • Копие без първия елемент
  • Първи/последен/произволен елемент
  • Много други

Колекциите в Ruby имат utility методи за всякакви често срещани операции, не се ограничавай само до итерация и индексиране.


Поиграй си малко с имената:

  • move_helper не е ясно какво прави преди човек да прочете имплементацията.
  • mutable_snake е подвеждащо, първоначалната змия също е mutable.
  • Защо points като е само един point. Също от името не се разбира какво е значимото на този point.
  • coordinate звучи като само x координата или само y координата.
  • Не използвай еднобуквени имена освен в известни математически/физични формули.

Ще видиш, че доста от проблемите с имената ще изчезнат след като разглеждаш наличните методи.


Още идеи:

  • Опитай се да измислиш как можеш да имплементираш next_coordinates без да изброяваш всеки отделен случай.
  • Малко проблеми с whitespaces

Илия обнови решението на 17.10.2015 18:54 (преди над 9 години)

# -*- coding: utf-8 -*-
def move(snake, direction)
- snake_ready_for_change = copy_array(snake)
- snake_ready_for_change.shift()
- move_helper(snake_ready_for_change, direction,
- extract_last_snake_coordinates(snake_ready_for_change))
+ mutable_snake = snake.clone
+ mutable_snake.shift()
+ extract_new_snake(mutable_snake, direction,
+ extract_snake_last_coordinates(mutable_snake))
end
-def extract_last_snake_coordinates(snake)
+def extract_snake_last_coordinates(snake)
next_x = snake[snake.length - 1][0]
next_y = snake[snake.length - 1][1]
[next_x, next_y]
end
def next_coordinates(direction, last_coordinates)
if direction == [0, 1]
last_coordinates[1] += 1
elsif direction == [0, -1]
last_coordinates[1] -= 1
elsif direction == [1, 0]
last_coordinates[0] += 1
else
last_coordinates[0] -= 1
end
last_coordinates
end
-def move_helper(snake, direction, last_coordinates)
- next_coordinates = next_coordinates(direction, last_coordinates)
- snake.push(next_coordinates)
- return snake
+def extract_new_snake(snake, direction, last_coordinates)
+ snake.push(next_coordinates(direction, last_coordinates))
+ snake
end
-def copy_array(array)
- result = []
- array.map { |each| result.push(each) }
- return result
-end
-
def grow(snake, direction)
- snake_ready_for_change = copy_array(snake)
- next_x = snake_ready_for_change[snake_ready_for_change.length - 1][0]
- next_y = snake_ready_for_change[snake_ready_for_change.length - 1][1]
-
- move_helper(snake_ready_for_change, direction, [next_x, next_y])
+ mutable_snake = snake.clone
+ next_x = mutable_snake[mutable_snake.length - 1][0]
+ next_y = mutable_snake[mutable_snake.length - 1][1]
+ extract_new_snake(mutable_snake, direction, [next_x, next_y])
end
def new_food(food, snake, dimensions)
r = Random.new
random_coordinates = [r.rand(1..dimensions[:width]),
r.rand(1..dimensions[:height])]
- collapse_coordinate = snake.select { |each| each == random_coordinates }
- if collapse_coordinate.length == 0 and random_coordinates != food
+ collapse_coordinates = snake.select { |each| each == random_coordinates }
+ if collapse_coordinates.length == 0 and random_coordinates != food
return random_coordinates
- else
- new_food(food, snake, dimensions)
+ end
+ new_food(food, snake, dimensions)
end
-end
-def set_up_mutable_snake(snake)
- snake_ready_for_change = copy_array(snake)
- snake_ready_for_change.shift()
- next_x = snake_ready_for_change[snake_ready_for_change.length - 1][0]
- next_y = snake_ready_for_change[snake_ready_for_change.length - 1][1]
- [next_x, next_y]
-end
-
def obstacle_ahead?(snake, direction, dimensions)
- mutable_snake = copy_array(snake)
- next_coordinates = next_coordinates(direction,
- extract_last_snake_coordinates(mutable_snake))
- if dimensions[:width] >= next_coordinates[0] or
- dimensions[:height] >= next_coordinates[1] or
- mutable_snake.any? {|coordinate| coordinate == next_coordinates }
+ mutable_snake = snake.clone
+ future_coordinates = next_coordinates(direction,
+ extract_snake_last_coordinates(mutable_snake))
+ if dimensions[:width] <= future_coordinates[0] or
+ dimensions[:height] <= future_coordinates[1] or
+ mutable_snake.any? {|coordinates| coordinates == future_coordinates }
return true
end
false
end
def danger?(snake, direction, dimensions)
- mutable_snake = move(snake, direction)
- points = next_coordinates(direction,
+ snake_move_ahead = move(snake, direction)
- mutable_snake[mutable_snake.length - 1])
+ future_coordinates = next_coordinates(direction,
- already_in_snake = snake.any? {
+ extract_snake_last_coordinates(snake_move_ahead))
- |coordinate| coordinate == points
+ obstacle_ahead?(snake_move_ahead, direction,
- }
+ dimensions)
- out_scope = points[0] > dimensions[:width] or points[1] > dimensions[:height]
+end
- already_in_snake or out_scope
-end

Илия обнови решението на 18.10.2015 11:05 (преди над 9 години)

-# -*- coding: utf-8 -*-
-
def move(snake, direction)
mutable_snake = snake.clone
mutable_snake.shift()
extract_new_snake(mutable_snake, direction,
extract_snake_last_coordinates(mutable_snake))
end
def extract_snake_last_coordinates(snake)
next_x = snake[snake.length - 1][0]
next_y = snake[snake.length - 1][1]
[next_x, next_y]
end
def next_coordinates(direction, last_coordinates)
if direction == [0, 1]
last_coordinates[1] += 1
elsif direction == [0, -1]
last_coordinates[1] -= 1
elsif direction == [1, 0]
last_coordinates[0] += 1
else
last_coordinates[0] -= 1
end
last_coordinates
end
def extract_new_snake(snake, direction, last_coordinates)
snake.push(next_coordinates(direction, last_coordinates))
snake
end
def grow(snake, direction)
mutable_snake = snake.clone
next_x = mutable_snake[mutable_snake.length - 1][0]
next_y = mutable_snake[mutable_snake.length - 1][1]
extract_new_snake(mutable_snake, direction, [next_x, next_y])
end
def new_food(food, snake, dimensions)
r = Random.new
random_coordinates = [r.rand(1..dimensions[:width]),
r.rand(1..dimensions[:height])]
collapse_coordinates = snake.select { |each| each == random_coordinates }
if collapse_coordinates.length == 0 and random_coordinates != food
return random_coordinates
end
new_food(food, snake, dimensions)
end
def obstacle_ahead?(snake, direction, dimensions)
mutable_snake = snake.clone
future_coordinates = next_coordinates(direction,
extract_snake_last_coordinates(mutable_snake))
if dimensions[:width] <= future_coordinates[0] or
dimensions[:height] <= future_coordinates[1] or
mutable_snake.any? {|coordinates| coordinates == future_coordinates }
return true
end
false
end
def danger?(snake, direction, dimensions)
snake_move_ahead = move(snake, direction)
- future_coordinates = next_coordinates(direction,
- extract_snake_last_coordinates(snake_move_ahead))
obstacle_ahead?(snake_move_ahead, direction,
dimensions)
-end
+end