9.6 Noslēguma projekts: "Krustiņi un nullītes" pārlūkā
Stundas uzdevums: Apvienot visas tēmas prasmes - Streamlit, session_state, ārējie API - pilnvērtīgā tīmekļa spēlē "Krustiņi un nullītes".
70 min plāns: Ievads un kritēriju pārruna (~10 min) · 1. uzdevums (~15 min) - uzzīmē 3x3 laukumu ar pogām · 2. uzdevums (~25 min) - pievieno gājienus un uzvaras pārbaudi · 3. uzdevums (~20 min) - pievieno statistiku un restartu. Papildu uzdevumu sāc tikai tad, ja pārējie trīs ir gatavi.
Pirms sāc: šis ir 9. tēmas noslēguma projekts. Izmanto Streamlit un st.session_state. Sāc ar tukšu laukumu un tikai tad ķeries pie uzvaras loģikas.
Teorija: Spēles apraksts un arhitektūra
Tava noslēguma spēle ir "Krustiņi un nullītes" pārlūkā, kas izmanto Streamlit, lai abi spēlētāji uz viena datora var spēlēt pret otru (vai pret vienkāršu AI).
Funkcijas:
- 3×3 spēles laukums ar pogām.
- Maiņa starp X un O spēlētājiem.
- Uzvaras pārbaude (8 kombinācijas).
- Statistika sesijas laikā: kurš ir uzvarējis vairāk reizes.
- Reset poga jaunai spēlei.
- Opcija "Spēlēt pret AI" ar minimax algoritmu.
Failu struktūra:
krustini/
├── app.py # Streamlit galvenā lapa
├── spele.py # Spele klase ar loģiku
├── ai.py # AISpeletajs ar minimax
└── requirements.txt
Praktiskie uzdevumi
1. uzdevums -
Uzzīmē 3x3 laukumu ar pogām
Beigās ekrānā būs deviņas pogas trīs rindās.
- Izveido failu
krustini.pyun importē Streamlit. - Izveido
st.session_state.laukums = ["" for _ in range(9)], ja tā vēl nav. - Uzraksti ciklu
for rinda in range(3):. - Izveido katrā rindā
cols = st.columns(3). - Ieliec katrā kolonnā pogu ar unikālu
key. - Palaid un pārbaudi, ka redzamas deviņas pogas.
Gatavs, kad: ekrānā ir 3x3 pogu režģis, un nospiežot pogu lapa nekļūdās.
2. uzdevums -
Pievieno gājienus un uzvaras pārbaudi
Beigās spēle pateiks, kurš uzvarējis.
- Ieraksti pogas nospiešanas brīdī laukumā
XvaiO. - Nomaini pašreizējo spēlētāju pēc katra gājiena.
- Neļauj pārrakstīt jau aizņemtu rūtiņu.
- Izveido sarakstu ar visām 8 uzvaras kombinācijām.
- Pārbaudi pēc katra gājiena, vai kāda kombinācija ir aizpildīta ar vienu simbolu.
- Izdrukā uzvarētāju ar
st.success(). - Izspēlē vienu partiju līdz uzvarai.
Gatavs, kad: spēle pareizi paziņo uzvarētāju un neļauj spēlēt uz aizņemtas rūtiņas.
3. uzdevums -
Pievieno statistiku un restartu
Beigās varēs spēlēt vairākas partijas pēc kārtas.
- Pievieno
session_stateskaitītājus X un O uzvarām. - Palielini attiecīgo skaitītāju pēc katras uzvaras.
- Izdrukā abus rezultātus lapas augšā.
- Pievieno pogu
Jauna spēle, kas notīra laukumu, bet ne statistiku. - Pievieno neizšķirta pārbaudi, kad visas rūtiņas aizpildītas.
- Izspēlē trīs partijas pēc kārtas.
- Veic commit, push un iesniedz krātuves saiti.
Gatavs, kad: pēc trim partijām statistika rāda pareizu uzvaru skaitu, un neizšķirts tiek atpazīts.
Papildu uzdevums - Pievieno vienkāršu AI
Ja pamatdarbs ir gatavs, ļauj spēlēt pret datoru.
- Pievieno sānjoslā izvēli
Spēlēt pret AI. - Uzraksti funkciju, kas izvēlas nejaušu brīvu rūtiņu.
- Izsauc to pēc cilvēka gājiena.
- Uzlabo AI: ja tas var uzvarēt vienā gājienā, lai izvēlas tieši to.
- Izspēlē partiju pret AI.
Gatavs, kad: AI aizpilda uzvaras rūtiņu, kad tāda ir pieejama, nevis izvēlas nejauši.
Biežākās kļūdas
- Pogu re-render visu lapu: Streamlit pārpalaiž skriptu - visas pogas jāzina savu key.
- session_state sajaukts: Piedēvē unikālus atslēgvārdus visiem objektiem (
game_id,spele, etc). - AI pārāk lēns: Minimax 9 līmeņu dziļumam ir ātrs (8! = 40320 stāvokļi); ja lietotnē kavējās, pievieno alpha-beta pruning.
Koda piemērs
import streamlit as st
class Spele:
UZVARES = [(0,1,2),(3,4,5),(6,7,8),(0,3,6),(1,4,7),(2,5,8),(0,4,8),(2,4,6)]
def __init__(self):
self.laukums = ["" for _ in range(9)]
self.pasreizejais = "X"
def gajiens(self, p):
if self.laukums[p] or self.uzvaretajs(): return
self.laukums[p] = self.pasreizejais
self.pasreizejais = "O" if self.pasreizejais == "X" else "X"
def uzvaretajs(self):
for a,b,c in self.UZVARES:
if self.laukums[a] == self.laukums[b] == self.laukums[c] != "":
return self.laukums[a]
return "neizšķirts" if "" not in self.laukums else None
if "spele" not in st.session_state:
st.session_state.spele = Spele()
s = st.session_state.spele
for r in range(3):
cols = st.columns(3)
for c in range(3):
i = r*3 + c
cols[c].button(s.laukums[i] or " ", key=i, on_click=s.gajiens, args=(i,))
u = s.uzvaretajs()
if u: st.success(f"Uzvarētājs: {u}")
else: st.info(f"Gājiens: {s.pasreizejais}")
if st.button("↻ Jauna spēle"):
st.session_state.spele = Spele()
st.rerun()
Pēc katra klikšķa simbols mainās;
Uzvaras paziņojums tiek parādīts.