Spotkanie X.

Proste reguły, niełatwe gry – część 1

Nasze jubileuszowe spotkanie poświęcimy grom. Będą to najczęściej gry dla dwóch graczy / drużyn, w których nie będzie losowości (nie używamy np. kostek czy tasowanych kart), grający dysponują jednakowymi informacjami o sytuacji w grze, a ruchy odbywają się naprzemiennie. Część z przedstawionych tu gier jest znana od dawna (np. gry typu NIM), inne są mniej popularne, wszystkie jednak w jakiś sposób rozwijają myślenie logiczne, abstrakcyjne i algorytmiczne.

Gra 1. Na stole, w jednym stosie, leży pewna liczba kamyków. Każdy gracz w swoim ruchu może z tego stosu zabrać 1 lub 2 lub 3 lub 4 kamyki. Wygrywa ten z graczy, po ruchu którego nie pozostanie już na stole żaden kamień.

Przykładowa rozgrywka dla 23 kamieni; grają gracze A i B:

    \[23\overset{A}{\longrightarrow}  21 \overset{B}{\longrightarrow} 17 \overset{A}{\longrightarrow} 16 \overset{B}{\longrightarrow}12 \overset{A}{\longrightarrow}9 \overset{B}{\longrightarrow}5 \overset{A}{\longrightarrow}4 \overset{B}{\longrightarrow}0.\]

Co oznacza, że wygrał gracz B (bo to on wykonał ostatni ruch).

Ćwiczenie 1. Rozegrajcie w parach co najmniej cztery partie w tę grę; dla początkowej liczby kamieni równej np. 15, 17, 20, 23. Starajcie się grać w taki sposób, aby wygrać. Przed każdą grą ustalcie kto rozpoczyna.

Ćwiczenie 2. Poniższy program gra w tę grę w sposób optymalny (jeżeli tylko można, to komputer wygra). Rozegraj z komputerem kilka partii i spróbuj wytłumaczyć na czym polega ,,spryt” tego programu.

import random

def ruch_komputera(k) :
    print(": Ruch Komputera. ",end="")
    if k % 5 == 0 :
        return 1
    else :
        return (k % 5)

def ruch_gracza(k) :
    x = 0
    while x>4 or x<1 or (k<4 and x>k) :
        x = int(input(": Twój ruch. Ile kamyków zabierasz? "))
    return x

def stan_gry(k) :
    print("-> Na stole leży ",k," kamyków.")

def ruch(k) :
    global n
    print("-> Zabrano kamieni: ",k)
    n = n - k

n = random.randint(15,30)
stan_gry(n)
r = ""
while r!="k" and r!="c" :
    r = input("Wybierz kto zaczyna?\n k = komputer,\t c = czlowiek  ")

if r=="c" :
    ruch(ruch_gracza(n))
    stan_gry(n)
    
while n>0 :
    ruch(ruch_komputera(n))
    stan_gry(n)
    if n>0 :
        ruch(ruch_gracza(n))
        stan_gry(n)
        if n==0 :
            print("Wygrał Człowiek!\n")
    else :
        print("Wygrał Komputer!\n")

Gra 2. Podobnie jak poprzednio, na stole znajduje się stos kamyków. Gracze mogą w jednym ruchu wziąć ze stosu 1 lub 2 lub 4 kamienie (ale nie mogą zabrać trzech kamieni). Wygrywa ten z graczy, po ruchu którego stół pozostanie pusty.

Przykładowa rozgrywka dla 17 kamieni; grają gracze A i B:

    \[17\overset{A}{\longrightarrow}  16 \overset{B}{\longrightarrow} 12 \overset{A}{\longrightarrow} 10 \overset{B}{\longrightarrow}9 \overset{A}{\longrightarrow}5 \overset{B}{\longrightarrow}3 \overset{A}{\longrightarrow}1 \overset{B}{\longrightarrow}0.\]

Co oznacza, że znów wygrał gracz B (bo to on wykonał ostatni ruch).

Ćwiczenie 3. Rozegrajcie w parach kilka partii. Jak myślicie, czy w tym przypadku także jest jakiś prosty sposób grania prowadzący do zwycięstwa?

Ćwiczenie 4. Spróbuj stwierdzić (sprawdzając bezpośrednio), który z graczy, dla początkowej liczby kamieni na stole wynoszącej 3, 4, 5, 6, 7, 8 lub 9 może sobie zapewnić wygraną w tej grze (zakładamy, że gracze podczas gry decyzje podejmują racjonalnie). Grę rozpoczyna zawsze gracz A. Wyniki możesz zebrać w tabelce:

Liczba kamieni123456789
Wygra gracz Ataktak
Wygra gracz Bnienie

Gra 3. Tym razem na stole znajdują się dwa odrębne stosy kamieni. Gracze wykonują ruchy naprzemiennie, a w jednym ruchu każdy z grających może z dowolnego (ale jeszcze niepustego) stosu zabrać dowolną liczbę kamieni (nawet cały stos!) – trzeba jednak wziąć przynajmniej jeden kamień. Zwycięża ta osoba, która zabierze ostatni kamień ze stołu.

Przykładowy przebieg partii dla sytuacji początkowej (16, 21). Co oznacza, że pierwszy stos zawiera 16, a drugi 21 kamieni.

(1)   \begin{eqnarray*} (16,21)&\overset{A}{\longrightarrow}&(10,21)\overset{B}{\longrightarrow}(10,11)\overset{A}{\longrightarrow}(1,11)\\ &\overset{B}{\longrightarrow}&(1,2)\overset{A}{\longrightarrow}(1,1)\overset{B}{\longrightarrow}(1,0)\overset{A}{\longrightarrow}(0,0). \end{eqnarray*}

Tym razem jak widać, zwyciężył pierwszy gracz.

Ćwiczenie 4. Po rozegraniu kilku partii spróbuj opisać, z których wyjściowych pozycji (pozycja w tej grze to liczby kamieni w obu stosach) łatwo doprowadzić do wygranej. W jaki sposób należy wtedy grać?

Ćwiczenie 5. Spróbuj zapisać algorytm (w postaci kroków lub odpowiedniego diagramu ze strzałkami), który odpowiadałby schematowi działania dla optymalnego sposobu gry.

Opis gry ,,Taśma”

Gra odbywa się na planszy w kształcie taśmy podzielonej na jednakowe kwadratowe pola. Taśma ma szerokość 1 pola i pewną długość n pól (poniższy rysunek pokazuje taśmę o długości 14 pól; dla jasności opisu, pola zostały ponumerowane).

\begin{tikzpicture} \draw[very thick,brown,fill=yellow!10!white] (0,0) grid (14,1); \foreach \x in {1,...,14}    \node[black!50!white,scale=1.3] at (\x-0.5,0.5) {\x};  \end{tikzpicture}

Grają dwie osoby wykonując ruchy naprzemiennie. W każdym ruchu dany gracz wybiera dowolne puste pole z taśmy i zakreśla je. Wraz z zakreślonym polem z dalszej gry wykluczone są pola z nim sąsiadujące (o ile pola te nie zostały wykluczone już wcześniej). Grę wygrywa ten z graczy, który jako ostatni mógł wykonać swój ruch.

Przykładowo, po dwóch kolejnych ruchach, w których gracz A (czerwony) wybierał pola: 3 i 10, zaś gracz B (niebieski) wybierał pola 14 i 5, plansza wygląda jak poniżej.

\begin{tikzpicture} \draw[very thick,brown,fill=yellow!10!white] (0,0) grid (14,1); \foreach \x in {1,...,14}    \node[black!40!white,scale=1.3] at (\x-0.5,0.5) {\x};   \foreach \x in {3,10}   \draw[ultra thick,red] (\x-0.9,0.1)--(\x-0.1,0.9) (\x-0.9,0.9)--(\x-0.1,0.1);  \foreach \x in {14,5}   \draw[ultra thick,blue] (\x-0.9,0.1)--(\x-0.1,0.9) (\x-0.9,0.9)--(\x-0.1,0.1);  \foreach \x in {2,4,9,11,6,13}    {    \draw[thin,fill=black!25!white] (\x-1,0) rectangle (\x,1);    \node[black!50!white,scale=1.3] at (\x-0.5,0.5) {\x};    } \end{tikzpicture}

Pozostały jeszcze cztery wolne pola, które wypełnią się w najbliższych trzech zagraniach. Oznacza to, że sytuacja taka jest dla gracza A zwycięska.

Grać w ,,taśmę” można na zwykłej kartce papieru, ustalając na początku długość planszy (minimum 10 pól) i zakreślając kolejno wybierane pola oraz pola sąsiednie. Oczywiście im plansza jest dłuższa, tym rozgrywka staje się ciekawsza.

4 myśli w temacie “Spotkanie X.”

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *