Решение на Шеста задача от Бойко Караджов
Резултати
- 5 точки от тестове
- 0 бонус точки
- 5 точки общо
- 12 успешни тест(а)
- 2 неуспешни тест(а)
Код
Лог от изпълнението
.........FF... Failures: 1) TurtleGraphics Canvas::ASCII renders the proper symbols depending on the intensity Failure/Error: expect(ascii.sub(/\n\z/, '')).to eq [ expected: "320\n110\n000" got: "323\n113\n333" (compared using ==) Diff: @@ -1,4 +1,4 @@ -320 -110 -000 +323 +113 +333 # /tmp/d20151203-5272-ey5mgh/spec.rb:128:in `block (3 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) TurtleGraphics Canvas::ASCII can render with a different number of symbols Failure/Error: expect(ascii.sub(/\n\z/, '')).to eq [ expected: "ttz\nooz\nzzz" got: "tot\nzzt\nttt" (compared using ==) Diff: @@ -1,4 +1,4 @@ -ttz -ooz -zzz +tot +zzt +ttt # /tmp/d20151203-5272-ey5mgh/spec.rb:151:in `block (3 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.01286 seconds 14 examples, 2 failures Failed examples: rspec /tmp/d20151203-5272-ey5mgh/spec.rb:112 # TurtleGraphics Canvas::ASCII renders the proper symbols depending on the intensity rspec /tmp/d20151203-5272-ey5mgh/spec.rb:135 # TurtleGraphics Canvas::ASCII can render with a different number of symbols
История (4 версии и 6 коментара)
Бойко обнови решението на 28.11.2015 21:07 (преди около 9 години)
Здравей!
- Имаш стилови проблеми - многоредовите блокове не се пишат с този синтаксис.
- Това е лошо използване на
Complex
. Ако ти трябва подобен клас си напиши собствен. :)Complex
не е създаден за тази цел. - Избирането на подходящ символ в
ASCII
може да стане доста по-чисто с използване на малко математика. Помисли как да превърнеш интензитет в индекс от масива със символите. :)
Бойко обнови решението на 30.11.2015 21:46 (преди около 9 години)
Здравей,
Благодаря за коментарите! Мисля че оправих многоредовите блокове и намирането на правилен индекс за ASCII.
За Complex
, така го харесвам. Според мен комплексните числа много добре изразяват посока и ротацията се получава естествено с умножение. Може би би било семантично подобрение ако го заменя с 2-мерен вектор, но Complex
ми се вижда по-интуитивно.
Поздрави,
Бойко
Не разбирам как би било по-интуитивно. :) Може ли да опишеш защо ти се струва по-интуитивно от двумерен вектор?
Ето моите доводи:
-
Complex
прави кода по-трудно четим, защото предполага познаване на особеностите на комплексните числа. - Никак не е очевидно, че
@orientation *= Complex(0, -1)
ще завърти нещото в правилната посока. Освен ако не си учил комплексни числа миналата седмица. - Не използваш класа по предназначение. Стандартното представяне на точка в равнина е чрез вектор, не чрез комплексно число. Това качва коефициента на
WTF
-та в минута. :) В този случай почти използвашComplex
като вектор.
Като цяло, идеята не е да измислим най-хитрия начин да направим нещо с възможно най-малко символи, а да го направим лесно четим и ясен.
Съгласен съм, че семантично "вектор" е геометричния термин, а комплексното число може да се разглежда като вектор. Не мога да намеря дефиниция на комплексно число без да има геометричен смисъл описан редом до аритметичния и те всички имат картинка на вектор. Ето няколко причини поради които предпочитам да използвам точно комплексни числа, а не вектор:
Комплексното число си е точно двумерен вектор с числа, а "вектор" само по себе си е по-широкото понятие от линейната алгебра.
Разгледах вградения
Vector
в Ruby и идва доста по-мощен от комплексно число, идва от модулMatrix
и в крайна сметка се гледа като ред или колона от матрица. Не ми дава да умножа 2 вектора без да транспонирам единия.Да си напиша мой вектор, който просто дублира комплексните числа ми се вижда странно. Един такъв потенциален клас ако трябва да скрие алгебрата то ще има вътре двата метода, които ни трябват - rotate_right и rotate_left и пак ще трябва да се напише това умножение вътре. В костенурката това същото е точно по един ред в метод със сответното име. От името е очевидно какво се очаква да прави.
Tова качва коефициента на WTF-та в минута.
този смисъл на умножението не ми е познат, но пак - защо да дискриминираме геометричния смисъл в полза на този или който и да е? Числата са абстрактни понятия. Все едно да спрем да ползваме реалните числа за дължина, защото вече ги ползваме за скорост.
Можеш да ми проследиш мисълта: тръгнах от case
с 4 случая. Като си го прочетох се засрамих. Това с умножението на комплексно число е първото, което ми дойде на ум в контекста на аналитична геометрия. За това смятам, че е интуитивно, но разбира се, съдя само по себе си. Разбирам, че така се добавя тежестта на линейната алгебра върху читателя, но в контекста на геометрията е човешко да се очаква, че ако на някой не му е ясно какво прави умножението ще си провери в wikipedia. Не съм учил тези неща миналата седмица и не уцелих от първия път точно по кой вектор трябва да умножа за правилната посока, но не ми беше зле да си припомня.
Съжалявам, че излезе толкова дълго, но ме провокира да се аргументирам :) . Правя го в името на добрата дискусия. Ако кажеш - спирам да се обяснявам и го сменям на... нещо. Не знам наистина какво се очаква да смени това умножение. Сигурно ще е някакъв малък вектор, който вместо да се умножава ще се ротира.
Няма за какво да съжаляваш. Точно това исках - да стане дискусия :) Не искам да го смениш против волята си, без да си съгласен с промяната - това би било безсмислено и излишно.
Продължавам дискусията:
Един такъв потенциален клас ако трябва да скрие алгебрата то ще има вътре
двата метода, които ни трябват - rotate_right и rotate_left и пак ще трябва да се
напише това умножение вътре. В костенурката това същото е точно по един ред в
метод със сответното име. От името е очевидно какво се очаква да прави.
Именно :) Защо изобщо ти трябва клас тогава?
Разбирам, че в някакъв математически смисъл, комплексните числа представят точка в двумерно пространство. Твърдя, че използването му в този смисъл не е добра идея в този код. Ако не можеше да използваш този трик със завъртането би ли използвал пак Complex
?
За да бъде един софтуер лесен за промяна, разширяемост и поддръжка, той на първо място трябва да е лесен за разбиране. Не мисля, че един код, използващ Complex
, за да замести две променливи е постигнал максимална яснота:
Разбирам, че така се добавя тежестта на линейната алгебра върху читателя,
но в контекста на геометрията е човешко да се очаква, че ако на някой не му
е ясно какво прави умножението ще си провери в wikipedia.
Не съм учил тези неща миналата седмица и не уцелих от първия път точно
по кой вектор трябва да умножа за правилната посока
Ето го проблема. Значи, за да разбера едно парче код в потенциално огромен проект, аз трябва да използвам Wikipedia. Вместо да прочета още два реда и да разбера веднага какво прави. :)
Сега си представи проект с десетки файлове и за да разбереш всеки трябва за всеки да потърсиш различно нещо в Wikipedia. Ако ти беше четящият щеше ли да си доволен от използването на Complex
, или щеше да предпочиташ по-простата имплементация? :) Разбира се, не говоря за проект, който се занимава конкретно с математика и комплексни числа - тогава Complex
е очаквано нещо и читателят се очаква да знае или да научи това. За всеки друг проект, Complex
е далече от контекста.
тръгнах от case с 4 случая. Като си го прочетох се засрамих.
Първо, един прост case
не е толкова лош. Аз лично бих го предпочел, ако избора беше само case
или Complex
. Отново, заради яснотата на четене.
В случая, обаче, има вариант просто да си създадеш един масив [:left, :up, :right, :down]
и да се местиш наляво или надясно в него. Елиминираш и другия case
.
@orientation = case orientation
when :left
Complex(0, -1)
when :up
Complex(-1, 0)
when :right
Complex(0, 1)
when :down
Complex(1, 0)
end
Този case
е по-голям повод за засрамване :) Най-малкото защото поражда въпроси от рода на "Защо се използва реалната част за y, а не за x координатата?".
Не се засрамвай от простите неща. Ако си успял да постигнеш необходимата функционалност с максимално очевидни и интуитивни средства, значи си си свършил страхотно работата. :)
По-скоро обърни нещата - стреми се да го правиш по-просто, не по-сложно. Яснотата е най-важният признак за качеството на един код. Дори не винаги по-простото решение е по-дълго като редове. Нашето решение е точно толкова реда, колкото и твоето, и не използва Complex
. Като свърши срока може да разгледаш и него :)
Много е полезно да се поставиш на мястото на човек, който няма никаква представа от кода и трябва да го разбере, за да оправи бъг. Колко време ще му отнеме? Трябва ли да се допитва до Wikipedia? Все въпроси, които са важни.
Бойко обнови решението на 02.12.2015 00:37 (преди около 9 години)
Последен аргумент за Complex: "Утре" ако някой каже, че стъпката, ще е с по 10 градуса примерно от тази имплементация ще стане по-лесна промяната.
Пооправих нещата като кръстих комплексните числа със символи и ползвам реалната част за X, а имагинерната за Y. Искаше ми се да ги инициализирам с ъгъл за да е по-ясно какво става: Complex.polar(1, Math::PI/2)
, но така се получават неточни числа: не е точно [0, 1], примерно, а е някакво много близко число... сигурно заради загубите от floating point operations. Това не може да се ползва като работим с цели числа, а излиза някакво излишно да ги round-вам в последствие.
След това упражнение (.с polar) стана ясно, че за задачата масивче от посоките с да бягане по индексите си е доста прилично решение на задачата, но вече ми е късно да променям. Ще разглеждам поне вашето решение после.