|
Serwis Edukacyjny w I-LO w Tarnowie
Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy Wałaszek |
©2026 mgr Jerzy Wałaszek
|
ProblemNależy opracować algorytm gry
|

Zasady gry
Zastanówmy się nad tym z jak dużym zbiorem mamy do czynienia. Kod kodera
składa się z 4 liter należących do alfabetu
6×6×6×6 = 1296
Jeśli nie znasz kombinatoryki, to wyjaśnienie tego wzoru jest następujące:
Na pierwszej pozycji może pojawić się jedna z 6 liter –
Axxx, Bxxx, Cxxx, Dxxx, Exxx, Fxxx, gdzie x – pozycja jeszcze nie zajęta
W każdej z tych 6 kombinacji drugą literę możemy wybrać również na 6 różnych sposobów. Na przykład dla Cxxx otrzymamy:
CAxx, CBxx, CCxx, CDxx, CExx, CFxx
Zatem ze względu na dwie pierwsze litery kodu otrzymujemy
BFAx, BFBx, BFCx, BFDx, BFEx, BFFx
Ze względu na 3 pierwsze litery kodu otrzymamy
Nie jest to zbiór specjalnie duży dla współczesnego komputera z procesorem Pentium –
możemy zastosować metodę naiwną, która polega na tym, iż tworzymy zbiór Z wszystkich możliwych słówek kodowych. Następnie w pętli wykonującej się
maksymalnie 6 razy losujemy ze zbioru Z jedno słowo kodowe słamacz, usuwamy je ze zbioru
Z i prezentujemy człowiekowi. W odpowiedzi człowiek zwraca
nam kod klucza sklucz zbudowany z liter x i
o wg zasad
gry
Pomimo swojej prostoty algorytm ten zupełnie dobrze radzi sobie z odgadywaniem kodów kodera w 6 ruchach. Oczywiście, z uwagi na losowy charakter typowania przez komputer swoich ruchów, istnieje mała szansa, iż komputer przegra wybierając nieefektywne posunięcia (tzn. takie, które eliminują ze zbioru Z zbyt małą liczbę kodów).
Zanim przystąpimy do tworzenia algorytmu, musimy rozwiązać kilka problemów.
Pierwszym z nich jest reprezentacja zbioru Z, który musi posiadać właściwość
usuwania elementów. Użyjemy do tego celu tablicy Z oraz dodatkowej zmiennej
zn, która będzie przechowywała liczbę elementów pozostałych w tablicy.
Aby system ten był efektywny, pozostałe elementy muszą być umieszczone w kolejnych komórkach
Teraz musimy określić operację usuwania elementu z tej struktury danych. Z tablicy nie można tak po prostu usunąć komórki. Dlatego przez usunięcie będziemy rozumieli zmniejszenie zawartości zn oraz przesunięcie o jedną pozycję wstecz zawartości wszystkich komórek za komórką, z której usuwamy dane.
Przykład:
Z[] przed operacją, zn = 10 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
|---|---|---|---|---|---|---|---|---|---|---|
Usuwanie |
|
|
|
|
|
X |
← |
← |
← |
← |
Z[] po operacji, zn = 9 |
0 |
1 |
2 |
3 |
4 |
6 |
7 |
8 |
9 |
9 |
Widzimy, iż fizycznie tablica dalej posiada 10 elementów. Ponieważ jednak zn zostało zmniejszone, to pod uwagę bierzemy teraz tylko 9 pierwszych elementów tablicy. Element 5 został nadpisany i nie występuje już w tym obszarze tablicy – usunęliśmy go.
Operacja usuwania jest nam potrzebna po wylosowaniu kodu – aby nie był
ponownie losowany. Ze zbioru Z musimy dodatkowo usuwać kody, które nie zgadzają
się z otrzymanym kluczem. Zastosujemy tutaj nieco inną operację usuwania ze względu na liniową złożoność obliczeniową (zastosowanie
zwykłej operacji usuwania prowadziłoby do złożoności kwadratowej).
Polega ona na tym, iż ustawiamy dwa indeksy
Przykład:
| Lp. | Operacja | Opis |
| 1. |
0 1 2 3 4 5 6 7 8 9 i1 i2 |
Ustawiamy oba indeksy na pierwszy
element zbioru. Za pomocą indeksu i1 przeglądamy kolejne elementy zbioru. |
| 2. |
0 1 2 3 4 5 6 7 8 9 i1 i2 |
0 kopiujemy (na
siebie, co nie jest szkodliwe). Oba indeksy są zwiększane o 1. |
| 3. |
0 1 2 3 4 5 6 7 8 9 i1 i2 |
1 kopiujemy, zwiększamy o 1 oba indeksy. |
| 4. |
0 1 2 3 4 5 6 7 8 9 i1 i2 |
2 kopiujemy, zwiększamy o 1 oba indeksy. |
| 5. |
0 1 2 3 4 5 6 7 8 9 i1 i2 |
3 pomijamy. Indeks i2 nie jest zwiększany. |
| 6. |
0 1 2 4 4 5 6 7 8 9 ↑ i1 i2 |
4 kopiujemy na byłe miejsce
3, zwiększamy o 1 oba indeksy. |
| 7. |
0 1 2 4 5 5 6 7 8 9 ↑ i1 i2 |
5 kopiujemy na byłe miejsce
4, zwiększamy o 1 oba indeksy. |
| 8. |
0 1 2 4 5 5 6 7 8 9 ↑ i1 i2 |
6 pomijamy |
| 9. |
0 1 2 4 5 5 6 7 8 9 ↑ i1 i2 |
7 pomijamy |
| 10. |
0 1 2 4 5 5 6 7 8 9 ↑ i1 i2 |
8 pomijamy |
| 11. |
0 1 2 4 5 9 6 7 8 9 ↑ i1 i2 |
9 kopiujemy na byłe miejsce
5, zwiększamy i2. |
| 12 |
0 1 2 4 5 9 6 7 8 9 ↑ i1 i2 |
Koniec. W zbiorze pozostało i2 elementów, wśród których nie ma już elementów pominiętych. |
Kolejnym problemem jest sposób wygenerowania 1296 łańcuchów kodowych. Zadanie
można rozwiązać na wiele sposobów. Jednym z nich jest potraktowanie każdego kodu
jako 4 cyfrowej liczby szóstkowej. W systemie szóstkowym jest 6 cyfr
Przykład:
Obliczymy wg tej metody wyraz o numerze 545:
545:6 = 90 i reszta 5 → F 90:6 = 15 i reszta 0 → A 15:6 = 2 i reszta 3 → D 2:6 = 0 i reszta 2 → C
Otrzymaliśmy wyraz
K01: Utwórz kody w tablicy Z ; tablicę Z wypełniamy 1296 kodami 4 znakowymi K02: zn ← 1296 ; początkowa liczba kodów w tablicy K03: Dla runda = 1, 2, …, 6: ; rozpoczynamy rozgrywkę wykonuj kroki K04…K18 K04: Jeśli zn = 0, ; jeśli zbiór Z jest pusty, kończymy – błędne dane człowieka to idź do kroku K19 K05: i2 ← losowa(zn) ; losujemy słówko kodowe K06: słamacz ← Z[i2] ; umieszczamy je w łańcuchu słamacz K07: Usuń kod Z[i2] ze zbioru Z K08: zn ← zn-1 ; usuwamy wylosowane słowo i zmniejszamy zn o 1 K09: Pisz runda, słamacz ; wyświetlamy słowo kodowe dla człowieka K10: Czytaj sklucz ; odczytujemy klucz K11: Jeśli sklucz = "xxxx", ; słowo odgadnięte? Jeśli tak, to kończymy to idź do kroku K19 K12: i2 ← 0 K13: Dla i1 = 0, 1, …, zn-1: ; przeglądamy zbiór Z i usuwamy z niego elementy wykonuj kroki K14…K17 ; nie pasujące do otrzymanego klucza K14: Oblicz sklucz2 dla słamacz i Z[i1] ; algorytm obliczania klucza ; podaliśmy w poprzednim rozdziale K15: Jeśli sklucz2 ≠ sklucz, ; słowa kodowe nie pasujące do klucza pomijamy to następny obieg pętli K13 K16: Z[i2] ← Z[i1] ; słowa pasujące do klucza kopiujemy pod i2 K17: i2 ← i2+1 K18: zn ← i2 ; korygujemy liczbę elementów zbioru Z K19: Jeśli sklucz = "xxxx", to zakończ
K20: Dla i1 = 0, 1, …, zn-1: ; wypisujemy pozostałe w zbiorze Z kody wykonuj: pisz Z[i1] K21: Zakończ
|
Uwaga: Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich. |
| Program prowadzi rozgrywkę
|
Pascal// MasterMind-komputer <-> człowiek
// Data: 17.08.2008
// (C)2020 mgr Jerzy Wałaszek
//---------------------------------
program prg;
var
Z : array [0..1295] of string;
skoder, slamacz, sklucz, sklucz2, sl : string;
zn, i, i1, i2, j, runda : integer;
begin
randomize;
// tworzymy zbiór Z
for i := 0 to 1295 do
begin
Z[i] := ''; i2 := i;
for j := 1 to 4 do
begin
Z[i] := Z[i]+chr(65+(i2 mod 6));
i2 := i2 div 6;
end;
end;
zn := 1296; // liczba kodów w Z
// rozgrywka
for runda := 1 to 6 do
if zn > 0 then
begin
i2 := random(zn);
slamacz := Z[i2];
// usuwamy wylosowane słowo ze zbioru Z
for i := i2+1 to zn-1 do
Z[i-1] := Z[i];
dec(zn);
// wylosowane słowo prezentujemy człowiekowi
write('Runda ', runda, ' : ', slamacz, zn:5, ' : ');
// odczytujemy kod klucza
readln(sklucz);
// analizujemy dane
if sklucz = 'xxxx' then break;
// ze zbioru Z wyrzucamy nie pasujące kody
i2 := 0;
for i1 := 0 to zn-1 do
begin
skoder := Z[i1];
sl := slamacz;
sklucz2 := '';
for i := 1 to 4 do
if skoder[i] = slamacz[i] then
begin
sklucz2 := sklucz2+'x';
skoder[i] := '#'; // wartownik w1
sl[i] := '$'; // wartownik w2
end;
for i := 1 to 4 do
if skoder[i] <> '#' then
for j := 1 to 4 do
if skoder[i] = sl[j] then
begin
sklucz2 := sklucz2+'o';
sl[j] := '$'; // wartownik w2
break;
end;
if sklucz = sklucz2 then
begin
Z[i2] := Z[i1];
inc(i2);
end;
end;
zn := i2;
end
else break;
// wyświetlamy pozostałe kody w Z
writeln;
if sklucz <> 'xxxx' then
begin
for i := 1 to zn do
write(Z[i-1], ' ');
writeln; writeln;
end;
end. |
// MasterMind-komputer <-> człowiek
// Data: 17.08.2008
// (C)2020 mgr Jerzy Wałaszek
//---------------------------------
#include <iostream>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
string Z[1296], skoder, slamacz, sklucz, sklucz2, sl;
int zn, i, i1, i2, j, runda;
srand(time(NULL));
// tworzymy zbiór Z
for(i = 0; i < 1296; i++)
{
Z[i] = ""; i2 = i;
for(j = 0; j < 4; j++)
{
Z[i] += char(65+(i2%6));
i2 /= 6;
}
}
zn = 1296; // liczba kodów w Z
// rozgrywka
for(runda = 1; runda <= 6; runda++)
if(zn > 0)
{
i2 = rand()%zn;
slamacz = Z[i2];
// usuwamy wylosowane słowo ze zbioru Z
for(i = i2+1; i < zn; i++)
Z[i-1] = Z[i];
zn--;
// wylosowane słowo prezentujemy człowiekowi
cout << "Runda " << runda
<< ": " << slamacz
<< setw(5) << zn
<< ": ";
// odczytujemy kod klucza
getline(cin, sklucz);
// analizujemy dane
if(sklucz == "xxxx") break;
// ze zbioru Z wyrzucamy nie pasujące kody
for(i2 = i1 = 0; i1 < zn; i1++)
{
skoder = Z[i1];
sl = slamacz;
sklucz2 = "";
for(i = 0; i < 4; i++)
if(skoder[i] == slamacz[i])
{
sklucz2 += 'x';
skoder[i] = '#'; // wartownik w1
sl[i] = '$'; // wartownik w2
}
for(i = 0; i < 4; i++)
if(skoder[i] != '#')
for(j = 0; j < 4; j++)
if(skoder[i] == sl[j])
{
sklucz2 += 'o';
sl[j] = '$'; // wartownik w2
break;
}
if(sklucz == sklucz2)
Z[i2++] = Z[i1];
}
zn = i2;
}
else break;
// wyświetlamy pozostałe kody w Z
cout << endl;
if(sklucz != "xxxx")
{
for(i = 1; i <= zn; i++)
cout << Z[i-1] << " ";
cout << endl << endl;
}
return 0;
} |
Basic' MasterMind-komputer <-> człowiek
' Data: 17.08.2008
' (C)2020 mgr Jerzy Wałaszek
'---------------------------------
Dim As String Z(1295), skoder, slamacz, sklucz, sklucz2, sl
Dim As Integer zn, i, i1, i2, j, runda
Randomize
' tworzymy zbiór Z
For i = 0 To 1295
Z(i) = "": i2 = i
For j = 1 To 4
Z(i) += Chr(65+(i2 Mod 6))
i2 \= 6
Next
Next
zn = 1296 ' liczba kodów w Z
' rozgrywka
For runda = 1 To 6
If zn > 0 Then
i2 = Cint(Rnd*(zn-1))
slamacz = Z(i2)
' usuwamy wylosowane słowo ze zbioru Z
For i = i2+1 To zn-1
Z(i-1) = Z(i)
Next
zn -= 1
' wylosowane słowo prezentujemy człowiekowi
Print Using "Runda # : &##### : ";runda;slamacz;zn;
' odczytujemy kod klucza
Line Input sklucz
' analizujemy dane
If sklucz = "xxxx" Then Exit For
' ze zbioru Z wyrzucamy nie pasujące kody
i2 = 0
For i1 = 0 To zn-1
skoder = Z(i1)
sl = slamacz
sklucz2 = ""
For i = 1 To 4
If Mid(skoder, i, 1) = Mid(slamacz, i, 1) Then
sklucz2 += "x"
Mid(skoder, i, 1) = "#" ' wartownik w1
Mid(sl, i, 1) = "$" ' wartownik w2
End If
Next
For i = 1 To 4
If Mid(skoder, i, 1) <> "#" Then
For j = 1 To 4
If Mid(skoder, i, 1) = Mid(sl, j, 1) Then
sklucz2 += "o"
Mid(sl, j, 1) = "$" ' wartownik w2
Exit For
End If
Next
End If
Next
If sklucz = sklucz2 Then
Z(i2) = Z(i1)
i2 += 1
End If
zn = i2
Next
Else
Exit For
End If
Next
' wyświetlamy pozostałe kody w Z
Print
If sklucz <> "xxxx" Then
For i = 1 To zn
Print Z(i-1);" ";
Next
Print: Print
End If
End |
Python
(dodatek)# MasterMind-komputer <-> człowiek
# Data: 24.03.2024
# (C)2024 mgr Jerzy Wałaszek
#---------------------------------
import random
sklucz = ''
# tworzymy zbiór Z
z = []
for i in range(1296):
z.append("")
i2 = i
for j in range(4):
z[i] += chr(65+(i2%6))
i2 //= 6
zn = 1296 # liczba kodów w Z
# rozgrywka
for runda in range(1, 7):
if zn > 0:
i2 = random.randrange(zn)
slamacz = z[i2][:]
# usuwamy wylosowane słowo ze zbioru Z
for i in range(i2+1, zn):
z[i-1] = z[i][:]
zn -= 1
# wylosowane słowo prezentujemy człowiekowi
print("Runda", runda, ":", slamacz, "%5d" % zn, ":", end=" ")
# odczytujemy kod klucza
sklucz = input()
# analizujemy dane
if sklucz == "xxxx": break
# ze zbioru Z wyrzucamy nie pasujące kody
i2 = 0
for i1 in range(zn):
skoder = z[i1][:]
sl = slamacz[:]
sklucz2 = ""
for i in range(4):
if skoder[i] == slamacz[i]:
sklucz2 += 'x'
skoder = skoder[:i]+'#'+skoder[i+1:]
sl = sl[:i]+'$'+sl[i+1:]
for i in range(4):
if skoder[i] != '#':
for j in range(4):
if skoder[i] == sl[j]:
sklucz2 += 'o'
sl = sl[:j]+'$'+sl[j+1:]
break
if sklucz == sklucz2:
z[i2] = z[i1][:]
i2 += 1
zn = i2
else: break
# wyświetlamy pozostałe kody w Z
print()
if sklucz != "xxxx":
for i in range(1, zn+1):
print(z[i-1], end=" ")
print()
print()
|
| Wynik: |
Runda 1 : CBFF 1295 : o Runda 2 : EAAB 275 : xxo Runda 3 : EABE 14 : xx Runda 4 : EACA 2 : xo Runda 5 : AABB 0 : xxxx |
![]() |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2026 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.