Решение на Втора задача от Петър Иванов

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

Към профила на Петър Иванов

Резултати

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

Код

def get_position_ahead(snake_head, direction)
snake_head.map.with_index { |m, i| m + direction[i] }
end
def move(snake, direction)
snake.drop(1) << get_position_ahead(snake[-1], direction)
end
def grow(snake, direction)
snake.drop(0) << get_position_ahead(snake[-1], direction)
end
def new_food(food, snake, dimensions)
taken_fields = food + snake
widths = (0..dimensions[:width] - 1).to_a
heights = (0..dimensions[:height] - 1).to_a
all_fields = widths.product(heights)
all_fields.select { |v| !taken_fields.include?(v) }.sample
end
def position_in_bounds?(new_snake, dimensions)
((new_snake.first >= dimensions[:width] or new_snake.first < 0) or
(new_snake.last >= dimensions[:height] or new_snake.last < 0)) ? true : false
end
def obstacle_ahead?(snake, direction, dimensions)
new_position = get_position_ahead(snake[-1], direction)
(snake.include?(new_position) or
position_in_bounds?(new_position, dimensions)) ? true : false
end
def danger?(snake, direction, dimensions)
new_position_1 = get_position_ahead(snake[-1], direction)
new_position_2 = get_position_ahead(new_position_1, direction)
(position_in_bounds?(new_position_1, dimensions) or
position_in_bounds?(new_position_2, dimensions)) ? true : false
end

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

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

Finished in 0.02145 seconds
20 examples, 0 failures

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

Петър обнови решението на 16.10.2015 12:28 (преди над 9 години)

+def move(snake, direction)
+ new_snake = snake.dup
+ new_snake.delete_at(0)
+ new_snake << new_snake[-1].map.with_index { |m, i| m + direction[i] }
+end
+
+def grow(snake, direction)
+ new_snake = snake.dup
+ new_snake << new_snake[-1].map.with_index { |m, i| m + direction[i] }
+end
+
+def new_food(food, snake, dimensions)
+ temp = food + snake
+ width_arr = (0..dimensions[:width] - 1).to_a
+ height_arr = (0..dimensions[:height] - 1).to_a
+ dimensions_arr = width_arr.product(height_arr)
+ new_food_x_y = dimensions_arr.select { |v| !temp.include?(v) }.sample
+end
+
+def check_next_position(new_snake, dimensions)
+ if new_snake.first >= dimensions[:width] or new_snake.first < 0
+ true
+ elsif new_snake.last >= dimensions[:height] or new_snake.last < 0
+ true
+ else
+ false
+ end
+end
+
+def obstacle_ahead?(snake, direction, dimensions)
+ new_x_y = snake[-1].map.with_index { |m, i| m + direction[i] }
+ p check_next_position(new_x_y, dimensions)
+ if snake.include?(new_x_y) or check_next_position(new_x_y, dimensions)
+ true
+ else
+ false
+ end
+end
+
+def danger?(snake, direction, dimensions)
+ new_x_y_1 = snake[-1].map.with_index { |m, i| m + direction[i] }
+ new_x_y_2 = new_x_y_1.map.with_index { |m, i| m + direction[i] }
+ if check_next_position(new_x_y_1, dimensions) or
+ check_next_position(new_x_y_2, dimensions)
+ true
+ else
+ false
+ end
+end

Петър обнови решението на 16.10.2015 13:33 (преди над 9 години)

+def get_new_snake_x_y(snake_head, direction)
+ snake_head.map.with_index { |m, i| m + direction[i] }
+end
+
def move(snake, direction)
new_snake = snake.dup
new_snake.delete_at(0)
- new_snake << new_snake[-1].map.with_index { |m, i| m + direction[i] }
+ new_snake << get_new_snake_x_y(snake[-1], direction)
end
def grow(snake, direction)
new_snake = snake.dup
- new_snake << new_snake[-1].map.with_index { |m, i| m + direction[i] }
+ new_snake << get_new_snake_x_y(snake[-1], direction)
end
def new_food(food, snake, dimensions)
temp = food + snake
width_arr = (0..dimensions[:width] - 1).to_a
height_arr = (0..dimensions[:height] - 1).to_a
dimensions_arr = width_arr.product(height_arr)
new_food_x_y = dimensions_arr.select { |v| !temp.include?(v) }.sample
end
def check_next_position(new_snake, dimensions)
if new_snake.first >= dimensions[:width] or new_snake.first < 0
true
elsif new_snake.last >= dimensions[:height] or new_snake.last < 0
true
else
false
end
end
def obstacle_ahead?(snake, direction, dimensions)
- new_x_y = snake[-1].map.with_index { |m, i| m + direction[i] }
- p check_next_position(new_x_y, dimensions)
+ new_x_y = get_new_snake_x_y(snake[-1], direction)
if snake.include?(new_x_y) or check_next_position(new_x_y, dimensions)
true
else
false
end
end
def danger?(snake, direction, dimensions)
- new_x_y_1 = snake[-1].map.with_index { |m, i| m + direction[i] }
- new_x_y_2 = new_x_y_1.map.with_index { |m, i| m + direction[i] }
+ new_x_y_1 = get_new_snake_x_y(snake[-1], direction)
+ new_x_y_2 = get_new_snake_x_y(new_x_y_1, direction)
if check_next_position(new_x_y_1, dimensions) or
check_next_position(new_x_y_2, dimensions)
true
else
false
end
-end
+end

Извинявай, злощастно сме те пропуснали. Най-вероятно защото в списъка с всички решения, твоето има коментар и не сме видяли, че не е от нас. Ще се опитам да внимавам повече в бъдеще. Ето няколко насоки за подобрение:

  • snake_head.map.with_index { |m, i| m + direction[i] } е малко overkill, искаше просто [x1 + y1, x2 + y2].
  • Вероятно можеше да си направиш move one-liner, ако беше видял Array#drop. Подобно за grow - няма много смисъл от междинната променлива.
  • Последните три метода значително ще се опростят, ако замениш if x then true else false конструкциите с еквивалентното само x.

Главните забележки са откъм имена:

  • get_new_snake_x_y не е много ясно какво значи. Като правило, не използвай get_foo за имена в Ruby, не носи информация отвъд foo. Останалата част се чете като x и y на новата змия. Една идея по-ясно ще е координатите на новата змия. Но идва третия проблем - това всъщност са координатите на новата глава. Можеше да е просто new_head или position_ahead/next_square.
  • Не използвай temp за име на променлива. Не носи никаква информация за съдържанието. Винаги си задавай въпроса Какво значи тази стойност в домейна на решавания проблем?. Например тук можеше да я кръстиш taken (за заети полета).
  • Избягвай да слагаш типовете на обектите в имената (като width_arr). arr не е близко до домейна на проблема, а е имплементационен детайл. Също ще трябва и да сменяш името, ако после решиш да използваш друг тип. Ако си искал да държиш височини, вместо height_arr използвай heights.
  • Не използвай еднобуквени имена, освен в известни математически/физични формули. Ограничението символи на ред не е аргумент. :)
  • От check_next_position разбирам ще взема следващата позиция и ще проверя нещо за нея. Ти вече й подаваш следващата позиция, съотвено би следвало да е само check_position (проверява позицията, която й е подадена, а не следващата на тази, която е подадена). В Ruby конвенцията казва, че имената на предикатите трябва да завършват на ?. Можеше да си и малко по-ясен от check. Например position_in_bounds?.

Благодаря за насоките. Ще гледам занапред да си именовам променливите по-добре.

Относно get_new_x_y, исках просто да си поиграя с нещо по-различно и да се разръчкам.

Относно if x then true else false конструкцията, тя не се ли използва когато е one-line statement, тъй като при мен е multi-line, или поне така си мисля :D. Също така как е по-добре с (if/then/else/end) или с (?:) конструкцията.

Това с if x then true else false го казах примерно, ?: се предпочита - да (ако няма странични ефекти). Многоредово, принципът е същият:

if some_boolean_value
  true
else
  false
end

E напълно еквивалентно на просто some_boolean_value.

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

-def get_new_snake_x_y(snake_head, direction)
+def get_position_ahead(snake_head, direction)
snake_head.map.with_index { |m, i| m + direction[i] }
end
def move(snake, direction)
- new_snake = snake.dup
- new_snake.delete_at(0)
- new_snake << get_new_snake_x_y(snake[-1], direction)
+ snake.drop(1) << get_position_ahead(snake[-1], direction)
end
def grow(snake, direction)
- new_snake = snake.dup
- new_snake << get_new_snake_x_y(snake[-1], direction)
+ snake.drop(0) << get_position_ahead(snake[-1], direction)
end
def new_food(food, snake, dimensions)
- temp = food + snake
- width_arr = (0..dimensions[:width] - 1).to_a
- height_arr = (0..dimensions[:height] - 1).to_a
- dimensions_arr = width_arr.product(height_arr)
- new_food_x_y = dimensions_arr.select { |v| !temp.include?(v) }.sample
+ taken_fields = food + snake
+ widths = (0..dimensions[:width] - 1).to_a
+ heights = (0..dimensions[:height] - 1).to_a
+ all_fields = widths.product(heights)
+ all_fields.select { |v| !taken_fields.include?(v) }.sample
end
-def check_next_position(new_snake, dimensions)
- if new_snake.first >= dimensions[:width] or new_snake.first < 0
- true
- elsif new_snake.last >= dimensions[:height] or new_snake.last < 0
- true
- else
- false
- end
+def position_in_bounds?(new_snake, dimensions)
+ ((new_snake.first >= dimensions[:width] or new_snake.first < 0) or
+ (new_snake.last >= dimensions[:height] or new_snake.last < 0)) ? true : false
end
def obstacle_ahead?(snake, direction, dimensions)
- new_x_y = get_new_snake_x_y(snake[-1], direction)
- if snake.include?(new_x_y) or check_next_position(new_x_y, dimensions)
- true
- else
- false
- end
+ new_position = get_position_ahead(snake[-1], direction)
+ (snake.include?(new_position) or
+ position_in_bounds?(new_position, dimensions)) ? true : false
end
def danger?(snake, direction, dimensions)
- new_x_y_1 = get_new_snake_x_y(snake[-1], direction)
- new_x_y_2 = get_new_snake_x_y(new_x_y_1, direction)
+ new_position_1 = get_position_ahead(snake[-1], direction)
- if check_next_position(new_x_y_1, dimensions) or
+ new_position_2 = get_position_ahead(new_position_1, direction)
- check_next_position(new_x_y_2, dimensions)
+ (position_in_bounds?(new_position_1, dimensions) or
- true
+ position_in_bounds?(new_position_2, dimensions)) ? true : false
- else
+end
- false
- end
-end