Ana Başlık 4. Adım Adım: XOX (Tic-Tac-Toe)

Amaç: İki boyutlu dizi, fare tıklaması ve durum makinesini birleştirerek tam bir XOX oyunu kodlamak; Önceki bölümlerde öğrenilen girdi, modüler çizim ve oyun aşamalarını tek projede toplamak.

Öğrenme Çıktıları:

Anahtar Sözcükler: XOX, tic-tac-toe, iki boyutlu dizi, ızgara, matris, hamle, kazanma koşulu, beraberlik, durum makinesi

Giriş

Önceki ana başlıkta durum makinesi ile menü, oyun ve bitiş aşamaları oyunDurumu değişkeniyle yönetilmişti; Kaç-Kaç Top örneğinde SPACE ile başlama, çarpışma ile bitiş ve R ile menüye dönüş kodlanmıştı. XOX (Tic-Tac-Toe) oyunu aynı üç aşamalı iskeleti kullanır; fark, DURUM_OYUN içinde 3×3 ızgara tahtası ve sırayla X/O yerleştirme mantığının çalışmasıdır.

Önceki bölümlerde tek boyutlu diziler, iç içe for döngüleriyle ızgara çizimi ve modüler tahtaCiz / hucreCiz fonksiyonları tanıtılmıştı. Önceki bölümlerde fare tıklaması (mousePressed), klavye (keyPressed) ve durum makinesi eklendi. Bu ana başlıkta tahta verisi iki boyutlu dizi (tahta[satir][sutun]) ile saklanır; her frame'de (her draw() çağrısında) tahta çizilir, hamle yalnızca fare tıklandığında işlenir. Böylece sürekli animasyon ile olay tabanlı girdi aynı sketch'te birleşir; çizim her frame yenilenirken kurallar tıklama anında uygulanır.

Dikkat: p5.js'te frame, draw() fonksiyonunun bir kez çalışmasıdır (Bölüm 2 Ana Başlık 4). XOX tahtasındaki kare (hücre) ise ızgaradaki tek bir oyun alanıdır; burada kare sözcüğü yalnızca tahta hücresi anlamında kullanılır, oyun döngüsü frame'i ile karıştırılmaz.

4.1. Oyun Kuralları ve Veri Yapısı

Tanım: XOX (Tic-Tac-Toe) — İki oyuncunun sırayla 3×3 ızgara üzerinde X ve O işaretleri koyduğu; aynı işaretin yatay, dikey veya çapraz üç hücreyi doldurmasıyla kazanılan, tüm hücreler dolunca kazanan çıkmazsa beraberlikle biten masa oyunudur.

Temel kurallar:

Tablo 1.

Kural Açıklama
Tahta 3 satır × 3 sütun = 9 hücre
Sıra Oyuncular sırayla hamle yapar; örnekte X başlar
Geçerli hamle Boş hücreye tıklama
Geçersiz hamle Dolu hücreye veya tahta dışına tıklama — yok sayılır
Kazanma Aynı işaretle üç hücre (8 olası hat)
Beraberlik 9 hücre dolu, kazanan yok

Klasik XOX kurallarını denemek için kaynaklardaki çevrim içi tahta bağlantısına bakılabilir.

Tahta durumu iki boyutlu dizi ile modellenir. Önceki bölümlerdeki tek boyutlu dizi[0], dizi[1] yapısının satır–sütun karşılığı tahta[satir][sutun] erişimidir:

Kod 1.

javascript
let tahta = [  ["", "", ""],  ["", "", ""],  ["", "", ""]];

Tablo 2.

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

Görsel 1. 3×3 tahta — iki boyutlu dizi indeksleri (satır, sütun)
Görsel 1. 3×3 tahta — iki boyutlu dizi indeksleri (satır, sütun)

Görsel 1, tahta[satir][sutun] erişiminde satırın önce, sütunun sonra geldiğini ve her hücrenin boş string veya "X" / "O" tuttuğunu gösterir.

Oyun durumu için önceki ana başlıktaki sabitler korunur; tahta mantığına ek değişkenler eklenir:

Kod 2.

javascript
const DURUM_MENU = "menu";const DURUM_OYUN = "oyun";const DURUM_BITIS = "bitis";const HUCRE = 100; let oyunDurumu;let tahta;let sira;      // "X" veya "O" — şu an kim oynuyorlet sonuc;     // kazanan ("X"/"O") veya "beraberlik"

Tablo 3.

Değişken Görev
oyunDurumu Menü / oyun / bitiş aşaması (Ana Başlık 2)
tahta 3×3 hücre verisi
sira Sıradaki oyuncunun işareti
sonuc Bitiş ekranında gösterilecek sonuç metni

Tuval boyutu tahta ile uyumludur: createCanvas(300, 300) ve HUCRE = 100 → 3×3 kare tam tuvali kaplar. oyunuSifirla() yeni turda tahtayı boşaltır ve sırayı X'e verir:

Kod 3.

javascript
function oyunuSifirla() {  tahta = [    ["", "", ""],    ["", "", ""],    ["", "", ""]  ];  sira = "X";  sonuc = "";}

Bilgi: İki boyutlu dizi, önceki bölümlerdeki dizinin iç içe kullanımıdır; tahta.length satır sayısını (3), tahta[0].length sütun sayısını verir. XOX sabit 3×3 olduğu için döngülerde 0–2 aralığı yeterlidir.

Neden oyun programlamada iki boyutlu dizi? Birçok oyun dünyası satır–sütun ızgarasıdır: her hücre “burada ne var?” sorusuna tek bir yanıt tutar (boş, taş, duvar, mayın, yem…). tahta[satir][sutun] bu soruyu doğrudan sorar. Komşu hücreler (satir ± 1, sutun ± 1), kazanma çizgileri veya “bu sütunda aşağı düş” gibi kurallar da aynı indeks diline oturur. Aynı veriyi tek boyutlu 9 (veya 64) elemanlı dizide tutmak mümkündür; fakat “2. satır, 3. sütun” her seferinde elle formülle çevrilir — ızgara büyüdükçe hata ve okuma maliyeti artar.

Tanıdık oyunlarda tipik kullanım (hücrede ne tutulduğunun özeti):

Tablo 4.

Oyun Tipik ızgara Hücrede örnek veri
XOX / üç taş 3×3 boş / X / O
Satranç, dama 8×8 boş veya taş türü
Mayın Tarlası örn. 9×9 kapalı / açık / mayın / bayrak
Connect Four 6×7 boş / renkli taş (sütunda aşağı kayar)
Tetris örn. 20×10 boş veya dolu blok
2048, match-3 (Candy Crush tarzı) N×N veya N×M sayı / renk / boş
Pac-Man labirenti, birçok platform tile map geniş ızgara yol / duvar / nokta / kapı
Sudoku 9×9 1–9 veya boş

Bu örneklerin hepsi “önce tahtayı diziyle modelle, sonra çiz ve kuralları uygula” sırasını paylaşır; XOX o sıranın en küçük tam projesidir. İleri Teknikler kitabında aynı fikir büyür: Yılan ve Connect Four’da daha büyük matris, Mayın Tarlası’nda hücre durumu zenginleşir.

Çok boyutlu dizi (kısa bakış): Üç veya daha fazla indeks bazen işe yarar — örneğin katman[z][y][x] ile Minecraft tarzı blok dünyası, veya kare[satir][sutun][ozellik] ile aynı hücrede birkaç sayı. Bu kitapta önce iki boyutlu tahta yeterlidir; çok boyutlu yapı, ızgara fikrinin doğal uzantısıdır, ayrı bir sihir değildir. Pratikte çoğu 2B oyun tek matris + birkaç yardımcı dizi ile ilerler.

4.2. Tahta ve Taş Çizimi

Tahta çizimi modüler fonksiyonlara ayrılır (Bölüm 2'in 3. ana başlığı): çizgiler, taşlar ve oyun ekranı birleşimi ayrı bloklardadır. draw() içinde DURUM_OYUN iken yalnızca oyun ekranı çizilir; menü ve bitiş Ana Başlık 2'deki gibi ayrı fonksiyonlardır.

Kod bloğu: Tahta çizgileri — line() ile ızgara.

Kod 4.

javascript
function cizTahtaCizgileri() {  background(245, 242, 235);  stroke(40);  strokeWeight(4);  line(HUCRE, 0, HUCRE, height);  line(HUCRE * 2, 0, HUCRE * 2, height);  line(0, HUCRE, width, HUCRE);  line(0, HUCRE * 2, width, HUCRE * 2);  noStroke();}

Dört line() çağrısı dikey iki, yatay iki çizgi çizer; hücre sınırları oluşur. Arka plan rengi background() ile her frame'de yenilenir.

Taşlar, tahtadaki dolu hücreler üzerinden iç içe döngüyle çizilir:

Kod 5.

javascript
function taslariCiz() {  for (let satir = 0; satir < 3; satir = satir + 1) {    for (let sutun = 0; sutun < 3; sutun = sutun + 1) {      let deger = tahta[satir][sutun];      if (deger !== "") {        tasCiz(sutun * HUCRE, satir * HUCRE, HUCRE, deger);      }    }  }}

Tablo 5.

Fonksiyon Sorumluluk
cizTahtaCizgileri() Arka plan + ızgara çizgileri
taslariCiz() Dolu hücreleri dolaş, tasCiz çağır
tasCiz(x, y, boyut, deger) Tek hücrede X veya O metni
cizOyunEkrani() Tahta + taşlar + sıra metni

Kod bloğu: Tek taş çizimi — text() ile X/O.

Kod 6.

javascript
function tasCiz(x, y, boyut, deger) {  textAlign(CENTER, CENTER);  textSize(boyut * 0.55);  if (deger === "X") {    fill(200, 50, 50);  } else {    fill(50, 80, 200);  }  text(deger, x + boyut / 2, y + boyut / 2);}

Piksel konumu sutun * HUCRE, satir * HUCRE ile hesaplanır: sütun soldan sağa, satır yukarıdan aşağı artar. Metin hücre merkezine textAlign(CENTER, CENTER) ile yerleştirilir. Oyun ekranında sıra bilgisi sol üstte gösterilir:

Kod 7.

javascript
function cizOyunEkrani() {  cizTahtaCizgileri();  taslariCiz();  fill(30);  textSize(14);  textAlign(LEFT, TOP);  noStroke();  text("Sıra: " + sira, 8, 8);}

Dikkat: Çizim her frame'de tahta dizisinin güncel halini yansıtır; hamle mousePressed() içinde diziyi günceller, bir sonraki draw() yeni taşı ekrana yazar. Tahta verisi ile çizim ayrı tutulduğu için aynı tasCiz farklı konumlarda tekrar kullanılabilir.

4.3. Tıklama ile Hamle

Hamle, p5.js olay fonksiyonu mousePressed() ile işlenir (önceki bölümler). Fare koordinatları mouseX, mouseY piksel cinsindendir; hücre indeksine dönüştürmek için floor() kullanılır (önceki bölümler, diziler ana başlığı):

Kod 8.

javascript
let sutun = floor(mouseX / HUCRE);let satir = floor(mouseY / HUCRE);

Örneğin HUCRE = 100 iken mouseX = 150 → sutun = 1 (orta sütun); mouseY = 220 → satir = 2 (alt satır).

Hamle işleme sırası:

Tablo 6.

Adım Kontrol Başarısızsa
1 Menüdeyse tıklama → oyuna geç oyunuSifirla(), DURUM_OYUN
2 oyunDurumu === DURUM_OYUN mu? return
3 satir, sutun 0–2 aralığında mı? return
4 tahta[satir][sutun] === "" mu? return (dolu kare)
5 Hamleyi yaz: tahta[satir][sutun] = sira —
6 Kazanan veya beraberlik var mı? Bitiş durumuna geç
7 Sırayı diğer oyuncuya ver if/else ile X ↔ O

Görsel 2. Fare tıklaması → satır/sütun indeksi (floor bölme)
Görsel 2. Fare tıklaması → satır/sütun indeksi (floor bölme)

Görsel 2, piksel koordinatının floor(mouseX / HUCRE) ile hangi kareye denk geldiğini özetler.

Kod bloğu: mousePressed() — hamle ve durum kontrolü.

Kod 9.

javascript
function mousePressed() {  if (oyunDurumu === DURUM_MENU) {    oyunuSifirla();    oyunDurumu = DURUM_OYUN;    return;  }  if (oyunDurumu !== DURUM_OYUN) {    return;  }   let sutun = floor(mouseX / HUCRE);  let satir = floor(mouseY / HUCRE);  if (satir < 0 || satir > 2 || sutun < 0 || sutun > 2) {    return;  }  if (tahta[satir][sutun] !== "") {    return;  }   tahta[satir][sutun] = sira;   let kazanan = kazananKontrol();  if (kazanan !== "") {    sonuc = kazanan;    oyunDurumu = DURUM_BITIS;    return;  }  if (tahtaDoluMu()) {    sonuc = "beraberlik";    oyunDurumu = DURUM_BITIS;    return;  }   if (sira === "X") {    sira = "O";  } else {    sira = "X";  }}

Sıra değişimi üçlü operatör (ternary) yerine if/else ile yazılmıştır; okunabilirlik ve önceki bölümlerdeki dallanma alışkanlığı korunur. Bitiş ekranındayken tıklama erken return ile yok sayılır — Ana Başlık 2'deki “duruma göre girdi” kuralının uygulamasıdır.

Menüden oyuna geçiş hem SPACE (keyPressed) hem tıklama ile mümkündür; ikisi de oyunuSifirla() çağırır.

4.4. Kazanan ve Beraberlik

Kazanma koşulu: üç hücrede aynı işaret ve hücrelerin boş olmaması. 3×3 tahtada toplam 8 kazanma hattı vardır:

Tablo 7.

# Tür Kontrol edilen hücreler
1 Yatay satır 0 [0][0] — [0][1] — [0][2]
2 Yatay satır 1 [1][0] — [1][1] — [1][2]
3 Yatay satır 2 [2][0] — [2][1] — [2][2]
4 Dikey sütun 0 [0][0] — [1][0] — [2][0]
5 Dikey sütun 1 [0][1] — [1][1] — [2][1]
6 Dikey sütun 2 [0][2] — [1][2] — [2][2]
7 Çapraz \ [0][0] — [1][1] — [2][2]
8 Çapraz / [0][2] — [1][1] — [2][0]

Görsel 3. XOX — 8 kazanma hattı (3 yatay + 3 dikey + 2 çapraz)
Görsel 3. XOX — 8 kazanma hattı (3 yatay + 3 dikey + 2 çapraz)

Görsel 3, sekiz hattın tahta üzerindeki konumunu ve beraberlik koşulunu özetler.

Kod bloğu: kazananKontrol() — satır, sütun ve çapraz tarama.

Kod 10.

javascript
function kazananKontrol() {  for (let i = 0; i < 3; i = i + 1) {    if (tahta[i][0] !== "" && tahta[i][0] === tahta[i][1] && tahta[i][1] === tahta[i][2]) {      return tahta[i][0];    }  }  for (let j = 0; j < 3; j = j + 1) {    if (tahta[0][j] !== "" && tahta[0][j] === tahta[1][j] && tahta[1][j] === tahta[2][j]) {      return tahta[0][j];    }  }  if (tahta[0][0] !== "" && tahta[0][0] === tahta[1][1] && tahta[1][1] === tahta[2][2]) {    return tahta[0][0];  }  if (tahta[0][2] !== "" && tahta[0][2] === tahta[1][1] && tahta[1][1] === tahta[2][0]) {    return tahta[0][2];  }  return "";}

Fonksiyon kazanan işareti ("X" veya "O") veya kazanan yoksa "" döndürür. İlk for üç yatay satırı, ikinci for üç dikey sütunu tarar; çaprazlar ayrı if bloklarındadır.

Beraberlik: Tüm hücreler dolu ve kazananKontrol() boş string döndürürse oyun berabere biter. Yardımcı fonksiyon:

Kod 11.

javascript
function tahtaDoluMu() {  for (let satir = 0; satir < 3; satir = satir + 1) {    for (let sutun = 0; sutun < 3; sutun = sutun + 1) {      if (tahta[satir][sutun] === "") {        return false;      }    }  }  return true;}

Her hamle sonrası sıra önce kazanma, sonra beraberlik kontrol edilir; kazanan bulunursa sıra değiştirilmez (oyun zaten biter). Bitiş ekranı sonuc değişkenine göre mesaj gösterir:

Kod 12.

javascript
function cizBitisEkrani() {  background(35, 30, 40);  fill(255);  textAlign(CENTER, CENTER);  textSize(22);  if (sonuc === "beraberlik") {    text("Beraberlik!", width / 2, height / 2 - 20);  } else {    text("Kazanan: " + sonuc, width / 2, height / 2 - 20);  }  textSize(14);  text("R — menüye dön", width / 2, height / 2 + 30);}

4.5. Tam Kod ve Genişletme

Aşağıdaki sketch menü–oyun–bitiş durum makinesi, iki boyutlu tahta, tıklama ile hamle ve kazanma/beraberlik kontrolünü birleştirir; p5.js Web Editor'e yapıştırarak doğrudan çalıştırabilirsiniz.

XOX geçiş tablosu:

Tablo 8.

Mevcut durum Olay / koşul Yeni durum Ek işlem
DURUM_MENU SPACE veya tıklama DURUM_OYUN oyunuSifirla()
DURUM_OYUN Geçerli tıklama, kazanan var DURUM_BITIS sonuc = kazanan
DURUM_OYUN Geçerli tıklama, tahta dolu DURUM_BITIS sonuc = "beraberlik"
DURUM_OYUN Geçerli tıklama, oyun sürüyor DURUM_OYUN Sıra X ↔ O
DURUM_OYUN Geçersiz tıklama DURUM_OYUN —
DURUM_BITIS R basıldı DURUM_MENU —

Oyun kuralları:

setup içinde yeni bir satır vardır: textFont("sans-serif"). Bu, tuvale yazılacak metnin yazı tipini seçer. "sans-serif" sistemdeki varsayılan sans-serif (tırnaksız) yazı tipini kullanır; menü ve bitiş yazıları daha okunaklı görünür. textSize boyutu, textAlign hizayı ayarlarken textFont aileyi (font) belirler. İlerideki oyunlarda (Mayın Tarlası vb.) aynı satır tekrarlanabilir.

Tanım: textFont(yazitipi) — p5.js’te sonraki text() çağrılarının kullanacağı yazı tipini ayarlar. Argüman genelde bir yazı tipi adı string’idir (ör. "sans-serif", "monospace"); özel fontlar için loadFont ile yüklenen nesne de verilebilir.

Kod 13.

javascript
const DURUM_MENU = "menu";const DURUM_OYUN = "oyun";const DURUM_BITIS = "bitis";const HUCRE = 100; let oyunDurumu;let tahta;let sira;let sonuc; function setup() {  createCanvas(300, 300);  textFont("sans-serif");  oyunDurumu = DURUM_MENU;} function draw() {  if (oyunDurumu === DURUM_MENU) {    cizMenu();  } else if (oyunDurumu === DURUM_OYUN) {    cizOyunEkrani();  } else if (oyunDurumu === DURUM_BITIS) {    cizBitisEkrani();  }} function cizMenu() {  background(28, 32, 48);  fill(255);  textAlign(CENTER, CENTER);  textSize(32);  text("XOX", width / 2, height / 2 - 30);  textSize(14);  text("SPACE veya tıkla — başla", width / 2, height / 2 + 20);} function cizOyunEkrani() {  cizTahtaCizgileri();  taslariCiz();  fill(30);  textSize(14);  textAlign(LEFT, TOP);  noStroke();  text("Sıra: " + sira, 8, 8);} function cizBitisEkrani() {  background(35, 30, 40);  fill(255);  textAlign(CENTER, CENTER);  textSize(22);  if (sonuc === "beraberlik") {    text("Beraberlik!", width / 2, height / 2 - 20);  } else {    text("Kazanan: " + sonuc, width / 2, height / 2 - 20);  }  textSize(14);  text("R — menüye dön", width / 2, height / 2 + 30);} function cizTahtaCizgileri() {  background(245, 242, 235);  stroke(40);  strokeWeight(4);  line(HUCRE, 0, HUCRE, height);  line(HUCRE * 2, 0, HUCRE * 2, height);  line(0, HUCRE, width, HUCRE);  line(0, HUCRE * 2, width, HUCRE * 2);  noStroke();} function taslariCiz() {  for (let satir = 0; satir < 3; satir = satir + 1) {    for (let sutun = 0; sutun < 3; sutun = sutun + 1) {      let deger = tahta[satir][sutun];      if (deger !== "") {        tasCiz(sutun * HUCRE, satir * HUCRE, HUCRE, deger);      }    }  }} function tasCiz(x, y, boyut, deger) {  textAlign(CENTER, CENTER);  textSize(boyut * 0.55);  if (deger === "X") {    fill(200, 50, 50);  } else {    fill(50, 80, 200);  }  text(deger, x + boyut / 2, y + boyut / 2);} function mousePressed() {  if (oyunDurumu === DURUM_MENU) {    oyunuSifirla();    oyunDurumu = DURUM_OYUN;    return;  }  if (oyunDurumu !== DURUM_OYUN) {    return;  }   let sutun = floor(mouseX / HUCRE);  let satir = floor(mouseY / HUCRE);  if (satir < 0 || satir > 2 || sutun < 0 || sutun > 2) {    return;  }  if (tahta[satir][sutun] !== "") {    return;  }   tahta[satir][sutun] = sira;   let kazanan = kazananKontrol();  if (kazanan !== "") {    sonuc = kazanan;    oyunDurumu = DURUM_BITIS;    return;  }  if (tahtaDoluMu()) {    sonuc = "beraberlik";    oyunDurumu = DURUM_BITIS;    return;  }   if (sira === "X") {    sira = "O";  } else {    sira = "X";  }} function kazananKontrol() {  for (let i = 0; i < 3; i = i + 1) {    if (tahta[i][0] !== "" && tahta[i][0] === tahta[i][1] && tahta[i][1] === tahta[i][2]) {      return tahta[i][0];    }  }  for (let j = 0; j < 3; j = j + 1) {    if (tahta[0][j] !== "" && tahta[0][j] === tahta[1][j] && tahta[1][j] === tahta[2][j]) {      return tahta[0][j];    }  }  if (tahta[0][0] !== "" && tahta[0][0] === tahta[1][1] && tahta[1][1] === tahta[2][2]) {    return tahta[0][0];  }  if (tahta[0][2] !== "" && tahta[0][2] === tahta[1][1] && tahta[1][1] === tahta[2][0]) {    return tahta[0][2];  }  return "";} function tahtaDoluMu() {  for (let satir = 0; satir < 3; satir = satir + 1) {    for (let sutun = 0; sutun < 3; sutun = sutun + 1) {      if (tahta[satir][sutun] === "") {        return false;      }    }  }  return true;} function oyunuSifirla() {  tahta = [    ["", "", ""],    ["", "", ""],    ["", "", ""]  ];  sira = "X";  sonuc = "";} function keyPressed() {  if (oyunDurumu === DURUM_MENU && key === " ") {    oyunuSifirla();    oyunDurumu = DURUM_OYUN;  }  if (oyunDurumu === DURUM_BITIS && (key === "r" || key === "R")) {    oyunDurumu = DURUM_MENU;  }}

Bu proje önceki bölümlerin kapanış örneğidir: Bölüm 2 Ana Başlık 4'teki frame döngüsü, Bölüm 3 Ana Başlık 4'teki klavye, Ana Başlık 1'deki koordinat mantığı, Ana Başlık 2'deki durum makinesi ve önceki bölümlerdeki diziler ile modüler fonksiyonlar tek XOX oyununda birleşir.

Genişletme fikirleri (İleri Teknikler kitabı): Bilgisayar rakibi (Minimax), Connect Four benzeri tahta — aynı tahta[satir][sutun] iskeleti üzerine. Aşağıdaki etkinlikte ise bu düzeyde kodlanabilir XOX varyantları vardır.

Aşağıdaki Yapay Zekâ Etkileşimi etkinlikleri önce ızgara / dizi fikrini tanıdık oyunlarla pekiştirir; sonra Ana Başlık 2'deki Hafıza projesine benzer biçimde XOX varyantı kodlamanızı ister. Takılınca YZ’den öğretmen / onarım yardımı alın — tüm oyunu baştan yazdırmayın.


Yapay Zekâ Etkileşimi: Izgara oyunları ve çok boyutlu dizi Tahmini süre: 15–25 dakika.

Amaç: İki (ve gerektiğinde çok) boyutlu dizinin oyun tasarımında nerede ortaya çıktığını bilinen oyunlar üzerinden görmek. Kod yazmanız gerekmez.

Adım 1 — YZ’siz: Yukarıdaki tablodan veya bildiğiniz bir oyundan iki örnek seçin. Her biri için birer cümle: “Bu oyunda ızgaranın bir hücresi ne tutuyor?”

Adım 2 — Örnek istem: "Yeni başlayan bir oyun programcısıyım. Oyun programlamada iki boyutlu dizi (matris / ızgara) neden sık kullanılır? (1) En az 6 bilinen oyunda (XOX dışında da) tahta veya harita nasıl ızgara gibi düşünülür? Her oyunda hücrede tipik olarak ne tutulur? (2) Aynı oyunu tek boyutlu diziyle modellemek ne zaman zahmetli olur? Somut bir örnek ver. (3) Üç boyutlu (veya daha çok indeksli) dizinin işe yarayabileceği 1–2 oyun veya durum örneği ver (ör. katmanlı dünya, aynı hücrede birden fazla özellik). Abartma; giriş düzeyinde tut. (4) Benim 3×3 XOX tahta[satir][sutun] modelim bu listenin neresine oturur? Kod yazma; Türkçe yaz."

Adım 3 — Kontrol: YZ’nin oyun örneklerinden ikisini kısa aramayla doğrulayın (uydurma oyun veya yanlış tahta boyutu olmasın). Sonra kendi cümlelerinizle yazın: İleride yapmak istediğiniz küçük bir oyunda ızgara kullanır mısınız, kullanırsanız hücrede ne tutarsınız?


Yapay Zekâ Etkileşimi: XOX varyantlarını keşfet Tahmini süre: 15–20 dakika.

Amaç: Klasik XOX’un yanında hangi kural değişince oyunun “aynı iskelet, farklı tat” olduğunu görmek. Bu adımda tam kod yazmanız gerekmez.

Adım 1 — Klasik tur + okuma: 1–2 tur oynayın; sonra varyant listesine göz atın:

Adım 2 — Örnek istem (mekanik, kod yok): "Yeni başlayan bir oyun programcısıyım; elinde klasik 3×3 XOX (p5.js, iki boyutlu dizi, menü–oyun–bitiş) var. Bu iskeletle kodlanabilecek XOX / Tic-Tac-Toe varyantlarını anlat. (1) En az 4 varyant: adı, kuralları (nasıl oynanır, klasik XOX’tan ne farkı var), kim için eğlenceli olduğu. (2) Programcı gözüyle sınıflandır: hangisi yalnızca taş metnini veya sembolünü değiştirmekle biter; hangisi kazanma kontrolünü veya tahta boyutunu değiştirmeyi gerektirir? Kısa tablo yeter. (3) Online ücretsiz (mümkünse kayıtsız) deneyebileceğim 1–2 site adresi. Örnek yönler (bunlarla sınırlı kalma): harf veya sembol değişimi; misère / ters XOX; 4×4 tahtada üçlü ile kazanma; her turda X veya O seçme. Kod yazma; Türkçe yaz; Minimax veya yapay zekâ rakip anlatma."

Adım 3: YZ’nin listesinden bir varyant seçin (bir sonraki etkinlikte kodlayacaksınız). Kâğıda, kitaptaki XOX’a göre kodda nelerin değişeceğini madde madde yazın (en az iki madde). İpucu olarak bakabileceğiniz yerler: sira ve taş metinleri, tasCiz, kazananKontrol, createCanvas ve HUCRE, bitiş mesajı.

Not: YZ bazen uydurma kural veya aşırı karmaşık varyant önerir. Seçiminiz bu ders düzeyinde bitsin: class yok, Minimax yok, ek kütüphane yok.


Yapay Zekâ Etkileşimi: XOX varyantı — sen yaz, YZ öğretmen olsun Tahmini süre: 50–80 dakika (plan + kod + YZ ile onarım).

Amaç: Bu ana başlıktaki çalışan XOX sketch’ini temel alıp bir varyant üretmek. Ana Başlık 2'deki Hafıza projesinde olduğu gibi: planı siz kurun, kodu siz yazın; takıldığınız yerde YZ’den yardım alın. Amaç yeni bir dil öğrenmek değil; aynı oyunDurumu + tahta + mousePressed iskeletinin kural değişince nasıl esnediğini görmek.

Varyant seçenekleri (birini seçin):

Tablo 9.

Seçenek Ne değişir? Zorluk
A) Sembol / harf "X"/"O" yerine "A"/"B", "★"/"●" veya iki kısa kelime; menü ve bitiş metinleri uyumlu Kolay
B) Ters XOX (misère) Üçlü yapan kaybeder; bitiş metni ve sonuc mantığı tersine döner Orta
C) 4×4, üçlü kazanır Tahta 4×4; hâlâ üç aynı işaret yan yana / çapraz kazandırır; HUCRE ve döngü sınırları büyür Orta–zor
D) Serbest işaret Sıra “X’ten O’ya otomatik geç” değildir: oyuncu önce taşı seçer (ör. 1 tuşu → X, 2 tuşu → O), sonra boş hücreye tıklayınca o taş yazılır Orta–zor

İsterseniz A ile başlayıp çalışan bir kopya görün; sonra B/C/D’den birine geçin.

Adım 1 — Plan (YZ’siz): Seçtiğiniz varyant için kısa not:

  1. Hangi sabit / değişken değişir?
  2. kazananKontrol aynı mı kalır, yoksa ne eklenir / çıkarılır?
  3. Bitiş ekranında ne yazılmalı?
  4. Geçersiz hamle kuralları aynı mı?

Adım 2 — Sizin kodunuz: Web Editor’de kitaptaki XOX sketch’inin bir kopyasını açın; dosya adını varyanta göre değiştirin (ör. xox-yildiz). Önce klasik oyunun kopyada çalıştığını doğrulayın; sonra yalnızca varyant için gereken satırları değiştirin. Class / ek kütüphane / Minimax kullanmayın.

Adım 3 — Takılınca YZ (onarım + öğretmen): Sketch’in tamamını (veya bozulan fonksiyonu) yapıştırın. Körü körüne yapıştırmayın.

Örnek istem — hata / eksik (B: ters XOX): "p5.js’te kitaptaki XOX’u ters XOX (misère) yaptım: üç aynı işaret yan yana gelince o oyuncu kaybeder, kazanmaz. Class yok, ek kütüphane yok. Sorun: Üçlü oluşunca oyun bitiyor ama sonuc hâlâ ‘X kazandı’ / ‘O kazandı’ diyor; kaybeden tarafı göstermiyor. Beraberlik (tahta dolu, üçlü yok) bozulmasın. (1) Önce öğretmen gibi anlat: bu hata hangi değişkende veya hangi fonksiyonda olabilir? (sonuc, mousePressed, kazananKontrol…) (2) Yalnızca gerekli satırları düzelt; tüm oyunu baştan yazma. (3) Neyi neden değiştirdiğini madde madde, bu ders düzeyinde açıkla. Kod:"

(Kendi sketch’inizi yapıştırın. Başka bir varyant seçtiyseniz ilk iki cümleyi kendi kuralınıza ve kendi hatanıza göre değiştirin.)

Örnek istem — yalnızca bir parça (C varyantı için): "p5.js’te class ve ek kütüphane kullanmadan tek bir fonksiyon yaz: kazananKontrol(tahta). tahta 4×4’lük iki boyutlu dizi; her hücre boş string, \"X\" veya \"O\". Kural: klasik XOX’taki gibi üç aynı işaret yan yana gelirse (yatay, dikey veya çapraz) o işaret kazansın. Tahta 4×4 olduğu için bir satırda birden fazla üçlü konumu olabilir; hepsini kontrol et. Kazanan yoksa boş string döndür. Kısa Türkçe yorum ekle. Oyunun geri kalanını yazma; Minimax yazma."

Adım 4 — Kontrol listesi:

Sıra Sizde: YZ’siz deneyin.

  1. Tablodaki oyunlardan (veya aklınızdakilerden) üçünü seçin; her biri için yazın: satır×sütun tahmini + hücrede ne tutulur? Hangisinde XOX’taki gibi tahta[satir][sutun] modeli doğrudan işe yarar?
  2. Kitaptaki XOX kopyasında "X"/"O" yerine kendi iki sembolünüzü kullanın (ör. "A"/"B" veya "1"/"2"); menü başlığı ve bitiş yazısını da uyumlu yapın. Bir tam tur oynayın. Bu değişiklik kazananKontrol içinde neden çoğu zaman hiç dokunulmadan çalışır?
  3. İsterseniz ikinci tur: ters XOX (üçlü yapan kaybeder) için mousePressed / bitiş dalında neyi tersine çevireceğinizi 3 maddeyle planlayın; kodlamaya başlayın, takılınca yukarıdaki YZ istemlerine geçin.

Özet

XOX oyunu 3×3 tahtayı iki boyutlu dizi (tahta[satir][sutun]) ile modeller; boş hücre "", dolu hücre "X" veya "O" tutar. Aynı satır–sütun fikri satranç, Mayın Tarlası, Tetris, Connect Four, Pac-Man labirenti gibi ızgara oyunlarının da omurgasıdır; hücrede tutulan veri oyuna göre değişir. Önceki bölümlerdeki tek boyutlu dizi alışkanlığı satır–sütun erişimine genişler: tahta[1][2] orta satırın sağ hücresidir. Tahta çizgileri ve taşlar modüler fonksiyonlarla her frame'de çizilir; hamle mousePressed() ile piksel koordinatından floor(mouseX / HUCRE) ve floor(mouseY / HUCRE) ile kare indeksine dönüştürülerek yapılır. Sınır dışı veya dolu hücreye tıklama erken return ile yok sayılır; geçerli hamlede mevcut sıra işareti yazılır, ardından sıra if/else ile X ve O arasında değişir. İndeks hesabı yanlışsa taş yanlış hücreye düşer. Sekiz kazanma hattı (üç satır, üç sütun, iki çapraz) kazananKontrol() ile taranır; aynı işaretle üç hücre doluysa kazanan döner. Tahta dolu ve kazanan yoksa tahtaDoluMu() ile beraberlik ilan edilir. Menü, oyun ve bitiş Ana Başlık 2'deki oyunDurumu deseniyle yönetilir; SPACE veya tıklama ile başlama, R ile menüye dönüş tamamlanır. Bitiş ekranındayken fare tıklaması hamle üretmez — girdi yalnızca geçerli durumda işlenir. draw() içinde durum dallanması menü metnini, oyun tahtasını ve bitiş sonucunu ayırır; tahta verisi ile çizim fonksiyonları birbirinden bağımsız kaldığı için bilgisayar rakibi veya skor tablosu gibi genişletmeler aynı iskelete eklenebilir. Menüye dönüşte tahta boşaltılır ve sıra yeniden X'e alınır.

Neler Öğrendik?

Soru 1 3×3 XOX tahtasında tahta[1][2] hangi hücreyi ifade eder?

A) Sol üst

B) Orta satır, sağ sütun

C) Alt satır, orta sütun

D) Sağ alt

E) İkinci sütunun tamamı

Soru 2 Dolu bir kareye tıklandığında mousePressed() içinde ne olması beklenir?

A) Taş üzerine yazılır

B) Sıra yine de değişir

C) Erken return ile hamle yok sayılır

D) setup() yeniden çalışır

E) Tuval boyutu değişir

Soru 3 [Kod okuma] kazananKontrol() boş string ("") döndürdüğünde ve tahtaDoluMu() true ise sonuç nedir?

A) Oyun menüye döner

B) Beraberlik — sonuc = "beraberlik"

C) X kazanır

D) Sıra değişmez, oyun sürer

E) Sketch hata verir

Soru 4 Bitiş ekranındayken fare tıklamasının hamle oluşturmaması hangi ilkeye dayanır?

A) draw() her frame çalışmaz

B) Girdi yalnızca geçerli oyun durumunda işlenir

C) mouseX bitiş ekranında tanımsızdır

D) tahta dizisi silinir

E) R tuşu zorunludur

Neler Öğrendik Yanıt Anahtarı

Soru 1: Doğru Cevap: B

Soru 2: Doğru Cevap: C

Soru 3: Doğru Cevap: B

Soru 4: Doğru Cevap: B

Yararlanılan Kaynaklar

Bu içerik aşağıdaki kaynaklardan derlenerek hazırlanmıştır: