Решение на Втора задача от Адриана Стефанова

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

Към профила на Адриана Стефанова

Резултати

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

Код

def move(snake, direction)
moved_snake = snake.clone
moved_snake.delete_at(0)
add_new_head(moved_snake, direction)
end
def grow(snake, direction)
add_new_head(snake.clone, direction)
end
def random_place(dimensions)
[Random.rand(dimensions[:width]), Random.rand(dimensions[:height])]
end
def new_food(food, snake, dimensions)
busy = snake.clone
busy += food
free = Array.new(dimensions[:width] * dimensions[:height])
free.each_with_index {|free_item, i|
free[i] = [ (i/dimensions[:width]).floor , i%dimensions[:height] ]
}
remove_busy_spaces(free, busy)
free.sample
end
def remove_busy_spaces(free, busy)
busy.each {|busy_element|
free.delete_at(free.index(busy_element))
}
end
def obstacle_ahead?(snake, direction, dimensions)
moved_snake = move(snake, direction)
collision?(moved_snake, direction, dimensions)
end
def danger?(snake, direction, dimensions)
moved_snake = move(snake, direction)
moved_snake = move(moved_snake, direction)
collision?(moved_snake, direction, dimensions)
end
def new_head(snake, direction)
current_head = snake.last.clone
[current_head.first + direction.first, current_head.last + direction.last]
end
def add_new_head(snake, direction)
snake << new_head(snake, direction)
end
def collision?(snake, direction, dimensions)
head = snake.last
snake_without_head = snake.clone.pop
x_out_of_bounds = head.first < 0 || head.first >= dimensions[:width]
y_out_of_bounds = head.last < 0 || head.last >= dimensions[:height]
x_out_of_bounds || y_out_of_bounds || snake_without_head.include?(head)
end

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

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

Failures:

  1) #move moves one-position-sized snake
     Failure/Error: expect(move([[2, 2]], [-1, 0])).to eq([[1, 2]])
     TypeError:
       can't clone NilClass
     # /tmp/d20151026-15631-e5rd0o/solution.rb:46:in `clone'
     # /tmp/d20151026-15631-e5rd0o/solution.rb:46:in `new_head'
     # /tmp/d20151026-15631-e5rd0o/solution.rb:51:in `add_new_head'
     # /tmp/d20151026-15631-e5rd0o/solution.rb:4:in `move'
     # /tmp/d20151026-15631-e5rd0o/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) #obstacle_ahead? returns true if snake body ahead
     Failure/Error: expect(
       
       expected: true
            got: false
       
       (compared using ==)
     # /tmp/d20151026-15631-e5rd0o/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.01468 seconds
20 examples, 2 failures

Failed examples:

rspec /tmp/d20151026-15631-e5rd0o/spec.rb:11 # #move moves one-position-sized snake
rspec /tmp/d20151026-15631-e5rd0o/spec.rb:82 # #obstacle_ahead? returns true if snake body ahead

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

Адриана обнови решението на 16.10.2015 10:34 (преди над 9 години)

+def move(snake, direction)
+ moved_snake = snake.clone
+ moved_snake.delete_at(0)
+ add_new_head(moved_snake, direction)
+end
+
+def grow(snake, direction)
+ grown_snake = snake.clone
+ add_new_head(grown_snake, direction)
+end
+
+def new_food(food, snake, dimensions)
+ busy = snake.clone
+ busy += food
+
+ possible_new_food = get_random_place(dimensions)
+
+ while busy.include? possible_new_food do
+ possible_new_food = get_random_place(dimensions)
+ end
+
+ possible_new_food
+end
+
+def obstacle_ahead?(snake, direction, dimensions)
+ new_snake = snake.clone
+ out_of_bounds(new_snake, direction, dimensions)
+end
+
+def danger?(snake, direction, dimensions)
+ new_snake = snake.clone
+ new_snake = add_new_head(snake, direction)
+ out_of_bounds(new_snake, direction, dimensions)
+end
+
+def get_new_head(snake, direction)
+ current_head = snake[-1].clone
+ new_head = current_head
+
+ new_head.zip(direction).map {|element| element.inject(:+)}
+end
+
+def add_new_head(snake, direction)
+ snake << get_new_head(snake, direction)
+end
+
+def get_random_place(dimensions)
+ [Random.rand(dimensions[:width]), Random.rand(dimensions[:height])]
+end
+
+def out_of_bounds(snake, direction, dimensions)
+ head = get_new_head(snake, direction)
+
+ x_out_of_bounds = head[0] < 0 || head[0] >= dimensions[:width]
+ y_out_of_bounds = head[1] < 0 || head[1] >= dimensions[:height]
+ snake.include?(head) || x_out_of_bounds || y_out_of_bounds
+end

Забелязвам common pattern в решението ти. Правиш някои неща ненужно постъпково. Като резултат решението ти става малко по-дълго и ти трябват малко повече променливи, за които да мислиш имена. И си им дала имена, които ще отразяват съдържанието им след края на изпълнението, не на мястото, където се срещат за първи път. Например:

grown_snake = snake.clone

Тук grown_snake всъщност не е grown. Става grown на следващия ред. По принцип би следвало да я кръстиш snake_duplicate. А тук можеш изцяло да избегнеш променливата, като направиш целия grow one-liner:

add_new_head(snake.clone, direction)

Някои други идеи:

  • danger? трябваше да проверява за опасност след 1 или два хода.
  • new_head.zip(direction).map {|element| element.inject(:+)} e overkill. Искаше просто [x1 + y1, x2 + y2]. Не е нужно да се ограничаваш до един ред.
  • Във форума сме обсъдили малко темата с generate_new_position until position.satisfies?(condition).
  • Има методи Array#first/Array#last, изглеждат по-ясно от индексирането.
  • do-то на while е излишно.

Още неща откъм имена:

  • out_of_bounds е леко объркващо. От името очаквах да проверява дали текущата змия е извън ограниченията. Без да я мърда и без да гледа дали се е самозахапала. head ми звучи като текущата, не "мръдналата" глава.
  • Избягвай get_x/set_x имена в Ruby. get_new_head като име не дава друга информация, която вече не се съдържа в new_head. В случая ще имаш колизия с имената, съответно би следвало да помислиш за нещо друго.

Адриана обнови решението на 18.10.2015 17:38 (преди над 9 години)

def move(snake, direction)
moved_snake = snake.clone
moved_snake.delete_at(0)
add_new_head(moved_snake, direction)
end
def grow(snake, direction)
- grown_snake = snake.clone
- add_new_head(grown_snake, direction)
+ add_new_head(snake.clone, direction)
end
+
+def random_place(dimensions)
+ [Random.rand(dimensions[:width]), Random.rand(dimensions[:height])]
+end
+
def new_food(food, snake, dimensions)
busy = snake.clone
busy += food
- possible_new_food = get_random_place(dimensions)
+ free = Array.new(dimensions[:width] * dimensions[:height])
+ free.each_with_index {|free_item, i|
+ free[i] = [ (i/dimensions[:width]).floor , i%dimensions[:height] ]
+ }
- while busy.include? possible_new_food do
- possible_new_food = get_random_place(dimensions)
- end
+ busy.each {|busy_element|
+ free.delete_at(free.index(busy_element))
+ }
- possible_new_food
+ free.sample
end
def obstacle_ahead?(snake, direction, dimensions)
- new_snake = snake.clone
- out_of_bounds(new_snake, direction, dimensions)
+ moved_snake = move(snake, direction)
+ collision?(moved_snake, direction, dimensions)
end
def danger?(snake, direction, dimensions)
- new_snake = snake.clone
- new_snake = add_new_head(snake, direction)
- out_of_bounds(new_snake, direction, dimensions)
+ moved_snake = move(snake, direction)
+ moved_snake = move(moved_snake, direction)
+ collision?(moved_snake, direction, dimensions)
end
-def get_new_head(snake, direction)
- current_head = snake[-1].clone
- new_head = current_head
-
- new_head.zip(direction).map {|element| element.inject(:+)}
+def new_head(snake, direction)
+ current_head = snake.last.clone
+ [current_head.first + direction.first, current_head.last + direction.last]
end
def add_new_head(snake, direction)
- snake << get_new_head(snake, direction)
+ snake << new_head(snake, direction)
end
-def get_random_place(dimensions)
- [Random.rand(dimensions[:width]), Random.rand(dimensions[:height])]
-end
-def out_of_bounds(snake, direction, dimensions)
- head = get_new_head(snake, direction)
+def collision?(snake, direction, dimensions)
+ head = snake.last
+ snake_without_head = snake.clone.pop
- x_out_of_bounds = head[0] < 0 || head[0] >= dimensions[:width]
- y_out_of_bounds = head[1] < 0 || head[1] >= dimensions[:height]
- snake.include?(head) || x_out_of_bounds || y_out_of_bounds
+ x_out_of_bounds = head.first < 0 || head.first >= dimensions[:width]
+ y_out_of_bounds = head.last < 0 || head.last >= dimensions[:height]
+
+ x_out_of_bounds || y_out_of_bounds || snake_without_head.include?(head)
end

Адриана обнови решението на 19.10.2015 14:18 (преди над 9 години)

def move(snake, direction)
moved_snake = snake.clone
moved_snake.delete_at(0)
add_new_head(moved_snake, direction)
end
def grow(snake, direction)
add_new_head(snake.clone, direction)
end
-
def random_place(dimensions)
[Random.rand(dimensions[:width]), Random.rand(dimensions[:height])]
end
def new_food(food, snake, dimensions)
busy = snake.clone
busy += food
free = Array.new(dimensions[:width] * dimensions[:height])
free.each_with_index {|free_item, i|
free[i] = [ (i/dimensions[:width]).floor , i%dimensions[:height] ]
}
+ remove_busy_spaces(free, busy)
+ free.sample
+end
+
+def remove_busy_spaces(free, busy)
busy.each {|busy_element|
free.delete_at(free.index(busy_element))
}
-
- free.sample
end
def obstacle_ahead?(snake, direction, dimensions)
moved_snake = move(snake, direction)
collision?(moved_snake, direction, dimensions)
end
def danger?(snake, direction, dimensions)
moved_snake = move(snake, direction)
moved_snake = move(moved_snake, direction)
collision?(moved_snake, direction, dimensions)
end
def new_head(snake, direction)
current_head = snake.last.clone
[current_head.first + direction.first, current_head.last + direction.last]
end
def add_new_head(snake, direction)
snake << new_head(snake, direction)
end
-
def collision?(snake, direction, dimensions)
head = snake.last
snake_without_head = snake.clone.pop
x_out_of_bounds = head.first < 0 || head.first >= dimensions[:width]
y_out_of_bounds = head.last < 0 || head.last >= dimensions[:height]
x_out_of_bounds || y_out_of_bounds || snake_without_head.include?(head)
-end
+end