Решение на Втора задача от Здравко Андонов

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

Към профила на Здравко Андонов

Резултати

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

Код

def position_ahead_of_snake(snake, direction, moves = 1)
[snake[-1][0] + moves * direction[0], snake[-1][1] + moves * direction[1]]
end
def grow(snake, direction)
snake.dup.push(position_ahead_of_snake(snake, direction))
end
def move(snake, direction)
snake[1..-1].push(position_ahead_of_snake(snake, direction))
end
def snake?(position, snake)
snake.include?(position)
end
def in_bounds?(position, dimensions)
position[0].between?(0, dimensions[:width] - 1) &&
position[1].between?(0, dimensions[:height] - 1)
end
def obstacle_ahead?(snake, direction, dimensions, moves = 1)
position = position_ahead_of_snake(snake, direction, moves)
!in_bounds?(position, dimensions) || snake?(position, snake)
end
def danger?(snake, direction, dimensions)
obstacles_in_one_move = obstacle_ahead?(snake, direction, dimensions)
obstacles_in_two_moves = obstacle_ahead?(snake, direction, dimensions, 2)
obstacles_in_one_move || obstacles_in_two_moves
end
def new_food(food, snake, dimensions)
valid_positions_x = (0...dimensions[:width]).to_a
valid_positions_y = (0...dimensions[:height]).to_a
valid_positions = valid_positions_x.product(valid_positions_y)
vacant_positions = valid_positions - food - snake
vacant_positions.sample
end

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

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

Finished in 0.01471 seconds
20 examples, 0 failures

История (5 версии и 6 коментара)

Здравко обнови решението на 13.10.2015 22:31 (преди над 9 години)

+def grow!(snake, direction)
+ snake.push([snake[-1][0] + direction[0], snake[-1][1] + direction[1]])
+end
+
+def grow(snake, direction)
+ grow!(Array.new(snake), direction)
+end
+
+def move(snake, direction)
+ shortened_snake = snake[1 .. -1]
+ grow!(shortened_snake, direction)
+end
+
+def food?(xs, ys, food)
+ not food.find_index([xs, ys]).nil?
+end
+
+def snake?(xs, ys, snake)
+ not snake.find_index([xs, ys]).nil?
+end
+
+def in_bounds?(xs, ys, dimensions)
+ xs >= 0 and xs < dimensions[:width] and ys >= 0 and ys < dimensions[:height]
+end
+
+def valid_and_vacant?(xs, ys, dimensions, snake, food = [])
+ in_bounds?(xs, ys, dimensions) and
+ not food?(xs, ys, food) and
+ not snake?(xs, ys, snake)
+end
+
+def new_food(food, snake, dimensions)
+ random_generator = Random.new
+ xs = random_generator.rand(dimensions[:width])
+ ys = random_generator.rand(dimensions[:height])
+ until valid_and_vacant?(xs, ys, dimensions, snake, food)
+ xs = random_generator.rand(dimensions[:width])
+ ys = random_generator.rand(dimensions[:height])
+ end
+ [xs, ys]
+end
+
+def obstacle_ahead?(snake, direction, dimensions, moves_count = 1)
+ xs = snake[-1][0] + moves_count * direction[0]
+ ys = snake[-1][1] + moves_count * direction[1]
+ not valid_and_vacant?(xs, ys, dimensions, snake)
+end
+
+def danger?(snake, direction, dimensions)
+ obstacles_in_one_move = obstacle_ahead?(snake, direction, dimensions)
+ obstacles_in_two_moves = obstacle_ahead?(snake, direction, dimensions, 2)
+ obstacles_in_one_move or obstacles_in_two_moves
+end

Генерирането на храната ми се вижда не добре написано, но не можах да измисля нищо по-смислено, което да отговаря на ограниченията. Освен това имам опционален параметър на функцията obstacle_ahead?, за да я преизползвам. Това проблем ли е, тъй като функцията ми приема не само аргументите от условието?

Здравко обнови решението на 14.10.2015 09:55 (преди над 9 години)

def grow!(snake, direction)
snake.push([snake[-1][0] + direction[0], snake[-1][1] + direction[1]])
end
def grow(snake, direction)
grow!(Array.new(snake), direction)
end
def move(snake, direction)
shortened_snake = snake[1 .. -1]
grow!(shortened_snake, direction)
end
def food?(xs, ys, food)
not food.find_index([xs, ys]).nil?
end
def snake?(xs, ys, snake)
not snake.find_index([xs, ys]).nil?
end
def in_bounds?(xs, ys, dimensions)
xs >= 0 and xs < dimensions[:width] and ys >= 0 and ys < dimensions[:height]
end
def valid_and_vacant?(xs, ys, dimensions, snake, food = [])
in_bounds?(xs, ys, dimensions) and
not food?(xs, ys, food) and
not snake?(xs, ys, snake)
end
def new_food(food, snake, dimensions)
random_generator = Random.new
xs = random_generator.rand(dimensions[:width])
ys = random_generator.rand(dimensions[:height])
until valid_and_vacant?(xs, ys, dimensions, snake, food)
- xs = random_generator.rand(dimensions[:width])
- ys = random_generator.rand(dimensions[:height])
+ xs += 1
+ ys = (ys + xs / dimensions[:width]) % dimensions[:height]
+ xs %= dimensions[:width]
end
[xs, ys]
end
def obstacle_ahead?(snake, direction, dimensions, moves_count = 1)
xs = snake[-1][0] + moves_count * direction[0]
ys = snake[-1][1] + moves_count * direction[1]
not valid_and_vacant?(xs, ys, dimensions, snake)
end
def danger?(snake, direction, dimensions)
obstacles_in_one_move = obstacle_ahead?(snake, direction, dimensions)
obstacles_in_two_moves = obstacle_ahead?(snake, direction, dimensions, 2)
obstacles_in_one_move or obstacles_in_two_moves
end

Здравко обнови решението на 15.10.2015 21:09 (преди над 9 години)

def grow!(snake, direction)
snake.push([snake[-1][0] + direction[0], snake[-1][1] + direction[1]])
end
def grow(snake, direction)
grow!(Array.new(snake), direction)
end
def move(snake, direction)
- shortened_snake = snake[1 .. -1]
+ shortened_snake = snake[1..-1]
grow!(shortened_snake, direction)
end
def food?(xs, ys, food)
not food.find_index([xs, ys]).nil?
end
def snake?(xs, ys, snake)
not snake.find_index([xs, ys]).nil?
end
def in_bounds?(xs, ys, dimensions)
xs >= 0 and xs < dimensions[:width] and ys >= 0 and ys < dimensions[:height]
end
def valid_and_vacant?(xs, ys, dimensions, snake, food = [])
in_bounds?(xs, ys, dimensions) and
not food?(xs, ys, food) and
not snake?(xs, ys, snake)
end
def new_food(food, snake, dimensions)
random_generator = Random.new
xs = random_generator.rand(dimensions[:width])
ys = random_generator.rand(dimensions[:height])
until valid_and_vacant?(xs, ys, dimensions, snake, food)
xs += 1
ys = (ys + xs / dimensions[:width]) % dimensions[:height]
xs %= dimensions[:width]
end
[xs, ys]
end
def obstacle_ahead?(snake, direction, dimensions, moves_count = 1)
xs = snake[-1][0] + moves_count * direction[0]
ys = snake[-1][1] + moves_count * direction[1]
not valid_and_vacant?(xs, ys, dimensions, snake)
end
def danger?(snake, direction, dimensions)
obstacles_in_one_move = obstacle_ahead?(snake, direction, dimensions)
obstacles_in_two_moves = obstacle_ahead?(snake, direction, dimensions, 2)
obstacles_in_one_move or obstacles_in_two_moves
end
  • Първо xs и ys не доста лоши имена за това, което правиш. Те са за масив, примерно в haskell имаш x:xs, т.е. първият елемент x и всичко друго xs - опашката.
  • Относно new_food аз бих търсил случаен елеменет от празните полета, а не случайно да попадна на празно поле.
  • За obstacle_ahead? по-добре си направи помощен метод, иначе сметката я правиш и в grow!.
  • Можеш и по-добре в food? и snake?
  • Идентацията в valid_and_vacant? не е ок.
  • Виж също тази тема във форума.
  • в danger? има бонус шпация

Здравко обнови решението на 16.10.2015 01:11 (преди над 9 години)

-def grow!(snake, direction)
- snake.push([snake[-1][0] + direction[0], snake[-1][1] + direction[1]])
+def position_ahead_of_snake(snake, direction, moves = 1)
+ [snake[-1][0] + moves * direction[0], snake[-1][1] + moves * direction[1]]
end
def grow(snake, direction)
- grow!(Array.new(snake), direction)
+ snake.dup.push(position_ahead_of_snake(snake, direction))
end
def move(snake, direction)
- shortened_snake = snake[1..-1]
- grow!(shortened_snake, direction)
+ grow(snake[1..-1], direction)
end
-def food?(xs, ys, food)
- not food.find_index([xs, ys]).nil?
+def food?(x, y, food)
+ food.include?([x, y])
end
-def snake?(xs, ys, snake)
- not snake.find_index([xs, ys]).nil?
+def snake?(x, y, snake)
+ snake.include?([x, y])
end
-def in_bounds?(xs, ys, dimensions)
- xs >= 0 and xs < dimensions[:width] and ys >= 0 and ys < dimensions[:height]
+def in_bounds?(x, y, dimensions)
+ x >= 0 && x < dimensions[:width] && y >= 0 && y < dimensions[:height]
end
-def valid_and_vacant?(xs, ys, dimensions, snake, food = [])
- in_bounds?(xs, ys, dimensions) and
- not food?(xs, ys, food) and
- not snake?(xs, ys, snake)
+def valid_and_vacant?(x, y, dimensions, snake, food = [])
+ in_bounds?(x, y, dimensions) && !snake?(x, y, snake) && !food?(x, y, food)
end
def new_food(food, snake, dimensions)
random_generator = Random.new
- xs = random_generator.rand(dimensions[:width])
- ys = random_generator.rand(dimensions[:height])
- until valid_and_vacant?(xs, ys, dimensions, snake, food)
- xs += 1
- ys = (ys + xs / dimensions[:width]) % dimensions[:height]
- xs %= dimensions[:width]
- end
- [xs, ys]
+ valid_positions_x = (0...dimensions[:width]).to_a
+ valid_positions_y = (0...dimensions[:height]).to_a
+ valid_positions = valid_positions_x.product(valid_positions_y)
+ vacant_positions = valid_positions - food - snake
+ vacant_positions[random_generator.rand(vacant_positions.size)]
end
-def obstacle_ahead?(snake, direction, dimensions, moves_count = 1)
- xs = snake[-1][0] + moves_count * direction[0]
- ys = snake[-1][1] + moves_count * direction[1]
- not valid_and_vacant?(xs, ys, dimensions, snake)
+def obstacle_ahead?(snake, direction, dimensions, moves = 1)
+ x, y = *position_ahead_of_snake(snake, direction, moves)
+ !valid_and_vacant?(x, y, dimensions, snake)
end
def danger?(snake, direction, dimensions)
obstacles_in_one_move = obstacle_ahead?(snake, direction, dimensions)
- obstacles_in_two_moves = obstacle_ahead?(snake, direction, dimensions, 2)
- obstacles_in_one_move or obstacles_in_two_moves
+ obstacles_in_two_moves = obstacle_ahead?(snake, direction, dimensions, 2)
+ obstacles_in_one_move || obstacles_in_two_moves
end
  • промених xs и ys на x и y; преди това използвах xs и ys, защото си мислех, че skeptic няма да приеме x и y, въпреки, че не съм сигурен дали и x и y са достатъчно добри имена.
  • new_food вече избира случаен елемент от свободните полета
  • махнах grow!, защото беше излишно
  • на мястото на Array.new използвах dup, защото на лекциите казахте да ползваме него
  • направих си position_ahead_of_snake за да не смятам два пъти едно и също
  • оправих food? и snake?
  • от темата за and, or и &&, || не ми стана съвсем ясно аз какво трябва да използвам в моя случай, но тъй като не е if/unless/.., използвах класическите &&, ||, !.

Започва да изглежда добре.

  • Погледни за Array#sample и ще можеш да се отървеш от малко код в new_food
  • Можеш да правиш a, b = [1, 2] # a = 1 и b = 2
  • Двойката x и y описват едно поле, та по-добре ги обедини в един параметър
  • valid_and_vacant? е леко излишен, също не използваш food = [], никъде. Бих ти предложил да го обединиш с obstacle_ahead?.
  • Понякога като имаш много равнота = е удобно да ги индентираш на едно ниво. По-добре се чете. Обикновено е най-добре като правиш подобни неща. пр.
def danger?(snake, direction, dimensions)
  obstacles_in_one_move  = obstacle_ahead?(snake, direction, dimensions)
  obstacles_in_two_moves = obstacle_ahead?(snake, direction, dimensions, 2)
  obstacles_in_one_move || obstacles_in_two_moves
end
  • Относно and, or и &&, || - така е перфектно.

Бих ти препоръчал още няколко неща. Първо малко ми притеснява, че move зависи от grow, защото зад тях стоят различни механики, но също и ако grow се промени (бъф за двойно по-бърз растеж ^^), ще стане лошо. Моят съвет е да внимаваш, когато навързваш разни неща и да се стремиш към по-самостоятелни методи, класове, модули, програми, системи и т.н. и т.н. градове, планети.. В текущия пример имаш две механики - за движение и за нарастване. Те се приличат и това те кара да направиш едната да зависи от другата. По-правилно е да вземеш приликите им и да създадеш трето нещо, което да използваш и в двете. (и да примерът е тривиален и т.н. но правиш един dup повече :D, но както и да е)

Второто нещо е да обръщаш внимание на това, че кодът се чете отгоре надолу. И е приятно да обединяваш методите в някакви групи. С други думи премести new_food нанякъде.

Здравко обнови решението на 17.10.2015 20:25 (преди над 9 години)

def position_ahead_of_snake(snake, direction, moves = 1)
[snake[-1][0] + moves * direction[0], snake[-1][1] + moves * direction[1]]
end
def grow(snake, direction)
snake.dup.push(position_ahead_of_snake(snake, direction))
end
def move(snake, direction)
- grow(snake[1..-1], direction)
+ snake[1..-1].push(position_ahead_of_snake(snake, direction))
end
-def food?(x, y, food)
- food.include?([x, y])
+def snake?(position, snake)
+ snake.include?(position)
end
-def snake?(x, y, snake)
- snake.include?([x, y])
+def in_bounds?(position, dimensions)
+ position[0].between?(0, dimensions[:width] - 1) &&
+ position[1].between?(0, dimensions[:height] - 1)
end
-def in_bounds?(x, y, dimensions)
- x >= 0 && x < dimensions[:width] && y >= 0 && y < dimensions[:height]
+def obstacle_ahead?(snake, direction, dimensions, moves = 1)
+ position = position_ahead_of_snake(snake, direction, moves)
+ !in_bounds?(position, dimensions) || snake?(position, snake)
end
-def valid_and_vacant?(x, y, dimensions, snake, food = [])
- in_bounds?(x, y, dimensions) && !snake?(x, y, snake) && !food?(x, y, food)
+def danger?(snake, direction, dimensions)
+ obstacles_in_one_move = obstacle_ahead?(snake, direction, dimensions)
+ obstacles_in_two_moves = obstacle_ahead?(snake, direction, dimensions, 2)
+ obstacles_in_one_move || obstacles_in_two_moves
end
def new_food(food, snake, dimensions)
- random_generator = Random.new
valid_positions_x = (0...dimensions[:width]).to_a
valid_positions_y = (0...dimensions[:height]).to_a
valid_positions = valid_positions_x.product(valid_positions_y)
vacant_positions = valid_positions - food - snake
- vacant_positions[random_generator.rand(vacant_positions.size)]
-end
-
-def obstacle_ahead?(snake, direction, dimensions, moves = 1)
- x, y = *position_ahead_of_snake(snake, direction, moves)
- !valid_and_vacant?(x, y, dimensions, snake)
-end
-
-def danger?(snake, direction, dimensions)
- obstacles_in_one_move = obstacle_ahead?(snake, direction, dimensions)
- obstacles_in_two_moves = obstacle_ahead?(snake, direction, dimensions, 2)
- obstacles_in_one_move || obstacles_in_two_moves
+ vacant_positions.sample
end

Благодаря за съветите! Ето какво промених:

  • вече използвам Array#sample вместо сам да си генерирам произволен индекс
  • обединих x и y в position, но така кодът в in_bounds? не се събира на един ред, точно и заради това си ги бях оставил x и y; сега открих between? и поне не се налага да пиша по два пъти position[0] и position[1]; освен това не знам дали така е добре индентиран кода в in_bounds?
  • valid_and_vacant? наистина беше излишен, както и food? - бях ги използвал за new_food и за тестовете и след предните промени не съм се усетил да ги махна - сега вече ги няма
  • подравних равнотата в danger?, но ги оставих както са си в new_food, защото изразите правят различни неща и сякаш няма смисъл да са подравнени еднакво, даже си мисля, че може и да е объркващо, ако са подравнени, а правят различни неща - това ти ще кажеш как го използват хората - може и да не съм прав
  • промених move да не зависи от grow
  • преместих new_food най-отдолу