Решение на Втора задача от Станимир Богданов

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

Към профила на Станимир Богданов

Резултати

  • 6 точки от тестове
  • 0 бонус точки
  • 6 точки общо
  • 20 успешни тест(а)
  • 0 неуспешни тест(а)

Код

def get_next_head_position(snake, direction)
[snake.last, direction].transpose.map { |x| x.reduce(:+) }
end
def grow(snake, direction)
snake.map { |item| item.dup } + [get_next_head_position(snake, direction)]
end
def move(snake, direction)
grow(snake, direction).drop(1)
end
def out_of_bounds?(x, y, dimensions)
x < 0 or x >= dimensions[:width] or y < 0 or y >= dimensions[:height]
end
def generate_fruit(dimensions)
[rand(dimensions[:width]), rand(dimensions[:height])]
end
def fruit_position_valid?(fruit, food, snake, dimensions)
on_snake = snake.include?(fruit)
on_food = food.include?(fruit)
out_of_bounds = out_of_bounds?(*fruit, dimensions)
not (on_snake or on_food or out_of_bounds)
end
def new_food(food, snake, dimensions)
fruit = generate_fruit(dimensions)
until fruit_position_valid?(fruit, food, snake, dimensions)
fruit = generate_fruit(dimensions)
end
fruit
end
def obstacle_ahead?(snake, direction, dimensions)
next_head = get_next_head_position(snake, direction)
ate_self = snake.include?(next_head)
out_of_bounds?(*next_head, dimensions) or ate_self
end
def danger?(snake, direction, dimensions)
dead_on_first_move = obstacle_ahead?(snake, direction, dimensions)
moved_snake = move(snake, direction)
dead_on_second_move = obstacle_ahead?(moved_snake, direction, dimensions)
dead_on_first_move or dead_on_second_move
end

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

....................

Finished in 0.01469 seconds
20 examples, 0 failures

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

Станимир обнови решението на 14.10.2015 13:46 (преди над 9 години)

+# Ще съм благодарен на hint как да напиша new_food по-елегантно
+# без да вдигам броя nest-вания :)
+
+def get_next_head_position(snake, direction)
+ [snake.last, direction].transpose.map { |x| x.reduce(:+) }
+end
+
+def grow(snake, direction)
+ snake + [get_next_head_position(snake, direction)]
+end
+
+def move(snake, direction)
+ grow(snake, direction).drop(1)
+end
+
+def out_of_bounds?(x, y, dimensions)
+ x < 0 or x >= dimensions[:width] or y < 0 or y >= dimensions[:height]
+end
+
+def generate_fruit(dimensions)
+ [rand(dimensions[:width]), rand(dimensions[:height])]
+end
+
+def fruit_position_valid?(fruit, food, snake, dimensions)
+ on_snake = snake.include?(fruit)
+ on_food = food.include?(fruit)
+ out_of_bounds = out_of_bounds?(*fruit, dimensions)
+
+ not on_snake and not on_food and not out_of_bounds
+end
+
+def new_food(food, snake, dimensions)
+ fruit = generate_fruit(dimensions)
+ until fruit_position_valid?(fruit, food, snake, dimensions)
+ fruit = generate_fruit(dimensions)
+ end
+ fruit
+end
+
+def obstacle_ahead?(snake, direction, dimensions)
+ next_head = get_next_head_position(snake, direction)
+ ate_self = snake.include?(next_head)
+
+ out_of_bounds?(*next_head, dimensions) or ate_self
+end
+
+def danger?(snake, direction, dimensions)
+ dead_on_first_move = obstacle_ahead?(snake, direction, dimensions)
+ moved_snake = move(snake, direction)
+ dead_on_second_move = obstacle_ahead?(moved_snake, direction, dimensions)
+
+ dead_on_first_move or dead_on_second_move
+end

можеш да пренапишеш not on_snake and not on_food and not out_of_bounds като not(on_snake or on_food or out_of_bounds)

За new_food може да се пробваш с някаква комбинаторика, ако много искаш да избегнеш цикъла.

snake в grow остава в изходния резултат. Това значи, че някой, който викне grow, може да промени оригиналния snake масив. Помисли как да не се стигне дотам

snake = [[1,1],[2,1],[3,1]]

p grow(snake, [1,0]) # => [[1, 1], [2, 1], [3, 1], [4, 1]]

p snake # => [[1, 1], [2, 1], [3, 1]]

p grow(snake, [0,1]) # => [[1, 1], [2, 1], [3, 1], [3, 2]]

p snake # => [[1, 1], [2, 1], [3, 1]]

Аз ли пропускам нещо, но не виждам snake да се променя в grow.

От документацията за Array#+ "Concatenation — Returns a new array built by concatenating the two arrays together to produce a third array."

snake = [[2, 1], [2, 2]]
direction = [1, 0]

new_snake = grow(snake, direction)
p snake
p new_snake

snake[0][0] = 'WTF'
p snake
p new_snake

Копираш мястото на snake, но не и елементите в него, new_snake[0] сочи на същото място, където и snake[0].

По принцип в задачата се иска само да не mute-ваш аргументите в своите функции, така че решението ти е ок в този смисъл(но е хубаво да имаш в предвид това поведение. Ако ти се наложи някой път да се предпазиш от такова бъркане в масива ти, може да ползваш dup и clone.

Станимир обнови решението на 19.10.2015 10:08 (преди над 9 години)

-# Ще съм благодарен на hint как да напиша new_food по-елегантно
-# без да вдигам броя nest-вания :)
-
def get_next_head_position(snake, direction)
[snake.last, direction].transpose.map { |x| x.reduce(:+) }
end
def grow(snake, direction)
- snake + [get_next_head_position(snake, direction)]
+ snake.map { |item| item.dup } + [get_next_head_position(snake, direction)]
end
def move(snake, direction)
grow(snake, direction).drop(1)
end
def out_of_bounds?(x, y, dimensions)
x < 0 or x >= dimensions[:width] or y < 0 or y >= dimensions[:height]
end
def generate_fruit(dimensions)
[rand(dimensions[:width]), rand(dimensions[:height])]
end
def fruit_position_valid?(fruit, food, snake, dimensions)
on_snake = snake.include?(fruit)
on_food = food.include?(fruit)
out_of_bounds = out_of_bounds?(*fruit, dimensions)
- not on_snake and not on_food and not out_of_bounds
+ not (on_snake or on_food or out_of_bounds)
end
def new_food(food, snake, dimensions)
fruit = generate_fruit(dimensions)
until fruit_position_valid?(fruit, food, snake, dimensions)
fruit = generate_fruit(dimensions)
end
fruit
end
def obstacle_ahead?(snake, direction, dimensions)
next_head = get_next_head_position(snake, direction)
ate_self = snake.include?(next_head)
out_of_bounds?(*next_head, dimensions) or ate_self
end
def danger?(snake, direction, dimensions)
dead_on_first_move = obstacle_ahead?(snake, direction, dimensions)
moved_snake = move(snake, direction)
dead_on_second_move = obstacle_ahead?(moved_snake, direction, dimensions)
dead_on_first_move or dead_on_second_move
end