Решение на Втора задача от Димитър Терзиев

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

Към профила на Димитър Терзиев

Резултати

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

Код

def destination(snake_head, direction)
[snake_head[0] + direction[0], snake_head[1] + direction[1]]
end
def move(snake, direction)
snake.drop(1).push(destination(snake.last, direction))
end
def grow(snake, direction)
snake + [destination(snake.last, direction)]
end
def new_food(food, snake, dimensions)
new_food = [rand(dimensions[:width]), rand(dimensions[:height])]
new_food = [rand(dimensions[:width]), rand(dimensions[:height])] while
snake.include?(new_food) || food.include?(new_food)
new_food
end
def obstacle_ahead?(snake, direction, dimensions)
next_head = destination(snake.last, direction)
no_overlap = move(snake, direction).uniq.length == snake.length
!(next_head.first.between?(0, dimensions[:width] - 1) &&
next_head.last.between?(0, dimensions[:height] - 1) && no_overlap)
end
def danger?(snake, direction, dimensions)
obstacle_ahead?(snake, direction, dimensions) ||
obstacle_ahead?(move(snake, direction), direction, dimensions)
end

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

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

Failures:

  1) #obstacle_ahead? returns true if snake body ahead
     Failure/Error: expect(
       
       expected: true
            got: false
       
       (compared using ==)
     # /tmp/d20151026-15631-1t6g2rt/spec.rb:83: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.0146 seconds
20 examples, 1 failure

Failed examples:

rspec /tmp/d20151026-15631-1t6g2rt/spec.rb:82 # #obstacle_ahead? returns true if snake body ahead

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

Димитър обнови решението на 15.10.2015 10:45 (преди над 9 години)

+dimensions = {width: 10, height: 10}
+
+def get_destination(snake_head, direction)
+ snake_head.zip(direction).map{ |dimension| dimension.inject(:+) }
+end
+
+def move(snake, direction)
+ snake.drop(1).push(get_destination(snake.last, direction))
+end
+
+def grow(snake, direction)
+ snake + [get_destination(snake.last, direction)]
+end
+
+def new_food(food, snake, dimensions)
+ new_food = [rand(dimensions[:width]), rand(dimensions[:height])] while
+ snake.include?(new_food) || food.include?(new_food) || new_food.nil?
+ new_food
+end
+
+def obstacle_ahead?(snake, direction, dimensions)
+ x = get_destination(snake.last, direction)
+ !(x.first.between?(0, dimensions[:width] - 1) &&
+ x.last.between?(0, dimensions[:height] - 1))
+end
+
+def danger?(snake, direction, dimensions)
+ obstacle_ahead?(snake, direction.map{|dimension| dimension * 3}, dimensions)
+end

Димитър обнови решението на 16.10.2015 19:48 (преди над 9 години)

dimensions = {width: 10, height: 10}
def get_destination(snake_head, direction)
snake_head.zip(direction).map{ |dimension| dimension.inject(:+) }
end
def move(snake, direction)
snake.drop(1).push(get_destination(snake.last, direction))
end
def grow(snake, direction)
snake + [get_destination(snake.last, direction)]
end
def new_food(food, snake, dimensions)
new_food = [rand(dimensions[:width]), rand(dimensions[:height])] while
snake.include?(new_food) || food.include?(new_food) || new_food.nil?
new_food
end
def obstacle_ahead?(snake, direction, dimensions)
x = get_destination(snake.last, direction)
+ no_overlap = move(snake, direction).uniq.length == snake.length
!(x.first.between?(0, dimensions[:width] - 1) &&
- x.last.between?(0, dimensions[:height] - 1))
+ x.last.between?(0, dimensions[:height] - 1) && no_overlap)
end
def danger?(snake, direction, dimensions)
- obstacle_ahead?(snake, direction.map{|dimension| dimension * 3}, dimensions)
+ current_snake = snake.dup
+ danger = false
+ 2.times do
+ current_snake = move(current_snake, direction)
+ danger |= obstacle_ahead?(current_snake, direction, dimensions)
+ end
+ danger
end

Няколко идеи:

  • Предполагам дефиницията на първия ред е останала от когато си експериментирал нещо. На нас не ни е нужна, не я включвай в решението.
  • Имплементацията на get_destination е малко overkill. Не е напълно задължително да е one-liner. Искаше да постигнеш просто [x1 + y1, x2 + y2].
  • Дори да игнорираме дребния проблем с детерминистичността на new_food, обсъден във форумите, има още нещо. Зачуди ли с е как работи new_food.nil?, след като преди първата итерация не си инициализирал променливата? Ако напишеш new_food.nil? в irb ще получиш NameError. Причината да работи с постфиксния синтаксис е имплементационен детайл свързан с начина, по който се интерпретират редовете. Не е част от спецификацията на езика. Може да се промени в бъдеще и добавя +1 wtf за всеки, който чете кода. :)
  • Имплементацията на danger? изглежда прекалено итеративна. Нямаше ли да е по-кратко и ясно да провериш дали има obstacle_ahead? или obstacle_ahead? с мръдналата змия.
  • Откъм имена - не използвай еднобуквени такива, освен в известни математически/физични формули. Замисли се какво значи въпросната стойност в контекста на текущата задача (например следваща позиция). Избягвай да пишеш get_x/set_x в Ruby. destination носи същата информация, която и get_destination.

Btw твоето решение е първото, което виждам с no_overlap идеята. Харесва ми.

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

-dimensions = {width: 10, height: 10}
-
-def get_destination(snake_head, direction)
- snake_head.zip(direction).map{ |dimension| dimension.inject(:+) }
+def destination(snake_head, direction)
+ [snake_head[0] + direction[0], snake_head[1] + direction[1]]
end
def move(snake, direction)
- snake.drop(1).push(get_destination(snake.last, direction))
+ snake.drop(1).push(destination(snake.last, direction))
end
def grow(snake, direction)
- snake + [get_destination(snake.last, direction)]
+ snake + [destination(snake.last, direction)]
end
def new_food(food, snake, dimensions)
+ new_food = [rand(dimensions[:width]), rand(dimensions[:height])]
new_food = [rand(dimensions[:width]), rand(dimensions[:height])] while
- snake.include?(new_food) || food.include?(new_food) || new_food.nil?
+ snake.include?(new_food) || food.include?(new_food)
new_food
end
def obstacle_ahead?(snake, direction, dimensions)
- x = get_destination(snake.last, direction)
+ next_head = destination(snake.last, direction)
no_overlap = move(snake, direction).uniq.length == snake.length
- !(x.first.between?(0, dimensions[:width] - 1) &&
- x.last.between?(0, dimensions[:height] - 1) && no_overlap)
+ !(next_head.first.between?(0, dimensions[:width] - 1) &&
+ next_head.last.between?(0, dimensions[:height] - 1) && no_overlap)
end
def danger?(snake, direction, dimensions)
- current_snake = snake.dup
- danger = false
- 2.times do
- current_snake = move(current_snake, direction)
- danger |= obstacle_ahead?(current_snake, direction, dimensions)
- end
- danger
+ obstacle_ahead?(snake, direction, dimensions) ||
+ obstacle_ahead?(move(snake, direction), direction, dimensions)
end