Uczelniane projekty – odbębnić i zapomnieć? cz. 1

(Tak, to będą posty o programowaniu. Tak, musiałem. Tak, to właśnie część mojego życia. Tak, ten post jest w wersji beta – może brakować mu troszkę treści, ładu i składu ;)) )

W życiu studenta jest szczególnie dużo różnych projektów – mniejszych i większych zadań, realizowanych jako jedno z wielu lub jako punkt kulminacyjny semestru. Studenci zaś przejawiają przeróżne podejścia

  • jedni nie robią nic, bo robią za nich koledzy.
  • inni nie robią nic, aż w ostatniej chwili nie skołują gotowca, którego w akcie łaski przerobią – nie zawsze po tych przeróbkach działa i nie zawsze wiedzą, co on właściwie robi
  • inni robią projekcik jakoś spełniający minimalne wymogi zadania – wiedzą, co jest do zrealizowania, uczą się, jak to zrealizować i zaliczają ładnie.
  • ostatni typ natomiast najpierw nie ma żadnego pomysłu, a potem nagle przychodzi Wizja. Wizja jest realizowana z rozmachem, program robi się rozbudowany, zespół ledwo mieści się w terminie (lub go przekracza), program jest wypasiony… a wykładowca ledwo rzuci okiem ;) Po czym program idzie w odstawkę i jest zapominany, jak w każdym wypadku.

Oczywiście niepokojąco często reprezentuję ten ostatni typ, co pewnie nietrudno się było domyślić po długości opisu ;)

W ciągu tych dwóch lat studiów powstało kilka takich programów, głównie pisanych przeze mnie wspólnie z emkaelem, z których po ukończeniu byłem chociaż troszkę dumny – bo fajny pomysł, bo mimo to (;D) zrealizowany… no, ewentualnie z poczuciem niespełnienia, że prowadzący przedmiot nawet nie rzucił okiem na żaden z fantastycznych „myków”, cudów i rozwiązań, nad którymi się meczyliśmy ;). Nie ukrywam, że niektóre miewam ochotę rozwinąć, komercyjniej ;)

Głupi projekt no. 1 – symulator autobusu

Na Programowaniu Obiektowym było wymyśleć sobie projekt, dowolny, najlepiej jakaś symulacja, który ogólnie rzecz biorąc zaimplementujemy obiektowo. Mając minuty na wybór tematu daliśmy się ponieść chwili i temu, jak inspi-, fascy- i irytujące jest zachowanie ludzi w środkach komunikacji miejskiej. Niektórzy z Was pewnie czytali już opisy rodzajów babć autobusowych, wielu widziało także „Dzień Świra”. Także i my mieliśmy pewne swoje spostrzeżenia:

  • Wszyscy, do ciężkiej cholery siadają pojedynczo. Jeśli chcesz usiąść w autobusie z kolegą/żanką obok siebie, a połowa autobusu jest zajęta, to znaczy, że podwójne miejsca już się skończyły. Bo każdy musi siedzieć SAM. Jeszcze do tego w połowie przypadku od przejścia, żebyś czasem się pod okno nie dopchnął. Mimo, że powszechnie wiadomo, że miejsca od okna są atrakcyjniejsze ;)
  • Pieprzone mohery zawsze muszą być w drzwiach pierwsze. Nie, nieważne, że na przystanku stoi tłum, a one jadą tylko jeden przystanek i będą się musiały przez cały ten tłum za chwilę przebijać do drzwi. Nie, one muszą się wepchnąć pierwsze i zająć swoje upatrzone miejsce. Jeśli zajmie je ktoś młodszy, stosują liczne techniki wywierania wpływu, by je odzyskać. Mohery generalnie przepychają się najbardziej ze wszystkich rodzajów pasażerów – jeśli upatrzy sobie miejsce, to przestawi pół autobusu, żeby się do niego dostać. Są także mohery-sprintery, które niemalże natychmiast po otwarciu drzwi pojawiają się na wybranym miejscu.
  • Do autobusów regularnie wsiadają ludzie bezdomni lub co najmniej nie zaznajomieni z dorobkiem kultury w dziedzinie środków czystości. Niezależnie od zatłoczenia autobusu, wokół takich osób zawsze pozostaje pewna ilość wolnego miejsca (chyba, że faktycznie ludzie nie mogą się już siłą nigdzie przepchnąć). A nawet jak wyjdziesz z autobusu, masz wrażenie, że smród był tak intensywny, że na Tobie pozostał.
  • Autobusami jeżdzą m.in. studenci, którzy – biedni, maltretowani przez uczelnie – po zarwanych nocach przysypiają podczas jazdy. Może spać na siedząco, na stojąco, a na swoim przystanku i tak się obudzi i wysiądzie.
  • W autobusach zdarzają się kontrole biletów. Kanary są przekupne, jednak najczęściej niezależnie od uiszczonej kwoty i stopnia formalizacji transakcji, trzeba wysiąść.

Z cech równie życiowych, ale nie zaimplementowanych w programie:

  • Przesiadki to mit. Jeśli w planie podróży masz napisane, że Twój autobus przyjedzie 17:05, a docelowy, do którego chcesz wsiąść, o 17:10, to możesz mieć pewność, że tak naprawdę będzie odwrotnie.
  • Rozkłady to mit. Jeśli autobus jedzie, to stanie w korku. Jeśli stanie w korku, to będzie miał 5-25 minut spóźnienia.
  • Rozkłady to mit. Jeśli autobus nie będzie miał spóźnienia, pourywa koła na dziurach w nawierzchni. Nie przyjedzie wcale. Ewentualnie Ty do niego wsiądziesz, ale nie dojedziesz do celu.
  • Jak nie pourywa kół, to spłonie. A ubranie będzie Ci śmierdzieć.
  • Wycieczki szkolne. Wpada toto do autobusu, podwaja głośność panującą w środku (dzieci to takie istoty, które zdolne są przekrzyczeć ryczący autobusowy silnik), przepycha się, biega, wkurza. Pcha nie tylko swoich, ale i obcych.

Model rozwiązania – UML

Jednym z wymogów było stworzenie diagramu UML do realizowanego projektu. Prawdziwie złożonym kwiatkiem wyszedł diagram akcji pasażera:

Diagram akcji pasażera

Gdybyś się zastanawiał(a): UML to taki język opisu różnych mądrych rzeczy za pomocą różnych mądrych diagramów. „Diagram akcji pasażera” znaczy „grafik, co pasażer może robić i kiedy i dlaczego to robi”

Okrągłe prostokąciki bez kącików prostych ( ;-) ) to czynności. romby to decyzje, „flagi” to zdarzenia, które nam się stały i powodują, że coś robimy.
Spójrz, czy zdawałeś/łaś sobie sprawę, jak skomplikowane jest korzystanie z autobusu? ;o

Nasz autobus „jeździł” po faktycznej trasie autobusu 69 w Łodzi – miał załadowaną listę przystanków z ich godzinami i nazwami oraz pasażerami, jacy na nich wsiadają i docelowych (np. zagęszczenie wysiadających moherów przy kościołach i cmentarzach wzdłuż trasy – a było ich trochę).

Poziom zrealizowanej interakcji: zero. Aczkolwiek mieliśmy koncepcję (gdyby było więcej czasu), by dało się wejść w tryb bardziej interaktywny ;) – kierować pasażerem lub modyfikować ich listę/cele… lub chociaż podejrzeć je bez debuggera ;-)

Interfejs

Program, działający w trybie tekstowym, miał mieć splash-screen, ale z racji platformy Win32 odpuściliśmy sobie konwersje z linuksowych escape-codes na windowsowy… kod, bo w ASCII nie idzie zdefiniować kolorów:

Następnie rysował w ASCII-arcie autobus, kolorowymi gwiazdkami oznaczając różnego rodzaju pasażerów: białą – zwykłego, zieloną – studenta (przygaszona – śpi), czerwoną kanara (rozjaśniona – sprawdza bilety), niebieską bezdomnego, a zgniłą – mohera. Moher sprinter wsiada w autobusu i zajmuje w jednej „turze”, podczas kiedy inni pasażerowie mogą robić tylko 1 krok na turę.

Wideo: 5 minut z życia aplikacji. Po 3 minucie mamy krótki przegląd kodu – chciałem zmniejszyć parametry opóźnień w programie by w drodze powrotnej „jechał szybciej”, jednak Visual Studio tak długo nanosiło zmiany w kodzie, że skończył się czas na nagranie (5 minut) ;-)

Największy ból w kodzie

Najbardziej masakryczna, zaciemniona, a zarazem kluczowa dla działania i wydajności programu to funkcja Przepchnij. Jak sama nazwa wskazuje, wiąże się ona z przepychaniem się pasażerów w autobusie. Przepychanie się pasażera nie jest w żaden sposób odgórnie skoordynowane przez sytuację w całym autobusie, czyli przez jakieś szersze spojrzenie ;) Optymalizacja bliska zeru.

Jeśli nie jesteś programistą, nie czytaj dalej tego paragrafu.

W skrócie jej działanie/wada (niepotrzebne skreślić) polega na tym:

  • funkcja przyjmuje parametry: kto się pcha, w którą stronę i jak mocno (z jaką siłą)
  • funkcja zwraca informację, czy udało się przepchnąć daną jednostkę z jej miejsca
  • funkcja jest tak masakrycznie pozagnieżdżana sama w sobie, że może trwać stulecia. Jeśli więc wykona się bezskutecznie ponad 10 000 razy to albo zwraca niepowodzenie, albo – jeśli przepychający się akurat wysiada, jest kanarem lub moherem-sprinterem – po prostu zamienia go miejscami z pasażerem na miejscu, na które się pchamy.
  • Siła = 5 oznacza, że jesteśmy w stanie przepchnąć łańcuszek 5 osób (!), by się poruszyć
  • Jeśli na miejscu, na które się pchamy, ktoś stoi – każemy mu się pchać w tym samym kierunku (jeśli mamy siłę)
  • Jeśli się to nie uda, próbujemy pchać go w kolejnym kierunku – i tak wszystkie po kolei, zgodnie z ruchem wskazówek zegara (albo przeciwnie – co za różnica)
  • Dlatego też jeden przepychający się pasażer w tłoku powoduje problem. Pcha on każdą osobę dookoła siebie w każdym z możliwych kierunków… a każda z tych osób…. no właśnie. I program się przywiesza.
  • Jeśli miejsce się zwolni (ja popchnąłem kogoś, oni dalej się poprzepychali w jakiś tam sposób (bo mnie, jako pchającego, w ogóle to nie obchodzi)), zajmujemy je
  • Jeśli wypróbujemy wszystkie kierunki i miejsce nadal jest zajęte – no to kiszka ;P
  • Wysiadający mogą się zamieniać zawsze, by zawsze mogli dopchnąć się w końcu kiedyś do drzwi – bo nasz autobus jest fajnyczeka, aż wszyscy wysiądą.

Tu miał ładny, sformatowany być kod źródłowy, ale… no wiecie, „Word HTML”.

Czego nauczył mnie ten projekt?

Że kodzić trzeba. I chyba tylko tyle. Może troszkę korzystania z STLa w C++, jeśli liczyć także ogólnie laboratoria. Że przedmiot „Programowanie Obiektowe” to kolejne „klepanie kodu”, bez żadnej szczególnej idei. Że ile się nie napracujesz, to prowadzący rzuci tylko okiem na ekran, zobaczy migające kolorowe gwiazdki, powie „bardzo ładne” i postawi maksymalna ocenę, minus jeden za opóźniony termin oddania.

Czas wykonania – 9 dni (głównie 1 weekend i dopracowywanie w wolnych chwilach przez tydzień)
Metodyka – Ballmer Peak.
Skład: ikari & MKL.
Podział pracy: fair.
Satysfakcja: 7/10 – fajnie, bo ekspresowo napisane i działa. Na minus, bo mało optymalny przepchnij i przywiesza. Czasem zatykało się kompletnie, a w skrajnym tłoku pasażer wypadał za drzwi (!?) mimo wielokrotnego sprawdzania pozycji przy przestawianiu ;)

Wanna see it?

Gdyby ktoś chciał się pobawić i/lub obejrzeć kod – jeśli MKL uzna ten pomysł za dobry – niech da znać ;)
Przepraszam, za nudzenie nieinformatycznej części publiki, możecie mnie nienawidzić, ale musiałem :P Od pół roku chciałem przyznać się do napisania symulatora zachowania ludzi w autobusie ;)