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

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

Към профила на Димитър Узунов

Резултати

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

Код

REPOSITORY = 'http://github.com/dimitaruzunov/ruby-retrospective-2015-1'
# Двадесет неща, които научих.
#
# Първа задача
# 1. Оставяне на празни редове в методи с цел разделяне на логически различните
# части от кода на метода е добра практика. Например, в първа задача, сложих
# празен ред преди стойността на връщане от функцията compare_prices.
# По този начин кодът стана по-четим.
#
# Втора задача
# 2. В move функцията за премахване на опашката на змията използвам Array#drop
# метода вместо копиране на змията (при grow), Array#shift и накрая връщане
# на преместената змия. Така кодът става по-кратък (от 3 на 1 ред), но и
# по-четим и разбираем. От тук научих, че е хубаво да се чете документацията
# с цел да се намери най-подходящата функция за решаването на даден проблем.
# 3. В new_food метода промених начина, по който взимам всички x координати
# (и съответно същото и за y координатите). Замених
# xs = *(0...dimensions[:width]) с xs = (0...dimensions[:width]).to_a,
# от което става ясно, че стойносттва на xs ще бъде масив, докато от splat-а
# не се разбира веднага какво се случва. От това научих, че е по-добре да
# се използват възможно най-простите и разбираеми конструкции, когато може,
# а не нещо изглеждащо 'fancy' като например splat-а, но същевременно и
# неразбираемо за дадената ситуация.
# 4. Използването на паралелно присвояване прави кода по-прост и четим,
# когато например елементите на даден масив са свързани логически и искаме
# да им дадем имена. Във функцията snake_ahead_position взимам x и y
# координатите на главата на змията чрез head_x, head_y = snake.last (по
# същия начин и координатите на посоката).
# 5. Сложни конструкции като zip -> map -> reduce не са подходящи за прилагане
# при решаването на проста задача като например сумирането на два 2D вектора,
# както е в snake_ahead_position функцията. Вместо zip -> map, имаме просто
# [head_x + direction_x, head_y + direction_y].
# 6. Не е смислено да се дефинира метод, който е 'синоним' на друг метод, и
# единственото нещо, което прави втория метод, е да извика първия. Например,
# метода not_in_bounds? е 'синоним' на wall_ahead? (wall_ahead? извиква
# not_in_bounds?). За да подобря това, преместих кода от not_in_bounds? в
# wall_ahead? и изтрих not_in_bounds? метода.
#
# Трета задача
# 7. Научих какво е Enumerator в Ruby и че при извикване на методи от
# Enumerable без подаване на блок тези методи връщата Enumerator и по този
# начин може да се chain-ват методи от Enumerable.
# 8. Научих за метода enum_for, чрез който можем да конструираме Enumerator от
# метод, който yield-ва стойности. И този Enumerator обхожда точно
# yield-натите стойности от подадения метод.
# 9. Научих за цикъла loop do ... end и използването и за конструиране на
# безкраен поток от стойности, като се използва заедно с enum_for. Цикълът
# може да бъде прекратен при възникване на StopIteration изключение, което
# се хвърля, когато Enumerator-ът обходи всички стойности.
# 10. Научих за lazy метода в Enumerable, който връща lazy_enumerator. Това е
# Enumerator, при който методи като map, select, take, drop, take_while,
# drop_while обхождат стойностите само при необходимост. Тоест при подаване
# на блок на някой от тези методи, съответния израз няма да бъде оценен
# веднага, а само при нужда или при изпълнение на force метода. По този
# начин може да се chain-ват map, select, take с подадени блокове без да
# се оценяват. Това е доста полезно при конструирането на безкрайни потоци.
# 11. Паралелното присвояване помага, когато искаме да вземем елементите от
# масив с дължина 2 и да им дадем имена, като по този начин кодът става
# по-разбираем. Така, например, във функцията meaningless от partition
# се получава масив от два елемента -- двете групи, на които е разделен
# входния масив. В старото решение бях дал името groups на тези две групи,
# което по никакъв начин не дава информация какви са тези групи. И за
# взимането на всяка група поотделно използвах индексиране, което също
# намалява разбираемостта на кода.
# 12. За рефакторирането на функцията aimless научих, че при подаването на масив
# като аргумент на блок можем да използваме паралелно присвояване и по
# този начин да избегнем индексиране, с което да направим кода по-четим.
# 13. Научих, че параметър на блок може да има стойност по подразбиране.
# Например, във функцията aimless сложих стойност по подразбиране на
# параметъра second 1, с което си спестих 1 проверка
# (pairs.last << 1 if n.odd?).
# 14. Научих за метода take_while (използван във функцията worthless)
# 15. При рефакторирането на метода prime? разбрах за метода all?, който в
# комбинация с upto метода доста опрости кода на функцията, като замени
# изцяло while цикъла.
#
# Четвърта задача
# 16. Научих, че не трябва да забравям да имплементирам each метода в клас,
# който включва Enumerable модула (в случая класа Deck)
# 17. Научих, че с влагане на клас в друг клас може да се постигне по-добра
# и интуитивна подредба на кода. Например при влагането на класа Hand в Deck
# и съответно на клас Hand във всеки от видовете тестета.
# 18. Хубаво е при моделирането на дадения проблем чрез средствата на ООП да
# се изгради изчистена и консистентна йерархия от класове.
# 19. Научих, че може да използваме splat вътре в дефиницията на масива, за да
# 'разгърнем' интервал от стойности:
# [:ace, :king, :queen, :jack, *(10.downto 2)]
# 20. Научих за ключовата дума next и използването и за прекратяване на текущата
# итерация, като може да се даде и стойност на връщане на блока. Например:
# next false if cards_of_suit.size < card_count в n_consecutive_cards?

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

From https://github.com/fmi/ruby-retrospective-2015-1
 * branch            master     -> FETCH_HEAD
HEAD is now at 767dd8d Update the task name in the readme for clarity
Cloning into 'submission'...
HEAD is now at 5112e35 Refactor SixtySixDeck::Hand methods
From /tmp/ruby-retrospective-2015-1/checker
 * branch            master     -> FETCH_HEAD
 * [new branch]      master     -> upstream/master

Changes URL:
http://github.com/dimitaruzunov/ruby-retrospective-2015-1/compare/767dd8dfe46...5112e35c91a

‘solutions/04.rb’ -> ‘/tmp/ruby-retrospective-2015-1/checker/solutions/04.rb’
‘solutions/02.rb’ -> ‘/tmp/ruby-retrospective-2015-1/checker/solutions/02.rb’
‘solutions/03.rb’ -> ‘/tmp/ruby-retrospective-2015-1/checker/solutions/03.rb’
‘solutions/01.rb’ -> ‘/tmp/ruby-retrospective-2015-1/checker/solutions/01.rb’
OK
........

Finished in 0.00478 seconds
8 examples, 0 failures
OK
....................

Finished in 0.01106 seconds
20 examples, 0 failures
OK
....................

Finished in 0.02413 seconds
20 examples, 0 failures
OK
.........................................................

Finished in 0.02797 seconds
57 examples, 0 failures
From https://github.com/fmi/ruby-homework
 * branch            master     -> FETCH_HEAD
HEAD is now at 9dd040c Modify a test in task 8 to not include empty cells
.

Finished in 0.00204 seconds
1 example, 0 failures

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

Димитър обнови решението на 27.01.2016 17:24 (преди около 9 години)

+REPOSITORY = 'http://github.com/dimitaruzunov/ruby-retrospective-2015-1'
+
+# Двадесет неща, които научих.
+#
+# Първа задача
+# 1. Оставяне на празни редове в методи с цел разделяне на логически различните
+# части от кода на метода е добра практика. Например, в първа задача, сложих
+# празен ред преди стойността на връщане от функцията compare_prices.
+# По този начин кодът стана по-четим.
+#
+# Втора задача
+# 2. В move функцията за премахване на опашката на змията използвам Array#drop
+# метода вместо копиране на змията (при grow), Array#shift и накрая връщане
+# на преместената змия. Така кодът става по-кратък (от 3 на 1 ред), но и
+# по-четим и разбираем. От тук научих, че е хубаво да се чете документацията
+# с цел да се намери най-подходящата функция за решаването на даден проблем.
+# 3. В new_food метода промених начина, по който взимам всички x координати
+# (и съответно същото и за y координатите). Замених
+# xs = *(0...dimensions[:width]) с xs = (0...dimensions[:width]).to_a,
+# от което става ясно, че стойносттва на xs ще бъде масив, докато от splat-а
+# не се разбира веднага какво се случва. От това научих, че е по-добре да
+# се използват възможно най-простите и разбираеми конструкции, когато може,
+# а не нещо изглеждащо 'fancy' като например splat-а, но същевременно и
+# неразбираемо за дадената ситуация.
+# 4. Използването на паралелно присвояване прави кода по-прост и четим,
+# когато например елементите на даден масив са свързани логически и искаме
+# да им дадем имена. Във функцията snake_ahead_position взимам x и y
+# координатите на главата на змията чрез head_x, head_y = snake.last (по
+# същия начин и координатите на посоката).
+# 5. Сложни конструкции като zip -> map -> reduce не са подходящи за прилагане
+# при решаването на проста задача като например сумирането на два 2D вектора,
+# както е в snake_ahead_position функцията. Вместо zip -> map, имаме просто
+# [head_x + direction_x, head_y + direction_y].
+# 6. Не е смислено да се дефинира метод, който е 'синоним' на друг метод, и
+# единственото нещо, което прави втория метод, е да извика първия. Например,
+# метода not_in_bounds? е 'синоним' на wall_ahead? (wall_ahead? извиква
+# not_in_bounds?). За да подобря това, преместих кода от not_in_bounds? в
+# wall_ahead? и изтрих not_in_bounds? метода.
+#
+# Трета задача
+# 7. Научих какво е Enumerator в Ruby и че при извикване на методи от
+# Enumerable без подаване на блок тези методи връщата Enumerator и по този
+# начин може да се chain-ват методи от Enumerable.
+# 8. Научих за метода enum_for, чрез който можем да конструираме Enumerator от
+# метод, който yield-ва стойности. И този Enumerator обхожда точно
+# yield-натите стойности от подадения метод.
+# 9. Научих за цикъла loop do ... end и използването и за конструиране на
+# безкраен поток от стойности, като се използва заедно с enum_for. Цикълът
+# може да бъде прекратен при възникване на StopIteration изключение, което
+# се хвърля, когато Enumerator-ът обходи всички стойности.
+# 10. Научих за lazy метода в Enumerable, който връща lazy_enumerator. Това е
+# Enumerator, при който методи като map, select, take, drop, take_while,
+# drop_while обхождат стойностите само при необходимост. Тоест при подаване
+# на блок на някой от тези методи, съответния израз няма да бъде оценен
+# веднага, а само при нужда или при изпълнение на force метода. По този
+# начин може да се chain-ват map, select, take с подадени блокове без да
+# се оценяват. Това е доста полезно при конструирането на безкрайни потоци.
+# 11. Паралелното присвояване помага, когато искаме да вземем елементите от
+# масив с дължина 2 и да им дадем имена, като по този начин кодът става
+# по-разбираем. Така, например, във функцията meaningless от partition
+# се получава масив от два елемента -- двете групи, на които е разделен
+# входния масив. В старото решение бях дал името groups на тези две групи,
+# което по никакъв начин не дава информация какви са тези групи. И за
+# взимането на всяка група поотделно използвах индексиране, което също
+# намалява разбираемостта на кода.
+# 12. За рефакторирането на функцията aimless научих, че при подаването на масив
+# като аргумент на блок можем да използваме паралелно присвояване и по
+# този начин да избегнем индексиране, с което да направим кода по-четим.
+# 13. Научих, че параметър на блок може да има стойност по подразбиране.
+# Например, във функцията aimless сложих стойност по подразбиране на
+# параметъра second 1, с което си спестих 1 проверка
+# (pairs.last << 1 if n.odd?).
+# 14. Научих за метода take_while (използван във функцията worthless)
+# 15. При рефакторирането на метода prime? разбрах за метода all?, който в
+# комбинация с upto метода доста опрости кода на функцията, като замени
+# изцяло while цикъла.
+#
+# Четвърта задача
+# 16. Научих, че не трябва да забравям да имплементирам each метода в клас,
+# който включва Enumerable модула (в случая класа Deck)
+# 17. Научих, че с влагане на клас в друг клас може да се постигне по-добра
+# и интуитивна подредба на кода. Например при влагането на класа Hand в Deck
+# и съответно на клас Hand във всеки от видовете тестета.
+# 18. Хубаво е при моделирането на дадения проблем чрез средствата на ООП да
+# се изгради изчистена и консистентна йерархия от класове.
+# 19. Научих, че може да използваме splat вътре в дефиницията на масива, за да
+# 'разгърнем' интервал от стойности:
+# [:ace, :king, :queen, :jack, *(10.downto 2)]
+# 20. Научих за ключовата дума next и използването и за прекратяване на текущата
+# итерация, като може да се даде и стойност на връщане на блока. Например:
+# next false if cards_of_suit.size < card_count в n_consecutive_cards?