Dawno temu czyjeś zajęcie zainspirowało mnie do skonstruowania ciekawego algorytmu i programu komputerowego. Napisałem opowiadanie-artykuł. Teraz dedykuję je Ani, która odeszła.
- Cześć Anka! Co ty tam gryzmolisz?
- Witaj dowcipasku. A ja po prostu projektuję grę planszową dla uczniów podstawówki. Nawet nie masz pojęcia Marku, jak są ciekawe przygód, które im, co tydzień w ten sposób zapewniam.
- Rozumiem, że pomagasz mamie nauczycielce, ale dlaczego poświęcasz temu tyle pracy, a efekt plastyczny jest jednak znacznie słabszy niż gier z drukarni, których tyle jest na rynku?
- Mama ma swój autorski program nauczania i chce żeby dzieci poznawały określone słowa, zwroty, sytuacje i żeby to było wplecione w zabawę. Nie ma takich gier na rynku.
- A czy te dzieci dają radę nauczyć się co tydzień nowej gry?
- Dostają szczegółową instrukcję, a gra jest typową grą z kostką i jednym pionkiem dla każdego gracza. Ale mam z nią inny problem. Okazuje się bowiem, że czas rozgrywki jest dla niektórych moich plansz zbyt długi przekraczając te czterdzieści minut, a dla innych zbyt krótki i dzieci są zawiedzione. Może ty jako matematyk mógłbyś mi pomóc tak projektować grę by trwała pomiędzy pół godziny a czterdzieści minut?
- Na to nie ma gotowego wzoru, a poza tym wiele zależy od tego jak szybko sobie podają kostkę, rzucają i dodatkowo dyskutują. Ale jak widzę u ciebie pola są ponumerowane od 0 do pewnej liczby n, więc pewnie dużo zależy jaka to liczba. Można tu podać następujący wzór na średnią liczbę rzutów jakie musi wykonać jeden gracz by przejść od początku do końca: n/3,5.
- To jest oczywiste, że im więcej pól tym gra dłużej trwa, ale miałam już kilka przypadków gier o równej liczbie pól i zupełnie różnych czasach rozgrywek dla nich.
- Ach widzę, że jeszcze masz wiele pól z nagrodami i karami.
- Zatrzymanie się na takim polu po rzucie kostką powoduje, że gracz jest zmuszany do przejścia na zupełnie inne pole planszy przez odliczenie pól kary lub nagrody.
- To komplikuje obliczenia, ale mogę spróbować je zrobić dla tej twojej planszy.
Wychodząc z pola zero prawdopodobieństwo zatrzymania się w jednym rzucie na polach od 1 do 6 wynosi po 1/6. Zróbmy więc tabelkę:
Pole |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
Rzut 1 |
0 |
1/6 |
1/6 |
1/6 |
1/6 |
1/6 |
1/6 |
0 |
0 |
Teraz możemy doliczyć prawdopodobieństwo z pola 1 do pola 6, bo tam zostanie automatycznie przeniesiony pionek jak zatrzyma się na polu 1..
Pole |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
Rzut 1 |
0 |
0 |
1/6 |
1/6 |
1/6 |
1/6 |
2/6 |
0 |
0 |
W kolejnym rzucie prawdopodobieństwa znowu się podzielą przez 6, a że rzuty będą następowały z pól 2,3,4,5,6 to będzie to tak wyglądało. Nie będzie rzutu z 1, bo tu pionek przeniesie się na 6 i z 6 będzie do podzielenia większe prawdopodobieństwo:
Pole |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
Rzut 2 |
0 |
0 |
0 |
1/36 |
1/36 +1/36 |
1/36 +1/36 +1/36 |
1/36 +1/36 +1/36 +1/36 |
1/36 +1/36 +1/36 +1/36 +2/36 |
1/36 +2/36 +3/36 +4/36 +10/36 |
- A z 7 pradobodobieństwo przeniesie się na 2.
Pole |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
Rzut 2 |
0 |
0 |
1/36 +1/36 +1/36 +1/36 +2/36 |
1/36 |
1/36 +1/36 |
1/36 +1/36 +1/36 |
1/36 +1/36 +1/36 +1/36 +1/36 |
0 |
1/36 +2/36 +3/36 +4/36 +10/36 |
- I teraz znowu to prawdopodobieństwo powróciło na początkowe pola i trzeba będzie liczyć od nowa. Daj mi trochę czasu to ci to wszystko ze spokojem powyliczam.
- Ale ładna tabelka. Tylko gdzie ja tu znajdę ile potrwa ta gra?
Rzut/Pole |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
0 |
1.0000 |
0.0000 |
0.0000 |
0.0000 |
0.0000 |
0.0000 |
0.0000 |
0.0000 |
0.0000 |
1 |
0.0000 |
0.0000 |
0.1667 |
0.1667 |
0.1667 |
0.1667 |
0.3333 |
0.0000 |
0.0000 |
2 |
0.0000 |
0.0000 |
0.1667 |
0.0278 |
0.0556 |
0.0833 |
0.1111 |
0.0000 |
0.5556 |
3 |
0.0000 |
0.0000 |
0.0741 |
0.0278 |
0.0324 |
0.0417 |
0.0556 |
0.0000 |
0.2130 |
4 |
0.0000 |
0.0000 |
0.0386 |
0.0123 |
0.0170 |
0.0224 |
0.0293 |
0.0000 |
0.1119 |
5 |
0.0000 |
0.0000 |
0.0199 |
0.0064 |
0.0085 |
0.0113 |
0.0150 |
0.0000 |
0.0584 |
6 |
0.0000 |
0.0000 |
0.0102 |
0.0033 |
0.0044 |
0.0058 |
0.0077 |
0.0000 |
0.0298 |
7 |
0.0000 |
0.0000 |
0.0052 |
0.0017 |
0.0023 |
0.0030 |
0.0040 |
0.0000 |
0.0153 |
8 |
0.0000 |
0.0000 |
0.0027 |
0.0009 |
0.0012 |
0.0015 |
0.0020 |
0.0000 |
0.0079 |
9 |
0.0000 |
0.0000 |
0.0012 |
0.0004 |
0.0004 |
0.0006 |
0.0009 |
0.0000 |
0.0037 |
10 |
0.0000 |
0.0000 |
0.0002 |
0.0002 |
0.0002 |
0.0002 |
0.0002 |
0.0000 |
0.0002 |
11 |
0.0000 |
0.0000 |
0.0000 |
0.0000 |
0.0000 |
0.0000 |
0.0000 |
0.0000 |
0.0000 |
- Teraz wystarczy, że elementy ostatniej kolumny czyli prawdopodobieństwa dotarcia do ostatniego pola przemnożymy przez liczbę rzutów, liczbę osób uczestniczących w grze i czas na wykonanie pojedynczego rzutu, a wyjdzie nam średni czas trwania gry. Tutaj wyjdzie 14.4 minuty po przyjęciu, że uczestniczy sześciu graczy rzucających co pięćdziesiąt sekund.
- To trochę mało.
- No to wystarczy, że zwiększysz liczę pól i dodasz trochę więcej kar. Ale ja już mam dosyć tego liczenia na piechotę, wolę ci napisać program, który to będzie sam robił.
program GRA;
const
n=50;
m=80;
eps=0.001;
var
Los: array[0..n]of array[0..m]of extended;
Uklad: array[0..n]of integer;
z:boolean;
nn,p,r:integer;
function Rzut(P,R:integer):boolean;
var i,j:integer;
begin
if Los[P,R]>eps
then begin
for i:=P+1 to P+6 do begin
if i>nn
then j:=nn
else j:=i;
Los[j,R+1]:=Los[j,R+1]+Los[P,R]/6;
if Uklad[j]<>0
then begin
Los[j+Uklad[j],R+1]:= Los[j+Uklad[j],R+1]+Los[P,R]/6;
Los[j,R+1]:=0;
end;
end;
Rzut:=true;
end
else Rzut:=false;
end;
procedure Drukuj;
var i,j,g,k:integer;
s:extended;
begin
write('Rzut/Pole');
for j:=0 to nn do
write(j:3,' ':4);
writeln;
for i:=0 to r do begin
write(i:3,' ':6);
for j:=0 to nn do
write(Los[j,i]:0:4,' ');
writeln;
end;
s:=0;
for i:=0 to r do
s:=s+Los[nn,i]*i;
writeln('Podaj liczbe graczy:');
readln(g);
writeln('Podaj sredni czas rzutu kostka i ruchu w sekundach:');
readln(k);
writeln('Szacowany czas gry:',s*g*k/60:7:1,' minut.');
readln;
end;
procedure Czytaj;
var p,r,nast:integer;
begin
for p:=0 to n do
for r:=0 to m do
Los[p,r]:=0;
writeln('Podaj ukˆad p¢l planszy do gry kostk¥.');
nast:=-1;
while(nast<>0)do begin
write('Podaj numer pola i przeskok z niego:');
readln(p,nast);
Uklad[p]:=nast;
end;
nn:=p;
end;
begin
Czytaj;
r:=0;
z:=true;
Los[0,0]:=1;
while z and (R<m) do begin
z:= false;
for p:=0 to nn-1 do
z:= Rzut(p,r) or z;
r:=r+1;
end;
Drukuj;
end.
- Spróbuję więc teraz skorzystać z twojego programu i wpiszę więcej pól:
45 -40
30 -20
20 20
50 0
I tyle co poprzednio graczy i czasu rzutu.
- No widzisz teraz wyszło znacznie więcej niż potrzebujesz, bo aż
80.6 minut. Musisz jeszcze poeksperymentować, a na pewno z łatwością będziesz uzyskiwała oczekiwane wyniki.