W moim tetrisowym narzędziu zwanym Richtris docelowo ma być wyświetlany bieżący wynik punktowy oraz pod nim różnica punktów w stosunku do tempa, pozwalającego pobić obecny rekord. Chyba za długo przy tym siedzę i każdy nowy pomysł na implementację jest gorszy od poprzedniego, więc zwracam się o małą pomoc.
Zadanie jest dość trudne, dlatego trochę rzeczy muszę opisać bo wiem, że nie gracie w tego Tetrisa i nie wiecie czym się od charakteryzuje. Ale postaram się ograniczyć opis do minimum. ;)
Od początku. Klasyczny Tetris posiada 19 poziomów, z których można wystartować grę. Rozgrywka praktycznie kończy się wraz z przejściem do poziomu 29. Każdy poziom charakteryzuje się inną liczbą punktów przyznawaną za wyczyszczenie linii (single, double, triple, tetris). Otrzymywane punkty za wyczyszczenie linii oblicza się według poniższego wzoru:
(level + 1) * 40 // single
(level + 1) * 100 // double
(level + 1) * 300 // triple
(level + 1) * 1200 // tetris
Czyli tetris na poziomie 0 wart jest 1200 punktów, a np. na poziomie 18 jest to 22.800 punktów. Skoro mnożną w tym wzorze jest inkrementowany numer poziomu, to przyrost punktów w kolejnych poziomach jest liniowy – tu jest wszystko proste.
Po wyczyszczeniu 10 kolejnych linii, przechodzi się do następnego poziomu. 10 kolejnych i do następnego. Tutaj zaczynają się schody. Tetris ma buga związanego z obliczaniem liczby linii po których przechodzi się do kolejnego poziomu. Jeśli startuje się z poziomu od 0 do 9, to ładnie do 10 wyczyszczonych linii wskakuje kolejny poziom. Wzór sypie się na poziomach od 10 do 19, co pokazuje poniższa tabelka:
Expected Lines oznacza, że takie wartości powinny być, aby wzór był spójny, natomiast Actual Lines zawiera wartości realne, które gra w wyniku błędu wykorzystuje.
Oznacza to, że startując np. z poziomu 13, należy zrobić 100 linii aby przejść do poziomu 14, a co za tym idzie, 250 linii do poziomu 29. Natomiast startując z poziomu 18, należy zrobić 130 linii aby przejść do poziomu 19 oraz łącznie 230 linii do poziomu 29. To trochę komplikuje obliczenia. Wzór pozwalający obliczyć ile linii mamy do osiągnięcia poziomu 29, na podstawie numeru poziomu startowego, wygląda następująco:
// obliczenie liczby linii do przejścia na poziom kolejny względem startowego
LinesTransition := Math.Min((LevelStart * 10 + 10), Math.Max(LevelStart * 10 - 50, 100));
// obliczenie liczby linii do osiągnięcia poziomu 29
LinesKillScreen := LinesTransition + (29 - LevelStart - 1) * 10;
Obliczenia te dają wyniki zgodne w wyżej podaną tabelką. Wszystkie informacje na temat internalsów tej wersji Tetrisa znajdują się w artykule Applying Artificial Intelligence to Nintendo Tetris.
Dane wejściowe, znane w każdej chwili to:
- numer poziomu startowego – od 0 do 19,
- obecny numer poziomu – od poziomu startowego do nieskończoności,
- obecna liczba wyczyszczonych linii – od 0 do nieskończoności,
- obecna liczba punktów – od 0 do nieskończoności,
- liczba punktów będąca rekordem – od 0 do nieskończoności.
Znane też są stałe, którymi gra się posługuje:
- liczba linii potrzeba do przejścia do kolejnego poziomu – dane z tabelki,
- liczba linii potrzebna do osiągnięcia poziomu 29 – dane z tabelki oraz podanego drugiego wzoru.
- liczba punktów, przyznawana za kasowanie linii – dane z pierwszego wzoru.
Sytuacja wydaje się prosta, bo teoretycznie wystarczy obliczyć ile linii mamy do poziomu 29, podzielić bieżący rekord punktowy przez tę liczbę linii, w wyniku czego uzyskać liczbę punktów przypadających na jedną linię. Następnie tę liczbę punktów pomnożyć przez liczbę obecnie wyczyszczonych linii – mamy tempo idealne. Na koniec od obecnej liczby punktów odjąć tę dla idealnego tempa i uzyskać liczbę dodatnią, jeśli tempo pozwala na pobicie rekordu lub ujemną, jeśli tempo jest za słabe.
Problem w tym, że taki wzór będzie produkował niepoprawną wartość tempa. Im niższy poziom startowy, tym strata tempa będzie coraz większa z każdą kolejną wyczyszczoną linią. Sytuacja unormuje się w granicach startowania z poziomu 10-15, a przy wyższych znów tempo będzie wyliczane niepoprawnie, tym razem w drugą stronę (zysk tempa będzie nienormalnie duży).
Chodzi o to, aby bez względu na numer poziomu startowego, robienie pod rząd tylko tetrisów powodowało wzrastanie zysku w stosunku do tempa. Dlatego na pewno należy wziąć pod uwagę poziom startowy i liczbę linii, po wyczyszczeniu których wskakuje kolejny poziom. Dalsze poziomy będą wskakiwać już co 10 kolejnych linii. Na pewno też należy wziąć pod uwagę punktację za single/double/triple/tetrisy w stosunku do poziomów pomiędzy startowym a końcowym (czyli 29).
Nie mam bladego pojęcia jak to policzyć. Mógłbym to zbrutforsować, ale że tempo liczone ma być po każdej wyczyszczonej linii, wolałbym oszczędzić moc obliczeniową. Ktoś ma jakiś pomysł?
Jeśli coś jest niejasne to piszcie – udzielę wszelkich informacji na temat gry oraz wymagań.
- transition lines.png (8 KB) - ściągnięć: 22