Bölüm 4 · Sunum 4

Adım adım XOX

İki boyutlu dizi, fare tıklaması ve durum makinesi tek bir oyunda buluşuyor.

İki boyutlu diziTahta ve taşlarTıklamadan hücreyeKazanan ve beraberlikVaryantlar

Önce bir el oynayalım

Tıklayarak başlayın; sırayla X ve O koyun. Dolu bir kareye tıklamayı deneyin. Oyun bitince tuvale tıklayıp R’ye basın.

XOX’un kuralları

XOX (Tic-Tac-Toe)İki oyuncunun sırayla 3 × 3 ızgaraya X ve O koyduğu oyun. Aynı işaret yatay, dikey ya da çapraz üç hücreyi doldurursa o oyuncu kazanır. Bütün hücreler dolup kazanan çıkmazsa oyun berabere biter.
KuralAçıklama
Tahta3 satır × 3 sütun = 9 hücre
SıraOyuncular sırayla oynar; X başlar
Geçerli hamleBoş bir hücreye tıklamak
Geçersiz hamleDolu hücre ya da tahta dışı: yok sayılır
KazanmaAynı işaretle üç hücre: 8 olası hat
Beraberlik9 hücre dolu, kazanan yok

Dokuz hücrenin içinde ne olduğunu program nerede tutacak?

Dokuz ayrı değişken mi? Dokuz elemanlı tek bir dizi mi? “Orta satırın sağ hücresi” dediğimizde hangisine bakacağız?

İki boyutlu dizi: dizilerin dizisi

Dış dizinin üç elemanı var; her biri üç elemanlı bir dizi, yani bir satır.

İfadeAnlamı
tahta[0]İlk satır (üç elemanlı dizi)
tahta[1][2]2. satır, 3. sütun
""Boş hücre
"X" / "O"Dolu hücre: o karedeki taş

Erişim hep aynı sırayla: tahta[satir][sutun]. Önce satır, sonra sütun.

Satır ve sütun indeksleri

3×3 tahta: iki boyutlu dizi indeksleri
Her hücre boş metin ya da "X" / "O" tutar. İlk indeks satır, ikinci indeks sütun.

Fareyi hücrelerin üstünde gezdirin

tahta[1] bütün bir satırı, tahta[1][2] o satırdaki tek bir hücreyi verir.

İki farklı “kare”

Framedraw() fonksiyonunun bir kez çalışması. Oyun döngüsünün bir turu.
Hücre (kare)Izgaradaki tek bir oyun alanı. Bu sunumda “kare” yalnızca tahta hücresi anlamında.
Boyutlartahta.length satır sayısını (3), tahta[0].length sütun sayısını verir. XOX hep 3 × 3 olduğu için döngülerde 0–2 aralığı yeter.

Aynı tahtayı 9 elemanlı düz bir dizide tutsak ne kaybederiz?

“2. satır, 3. sütun” hangi indeks? Peki hemen altındaki hücre?

Izgara dünyasının doğal dili

Düz dizide her seferinde bir formül gerekir: satir * 3 + sutun. Izgara büyüdükçe hata ve okuma yükü artar.

tahta[satir][sutun]“Burada ne var?” sorusunu doğrudan sorar.
  • Komşular: satir ± 1, sutun ± 1.
  • Kazanma çizgileri: aynı satır, aynı sütun, çapraz.
  • “Bu sütunda aşağı düş” gibi kurallar.

Hepsi aynı indeks diline oturur. Birçok oyun dünyası bir satır-sütun ızgarasıdır: her hücre tek bir yanıt tutar.

Hücrede ne tutuluyor? (1/2)

XOX 3 × 3Boş, X ya da O.
Satranç, dama 8 × 8Boş ya da taşın türü.
Mayın Tarlası 9 × 9Kapalı, açık, mayın, bayrak.
Connect Four 6 × 7Boş ya da renkli taş. Taş sütunda aşağı kayar.

Sıra hep aynı: önce tahtayı diziyle modelle, sonra çiz, sonra kuralları uygula. XOX bu sıranın en küçük tam projesi.

Hücrede ne tutuluyor? (2/2)

Tetris 20 × 10Boş ya da dolu blok.
2048, Candy CrushSayı, renk ya da boş.
Pac-Man labirentiYol, duvar, nokta, kapı. Platform oyunlarındaki karo haritalar (tile map) da böyle.
Sudoku 9 × 91–9 arası bir sayı ya da boş.
Üç ve daha fazla boyutBazen üçüncü bir indeks işe yarar: katman[z][y][x] ile Minecraft tarzı blok dünyası gibi. Ayrı bir sihir değil; ızgara fikrinin doğal uzantısı. Çoğu iki boyutlu oyun tek bir matris ve birkaç yardımcı diziyle ilerler.

Veri: sabitler, değişkenler, sıfırlama

DeğişkenGörevi
oyunDurumuMenü, oyun ya da bitiş
tahta3 × 3 hücre verisi
siraSıradaki oyuncunun işareti
sonucBitiş ekranında gösterilecek sonuç

createCanvas(300, 300) ve HUCRE = 100: üç hücre tuvali tam kaplar. oyunuSifirla() tahtayı boşaltır, sırayı X’e verir.

Çizimi dört fonksiyona bölmek

FonksiyonSorumluluğu
cizTahtaCizgileri()Arka plan ve ızgara çizgileri
taslariCiz()Dolu hücreleri dolaşır, her biri için tasCiz’i çağırır
tasCiz(x, y, boyut, deger)Tek bir hücreye X ya da O yazar
cizOyunEkrani()Tahta + taşlar + sıra yazısı

Tanıdık bir yapı: Bölüm 2’deki tahtaCiz ve hucreCiz. O zaman “ileride XOX’ta kullanacağız” demiştik.

Tahta çizgileri ve tek bir taş

Dört line: iki dikey, iki yatay. Taş, hücrenin ortasına textAlign(CENTER, CENTER) ile yazılan bir harf; X kırmızı, O mavi.

Diziyi gez, dolu hücreleri çiz

Veri ile görüntü ayrı: çizim her frame dizinin o anki hâlini yansıtır. Kodu kopyalayıp dizideki bir "" yerine "O" yazın; çizim kendiliğinden değişir.

Oyuncu (150, 220) pikseline tıkladı. Hangi hücre?

Fare bize piksel veriyor; dizimiz ise satır ve sütun istiyor. Hücreler 100 piksel. Pikselden indekse nasıl geçeriz?

Böl ve aşağı yuvarla

Bir tıklamanın yolculuğu

AdımKontrolSonuç
1Menüde miyiz?Evetse oyunuSifirla(), oyuna geç ve çık
2Oyun durumunda mıyız?Değilse return
3satir ve sutun 0–2 aralığında mı?Değilse return
4Hücre boş mu?Doluysa return
5Hamleyi yaztahta[satir][sutun] = sira
6Kazanan ya da beraberlik var mı?Varsa bitişe geç
7Sırayı diğer oyuncuya verX ↔ O

İlk dört adım birer kapı bekçisi: geçersiz her tıklama erken return ile elenir. Asıl iş tek satır.

mousePressed (1/2): bekçiler ve hamle

  • Menüde tıklamak oyunu başlatır.
  • Bitiş ekranında tıklama yok sayılır: “duruma göre girdi”.
  • Tahta dışı ve dolu hücre elenir.
  • Geriye kalan geçerli bir hamledir: sıradaki işaret diziye yazılır.
  • Çizim için hiçbir şey yapmıyoruz; bir sonraki draw yeni taşı kendisi çizecek.

mousePressed (2/2): sonuç ve sıra

  • Her hamleden sonra önce kazanan, sonra beraberlik kontrol edilir.
  • Oyun bittiyse sıra değiştirilmez; return ile çıkılır.
  • Oyun sürüyorsa sıra if / else ile X ve O arasında değişir.

Üçlü olmanın kaç farklı yolu var?

Yatay, dikey, çapraz… Hepsini sayın. Program bunların hepsine tek tek bakmak zorunda mı?

Sekiz kazanma hattı

Kazanma koşulu: üç hücrede aynı işaret ve o hücrelerin boş olmaması.

kazananKontrol: iki döngü, iki if

kazananKontrol nasıl okunur?

İlk forÜç yatay satır: tahta[i][0], [i][1], [i][2].
İkinci forÜç dikey sütun: tahta[0][j], [1][j], [2][j].
İki ifİki çapraz. Kazanan yoksa "" döner.

Fonksiyon kazananın işaretini ("X" ya da "O") döndürür. İlk bulduğu üçlüde return ile çıkar; geri kalan hatlara bakmaz.

Sekiz hat, dört kontrolDöngü değişkeni i satırı, j sütunu gezdiği için üç yatay ve üç dikey hat ikişer satıra sığıyor.

Koşuldaki !== "" kısmını silersek ne olur?

Oyunun en başında tahta nasıl görünüyor?

Üç boş hücre de “birbirine eşit”

🏆Tebrikler! Kazanan:Boş tahtada üst satır: "" === "" === "". Üçlü sayılır ve fonksiyon "" döndürür.
Şansımıza oyun bozulmaz, ama…Dönen değer "" olduğu için “kazanan yok” gibi görünür. Fakat fonksiyon ilk satırda çıktığı için diğer hatlara hiç bakmaz. Üst satır boşken alt satırdaki gerçek üçlü görülmez.
KuralÜç hücre birbirine eşit ve boş değil.

Beraberlik ve bitiş ekranı

Tek bir boş hücre bulunca false döner ve aramayı bırakır. Tahta dolu ve kazanan yoksa beraberlik. Bitiş ekranı sonuc’a bakıp mesajı seçer.

XOX’un geçiş tablosu

Mevcut durumOlay / koşulYeni durumEk işlem
DURUM_MENUSPACE ya da tıklamaDURUM_OYUNoyunuSifirla()
DURUM_OYUNGeçerli tıklama, kazanan varDURUM_BITISsonuc = kazanan
DURUM_OYUNGeçerli tıklama, tahta doluDURUM_BITISsonuc = "beraberlik"
DURUM_OYUNGeçerli tıklama, oyun sürüyorDURUM_OYUNSıra X ↔ O
DURUM_OYUNGeçersiz tıklamaDURUM_OYUN—
DURUM_BITISR basıldıDURUM_MENU—

Omurga Kaç-Kaç Top ile aynı. X ve O sırası ayrı birer durum değil; oyun durumunun içinde sira değişkeninde tutulan alt bilgi.

setup ve yönlendirici draw

Menü ve oyun ekranı

Klavye: başlat ve menüye dön

Menüden oyuna hem SPACE hem tıklama ile geçilir; ikisi de oyunuSifirla()’yı çağırır. Hamleler fareyle, menü geçişleri klavyeyle.

Bu projede her şey var

Bölüm 1Koordinat, text, if / else, mousePressed, return.
Bölüm 2İç içe for, modüler çizim fonksiyonları, oyun döngüsü.
Bölüm 3Diziler, floor, keyPressed.
Bölüm 4Durum makinesi, geçiş tablosu, iki boyutlu dizi.
Sırada ne var?Aynı tahta[satir][sutun] iskeletiyle bilgisayar rakibi (Minimax), Connect Four, Yılan ve Mayın Tarlası. Onlar İleri Teknikler kitabının konusu.

Yapay zekâyla: ızgara oyunları

  1. Önce siz: bildiğiniz iki oyun seçin. Her biri için bir cümle: “Bu oyunda ızgaranın bir hücresi ne tutuyor?”
  2. Sorun: “Oyun programlamada iki boyutlu dizi neden sık kullanılır? En az 6 bilinen oyunda tahta nasıl ızgara gibi düşünülür, hücrede ne tutulur? Tek boyutlu diziyle modellemek ne zaman zahmetli olur? Üç boyutlu dizinin işe yaradığı bir iki örnek ver. Kod yazma.”
  3. Doğrulayın: verdiği örneklerden ikisini kısa bir aramayla kontrol edin. Uydurma oyun ya da yanlış tahta boyutu var mı?
  4. Kendi cümlenizle yazın: yapmak istediğiniz küçük bir oyunda ızgara kullanır mısınız? Hücrede ne tutarsınız?

Yapay zekâyla: XOX varyantlarını keşfedin

  1. Çevrimiçi bir iki el klasik XOX oynayın; Wikipedia’daki varyant listesine göz atın.
  2. Sorun: “Elimde klasik 3 × 3 XOX var. Bu iskeletle kodlanabilecek en az 4 varyantı anlat. Hangisi yalnızca sembol değiştirmekle biter, hangisi kazanma kontrolünü ya da tahta boyutunu değiştirmeyi gerektirir? Kod yazma; Minimax anlatma.”
  3. Bir varyant seçin. Kâğıda, kodda nelerin değişeceğini en az iki maddeyle yazın. Bakılacak yerler: sira ve taş metinleri, tasCiz, kazananKontrol, createCanvas ve HUCRE, bitiş mesajı.

Kendi XOX varyantınızı yazın

SeçenekNe değişir?Zorluk
A · SembolX ve O yerine A / B, ★ / ● ya da iki kısa kelime. Menü ve bitiş yazıları uyumlu.Kolay
B · Ters XOXÜçlü yapan kaybeder. Bitiş yazısı ve sonuc mantığı tersine döner.Orta
C · 4 × 4Tahta 4 × 4; yine üç aynı işaret kazandırır. HUCRE ve döngü sınırları büyür.Orta–zor
D · Serbest işaretOyuncu önce taşı seçer (1 → X, 2 → O), sonra boş hücreye tıklar.Orta–zor
  1. Plan: hangi sabit ve değişken değişir? kazananKontrol aynı mı kalır? Bitişte ne yazmalı?
  2. Kod: kitaptaki XOX’un bir kopyasında önce klasik oyunun çalıştığını görün; sonra yalnızca gereken satırları değiştirin.
  3. Takılınca: yapay zekâdan önce açıklama, sonra yalnızca gerekli satırların düzeltmesini isteyin.

Yapay zekâsız deneyin

  1. Üç ızgara oyunu seçin. Her biri için yazın: satır × sütun tahmini ve hücrede tutulan veri. Hangisinde tahta[satir][sutun] doğrudan işe yarar?
  2. XOX kopyasında X ve O yerine kendi iki sembolünüzü kullanın; menü ve bitiş yazılarını uyumlu yapın. Bir tam tur oynayın.
  3. Bu değişiklik kazananKontrol’e neden hiç dokunmadan çalışıyor?
  4. Ters XOX için mousePressed ve bitiş dalında neyi tersine çevireceğinizi üç maddeyle planlayın.

HUCRE = 100. Oyuncu (299, 0) pikseline tıkladı. Hangi hücre?

  1. tahta[2][0]
  2. tahta[0][2]
  3. tahta[3][0]
  4. tahta[0][3]

sutun = floor(299 / 100) = 2, satir = floor(0 / 100) = 0. Dizide önce satır yazılır: tahta[0][2], sağ üst köşe.

Sıra değiştirme satırlarını kazanan kontrolünün önüne alırsak ne bozulur?

  1. Hiçbir şey; sıra önemli değil.
  2. Kazanan hiç bulunamaz.
  3. Kazanan doğru bulunur ama ekranda “Sıra” yazısı gereksiz yere değişir; ileride sira’ya güvenen kod yanlış oyuncuyu gösterir.

kazananKontrol tahtaya bakıyor, sira’ya değil; o yüzden kazanan doğru çıkar. Ama “kazanan = sira” diye yazılmış bir sürümde yanlış oyuncu kazanırdı. Sıra, oyun sürüyorsa değişmeli.

tahta[1].length ve tahta.length sırasıyla neyi verir?

  1. Satır sayısı ve sütun sayısı
  2. Bir satırdaki sütun sayısı ve satır sayısı
  3. İkisi de toplam hücre sayısı: 9

tahta satırların dizisi: uzunluğu satır sayısı. tahta[1] tek bir satır: uzunluğu o satırdaki hücre sayısı.

Merak edenler için kaynaklar

Kitap 1’i bitirdik

  • İki boyutlu dizi: tahta[satir][sutun]. Önce satır, sonra sütun.
  • Izgara oyunlarının ortak sırası: veriyi modelle, çiz, kuralları uygula.
  • Pikselden hücreye: floor(mouseX / HUCRE) ve floor(mouseY / HUCRE).
  • Geçersiz tıklamalar erken return ile elenir.
  • Sekiz kazanma hattı; hücreler eşit ve boş değil. Önce kazanan, sonra beraberlik.
  • Menü, oyun, bitiş: aynı durum makinesi omurgası.

Kitap 1 tamamlandı

Bir tuvalden tam bir oyuna

Gri bir kareyle başladık; menüsü, kuralları ve kazananı olan bir oyunla bitirdik.