Program
Mini-Max algoritması, 1920’lere uzanan zengin bir yapay zekâ geçmişine sahiptir. O dönemde bilgisayar algoritmaları için “yapay zekâ” terimi kullanılmasa da, bu temel algoritma, makinelerin çekişmeli senaryolarda nasıl en iyi kararları verebileceğine dair en erken içgörüleri sağlamıştır. Algoritma ilk olarak John von Neumann tarafından 1928 tarihli “Zur Theorie der Gesellschaftsspiele” (Strateji Oyunları Kuramı Üzerine) makalesinde resmileştirilmiş ve modern oyun kuramı ile karar verme algoritmalarının temelini atmıştır.
1997’de IBM’in Deep Blue’su, Mini-max’in gelişmiş varyantlarını kullanarak dünya satranç şampiyonu Garry Kasparov’u yendi. O zamandan beri algoritma, Monte Carlo Ağaç Araması (MCTS) ve pekiştirmeli öğrenme gibi daha sofistike yaklaşımların belkemiği olmuştur.
Bu yazıda, satranç için ünlü Deep Blue’yu yeniden inşa etmeyeceğiz; bunun yerine Python’da çok daha basit bir sürüm olan XOX için bir versiyon geliştireceğiz. Bu süreçte, algoritmanın nasıl çalıştığına ve onu daha karmaşık gerçek dünya oyunlarına nasıl uygulayacağınıza dair güçlü bir sezgi kazanacaksınız.
Minimax Algoritması Nedir?
Minimax genellikle iki oyunculu oyunlar (satranç, XOX veya dama gibi) için bir karar verme algoritmasıdır. Bilgisayarların, rakibinizin her zaman mümkün olan en iyi hamleyi yapacağını varsayarak birkaç hamleyi önden planlamasını sağlar. Bu bölümde, algoritmaya XOX örneği üzerinden genel bir bakış atacağız.
Minimax algoritmasına genel bakış
Gerçek bir XOX oyununda, sıra size geldiğinde en iyi hamleyi yapmaya çalışır ve rakibinizin de en iyi oyunu oynayacağını varsayarsınız. Minimax algoritması tam olarak bunu yapar — bilgisayarın tüm olası hamleleri önden düşünerek yapabileceği en iyi hamleyi bulmasına yardımcı olur.
Minimax adı, çalışma biçiminden gelir:
- “Mini”, rakibin sizin puanınızı en aza indirmeye çalışmasını temsil eder
- “Max”, sizin puanınızı en üst düzeye çıkarmaya çalışmanızı temsil eder
Sıra sizdeyken, size kazanma şansı en yüksek hamleleri yapmak istersiniz (maksimizasyon). Sıra rakibinizdeyken, size en kötü sonucu getirecek hamleleri yapacağını varsayarsınız (minimizasyon).
Yapay zekâda Minimax’in önemi
Minimax, yapay zekâda çeşitli nedenlerle son derece önemlidir:
- Bilgisayarların iki oyunculu oyunlarda akıllı kararlar almasına yardımcı olur
- Birçok modern oyun oynayan yapay zekâ sisteminin temelidir
- Bilgisayarlara önden düşünmeyi ve hamle planlamayı öğretir
En güzel yanı? Aynı fikir, gerçek dünyadaki birçok uygulamada da kullanılır:
- Video oyunlarındaki yapay zekâ rakipleri
- Satranç ve dama gibi strateji oyunları
- Hatta bazı iş karar destek araçları
Minimax kulağa karmaşık gelse de, aslında bir bilgisayara karar vermeden önce hem kendi hamlelerini hem de rakibinin hamlelerini dikkate alan dikkatli bir oyuncu gibi düşünmeyi öğretmektir.
Minimax Algoritmasını Anlamak
Minimax’in nasıl çalıştığını basit bir XOX örneğiyle adım adım inceleyelim. Siz X, bilgisayar ise O olarak oynuyor olun.
Bilgisayar nasıl düşünür
Sıra bilgisayara geldiğinde şu adımları izler:
- Yapabileceği tüm olası hamlelere bakar
- Her hamle için, sizin bir sonraki hamlede ne yapabileceğinizi hayal eder
- Bir sonuca ulaşana kadar (biri kazanır ya da beraberlik olur) önden düşünmeye devam eder
- Kendisine kazanma şansı en yüksek hamleyi seçer
Oyunu puanlamak
Bilgisayar basit bir puanlama sistemi kullanabilir:
- Bilgisayar kazanırsa +10 puan
- Siz kazanırsanız -10 puan
- Beraberlik olursa 0 puan
Bunu bir olasılıklar ağacı gibi düşünün:
- En üstte mevcut oyun tahtası vardır
- Her dal bir olası hamleyi temsil eder
- En altta tüm olası sonuçlar yer alır
Sıra değişimi
Bilgisayar iki düşünme modu arasında geçiş yapar:
1. Maksimizasyon modu (bilgisayarın sırası):
- En yüksek puanı getiren hamleleri arar
- Kazanmayı ya da beraberliği zorlamayı dener
2. Minimizasyon modu (oyuncunun sırası):
- Sizin en düşük puanı getiren hamleleri yapacağınızı varsayar
- Sizin yapabileceğiniz en iyi hamlelere hazırlanır
Basit bir örnek
Diyelim ki oyunda sıra bilgisayarda (X):

Bilgisayar şunları yapacaktır:
- Seçebileceği 3 boş alan olduğunu görür
- Her boş alan için tüm olası gelecek hamleleri hayal eder
- En iyi sonuca götüren hamleyi seçer
- Bu durumda, sizin kazanmanızı engellemek için alt-orta köşeyi seçmelidir
Bu önden düşünme biçimi, bilgisayarın her seferinde kusursuz bir XOX oyunu oynamasına yardımcı olur!
Minimax Algoritması Sözde Kod
Minimax algoritmasını adım adım nasıl yazacağımızı inceleyelim. Sözde koda yeniyseniz endişelenmeyin — onu, gerçek koda dönüştürmeden önce adımları sade bir dille yazmak gibi düşünebilirsiniz!
Adım adım açıklama
Minimax fonksiyonunun çalışması için üç temel şeye ihtiyacı vardır:
- Mevcut oyun tahtası
- Derinlik (önden kaç hamleyi incelediğimiz)
- Sıranın maksimize eden oyuncuda mı (bilgisayar) yoksa minimize eden oyuncuda mı (insan) olduğu
Temel sözde kod şu şekildedir:
function minimax(board, depth, isMaximizingPlayer):
# First, check if the game is over
if game is won:
return +10 if computer wins, -10 if human wins
if game is tied:
return 0
# If it's the computer's turn (maximizing)
if isMaximizingPlayer:
bestScore = -infinity
for each empty spot on board:
make the move
score = minimax(board, depth + 1, false)
undo the move
bestScore = max(score, bestScore)
return bestScore
# If it's the human's turn (minimizing)
else:
bestScore = +infinity
for each empty spot on board:
make the move
score = minimax(board, depth + 1, true)
undo the move
bestScore = min(score, bestScore)
return bestScore
Çoğu sözde kod örneği İngilizce okunur ve gayet anlaşılırdır; ancak yukarıdaki örnek, özyineleme (recursion) kullandığı için biraz farklıdır. Özyineleme, bir fonksiyonun daha büyük bir problemi çözmek için kendisini tekrar tekrar çağırmasıdır. Bir aynanın başka bir aynayı yansıtmasına bakmak gibidir — aynı görüntüyü birçok kez, her seferinde küçülerek görürsünüz.
Minimax algoritmamızda özyineleme gerekir; çünkü oyundaki tüm olası gelecek hamleleri incelemeye çalışıyoruz. Fonksiyon her kendini çağırdığında, bir sonraki olası hamleyi değerlendirir.
Bu, oyunun tüm olası gidişatlarını kontrol ederek en iyi hamleyi bulmamıza yardımcı olur; tıpkı “Ben bunu yaparsam, o şunu yapar, sonra ben bunu yaparım…” diye düşünen çok akıllı bir oyuncu gibi, oyun bitene kadar devam eder. Özyineleme hakkında daha fazla bilgi için ayrı özyineleme eğitimimize bakabilirsiniz.
Örnekleyici açıklama
Basit bir oyun durumunda bunun nasıl çalıştığını görelim:
1. Başlangıç Konumu:

2. Bilgisayar düşünür:
- “X’i herhangi bir boş alana koyarsam…”
- “İnsan bir sonraki hamlede ne yapar?”
- “Peki ben ondan sonra ne yapabilirim?”
- “Hangi hamle bana en iyi nihai puanı getirir?”
3. Her boş alan için bilgisayar:
- Bir hamle yapar
- Oyunun bitip bitmediğini kontrol eder
- Bitmediyse, insanın en iyi hamlesini hayal eder
- Bir sona ulaşana kadar devam eder
- En yüksek puanı getiren hamleyi seçer
Bunu satranç gibi düşünün — hep “Ben buraya gidersem, o şuraya gider, sonra ben buraya…” diye düşünürsünüz; ancak bilgisayar TÜM olası hamleleri aynı anda düşünebilir!
Bu algoritmanın güzel yanı, her iki tarafın da kusursuz oynadığı varsayımı altında her zaman mümkün olan en iyi hamleyi bulmasıdır. Oyunun tüm olası geleceklerini gösteren bir kristal küreye sahip olmak gibi!
XOX için Minimax’i Adım Adım Uygulama
Bu bölümde, saf Python ile Mini-max algoritması tarafından güçlendirilen yenilmez bir XOX yapay zekâsı oluşturacağız. Uygulamayı basit adımlara bölecek, her birinin arkasındaki sezgiyi ve oyunun büyük resmindeki yerini açıklayacağız.
Adım 1: TicTacToe sınıfını tanımlama
Önce, bilgisayarımızla bir XOX oyunu oynamak için ihtiyaç duyduğumuz tüm mantık ve yöntemleri içeren bir sınıf tanımlıyoruz:
class TicTacToe:
def __init__(self):
# Initialize empty board (using ' ' for empty squares)
self.board = [" " for _ in range(9)]
self.human_player = "O"
self.ai_player = "X"
def print_board(self):
"""Print the current state of the board"""
for i in range(0, 9, 3):
print(f"{self.board[i]} | {self.board[i+1]} | {self.board[i+2]}")
if i < 6:
print("---------")
def available_moves(self):
"""Returns list of available moves (indices of empty squares)"""
return [i for i, spot in enumerate(self.board) if spot == " "]
Yukarıda, __init__ metodu, 9 boş alandan (" " boşlukla temsil edilir) oluşan yeni bir oyun tahtası başlatır; 0–8 indeksleri soldan sağa, yukarıdan aşağıya tahta konumlarını temsil eder. Ayrıca iki oyuncu sembolünü belirler — insan oyuncu için "O", yapay zekâ için "X".
print_board metodu, tahtanın mevcut durumunu görselleştirmenin bir yolunu sunar. Her oyuncunun hamlesini ilgili konumlarda göstererek satırlar arasında bölücü çizgilerle 3x3 ızgarayı yazdırır.
available_moves metodu, hâlâ yapılabilecek tüm geçerli hamlelerin bir listesini döndürür. Bunu, tahtadaki hangi konumların hâlâ boş (" ") olduğunu kontrol ederek ve indekslerini döndürerek yapar. Bu, minimax algoritmasının hangi hamleleri değerlendirebileceğini bilmesi açısından kritik olacaktır.
Bu yöntemler, minimax algoritmasını kullanarak yapay zekâ oyuncumuzu oluşturmak için üzerine inşa edeceğimiz temeli oluşturur.
Hızlıca test edelim:
>>> game = TicTacToe()
>>> game.print_board()
| |
---------
| |
---------
| |
>>> game.available_moves()
[0, 1, 2, 3, 4, 5, 6, 7, 8]
Beklendiği gibi, şu anda tahta boş ve tüm hamleler mevcut.
Adım 2: Hamle yapma ve tahta durumlarını kontrol etme yöntemlerini uygulama
Şimdi, bir hamle yapma yöntemi ekleyelim:
class TicTacToe:
...
def make_move(self, position, player):
"""Make a move on the board"""
if self.board[position] == " ":
self.board[position] = player
return True
return False
make_move metodunu ekledik; bu yöntem:
- Girdi olarak bir konum (0–8) ve oyuncu sembolü (“X” veya “O”) alır
- Seçilen konumun boş (“ ”) olup olmadığını kontrol eder
- Boşsa, oyuncunun sembolünü yerleştirir ve True döndürür
- Konum doluysa, hiçbir değişiklik yapmadan False döndürür
Birkaç hamle yapalım ve kalan hamleleri kontrol edelim:
>>> game = TicTacToe()
>>> game.make_move(0, "X")
>>> game.make_move(1, "O")
>>> game.print_board()
X | O |
-----------
| |
-----------
| |
>>> game.available_moves()
[2, 3, 4, 5, 6, 7, 8]
Gayet iyi çalışıyor. Sıradaki adım, tahtanın dolu olup olmadığını kontrol eden bir yöntem eklemek:
class TicTacToe:
...
def is_board_full(self):
"""Check if the board is full"""
return " " not in self.board
is_board_full, tahtada hiç boş alan kalıp kalmadığını kontrol eden bir boole yöntemidir.
Sırada, bir kazanç durumu oluşup oluşmadığını kontrol eden bir yöntem eklemek var:
class TicTacToe:
...
def check_winner(self):
"""Check if there's a winner. Returns winner symbol or None"""
# Check rows
for i in range(0, 9, 3):
if self.board[i] == self.board[i + 1] == self.board[i + 2] != " ":
return self.board[i]
# Check columns
for i in range(3):
if self.board[i] == self.board[i + 3] == self.board[i + 6] != " ":
return self.board[i]
# Check diagonals
if self.board[0] == self.board[4] == self.board[8] != " ":
return self.board[0]
if self.board[2] == self.board[4] == self.board[6] != " ":
return self.board[2]
return None
check_winner metodu, XOX tahtasının mevcut durumunu değerlendirerek bir kazanan olup olmadığını belirler. Tüm olası kazanma kombinasyonlarını kontrol eder:
1. Satırlar (3 olasılık):
- Üst sıra (indeksler 0,1,2)
- Orta sıra (indeksler 3,4,5)
- Alt sıra (indeksler 6,7,8)
2. Sütunlar (3 olasılık):
- Sol sütun (indeksler 0,3,6)
- Orta sütun (indeksler 1,4,7)
- Sağ sütun (indeksler 2,5,8)
3. Çaprazlar (2 olasılık):
- Sol üstten sağ alta (indeksler 0,4,8)
- Sağ üstten sol alta (indeksler 2,4,6)
Her kombinasyon için, üç konumun da aynı oyuncu sembolünü (X veya O) içerip içermediğini ve boş olmadığını kontrol eder. Bir kazanma kombinasyonu bulunursa, kazanan oyuncunun sembolünü döndürür. Tüm olasılıklar kontrol edildikten sonra kazanan yoksa None döner.
Fonksiyonu, kazanç ve kazanç olmayan durumlarda test edelim:
game = TicTacToe()
# Winning state
game.make_move(0, "X")
game.make_move(1, "X")
game.make_move(2, "X")
>>> game.print_board()
X | X | X
-----------
| |
-----------
| |
>>> game.check_winner()
'X'
game = TicTacToe()
# Non-winning state
game.make_move(0, "X")
game.make_move(1, "O")
game.make_move(2, "O")
game.make_move(3, "X")
>>> game.print_board()
X | O | O
-----------
X | |
-----------
| |
>>> game.check_winner() is None
True
Son olarak, oyunun bitip bitmediğini belirtmek için başka bir boole yöntemi ekleyelim:
class TicTacToe:
...
def game_over(self):
"""Check if the game is over"""
return self.check_winner() is not None or self.is_board_full()
Bu yöntem, ya bir kazanan bulunduğunda ya da tahta dolu olduğunda True döndürür.
Bu noktada, tüm temel oyun mekaniğini oluşturduk:
- Tahta, boş olarak başlatılan 9 karelik bir listeyle temsil edilir
print_board()mevcut oyun durumunu görsel olarak gösteriravailable_moves()boş karelerin indekslerini döndürürmake_move()oyuncunun sembolünü tahtaya yerleştirircheck_winner()her hamlede satırları, sütunları ve çaprazları kazanç için inceleris_board_full()hamle kalıp kalmadığını belirlergame_over()kazanan kontrolü ile tahta dolu kontrolünü birleştirir
Bu yöntemler, hamle yapma ve oyun durumunu belirleme gibi tüm temel işlemleri ele alarak oynanabilir bir oyun için gereken temeli sağlar.
Şimdi kritik kısma geliyoruz — bilgisayara Minimax ile “zeka” kazandırmak.
Adım 3: XOX için Minimax’i uygulama
Şimdi, algoritmayı oyuna yeni bir yöntem olarak uygulayalım:
class TicTacToe:
...
def minimax(self, depth, is_maximizing):
"""
Minimax algorithm implementation
Returns the best score possible for the current board state
"""
# Base cases
winner = self.check_winner()
if winner == self.ai_player:
return 1
if winner == self.human_player:
return -1
if self.is_board_full():
return 0
Fonksiyon iki parametre alır:
depth— Özyinelemede kaç seviye derine indiğimizi takip eder. Çok karmaşık oyunlar için arama derinliğini sınırlamakta kullanılabilir; ancak XOX için sınırlamaya gerek yoktur.is_maximizing— Şu anda maksimum puanı (YZ’nin sırası) mı yoksa minimum puanı (insanın sırası) mı aradığımızı belirten boole bayrağıdır. Oyuncular sıra aldıkça her özyinelemeli çağrıda bu değer değişir.
Fonksiyon gövdesinde, temel durumları tanımlayarak başlarız: Oyun YZ tarafından kazanılmışsa (winner == ai_player), YZ için en iyi sonuç olduğundan 1 döndürürüz. İnsan kazanırsa (winner == human_player), YZ için en kötü sonuç olduğundan -1 döndürürüz. Tahta dolu ve kazanan yoksa, beraberlik için 0 döndürürüz.
def minimax(self, depth, is_maximizing):
...
# if it is the maximizing player's turn (AI), we want to maximize the score
if is_maximizing:
best_score = float("-inf")
for move in self.available_moves():
# Make a calculating move
self.board[move] = self.ai_player
# Recursively call minimax with the next depth and the minimizing player
score = self.minimax(depth + 1, False)
# Reset the move
self.board[move] = " "
# Update the best score
best_score = max(score, best_score)
return best_score
is_maximizing True olduğunda YZ’nin sırasını simüle ederiz ve en yüksek puana götüren hamleyi bulmak isteriz. best_score’u eksi sonsuza ayarlarız ki gerçek herhangi bir puan daha iyi olsun. Ardından her mevcut hamle için:
- YZ’nin sembolünü geçici olarak tahtaya koyarız
- Bu hamleyi yaparsak ne olacağını,
is_maximizing=Falseile minimax çağırarak özyinelemeli değerlendiririz (çünkü sıradaki hamle insanındır) - Geçici hamleyi geri alır, tahtayı eski hâline getiririz
- Gördüğümüz en yüksek puanı
max()ile takip ederiz
Bu, YZ’nin yapabileceği her olası hamleyi kontrol etmemizi sağlar. Her hamle için, birinin kazanmasına ya da oyunun berabere bitmesine kadar neler olabileceğine bakarız. Ardından geriye doğru çalışarak ilk hamlelerden hangisinin YZ’ye en iyi kazanma şansını verdiğini buluruz.
Şimdi, insan için minimize etme kısmını yapalım:
def minimax(self, depth, is_maximizing):
...
# if it is the maximizing player's turn (AI), we want to maximize the score
if is_maximizing:
...
else:
# if it is the minimizing player's turn (human), we want to minimize the score
best_score = float("inf")
for move in self.available_moves():
# Make a calculating move
self.board[move] = self.human_player
# Recursively call minimax with the next depth and the maximizing player
score = self.minimax(depth + 1, True)
# Reset the move
self.board[move] = " "
# Update the best score
best_score = min(score, best_score)
return best_score
is_maximizing False olduğunda, insan oyuncunun sırasını simüle ederiz ve en düşük puana götüren hamleyi bulmak isteriz (çünkü yüksek puan YZ’nin kazanması demektir). best_score’u artı sonsuzla başlatırız ki gerçek herhangi bir puan daha düşük olsun. Her mevcut hamle için:
- İnsanın sembolünü geçici olarak tahtaya koyarız
- Ne olacağını,
is_maximizing=Trueile minimax çağırarak özyinelemeli değerlendiririz (çünkü sıradaki hamle YZ’nindir) - Geçici hamleyi geri alırız
- Gördüğümüz en düşük puanı
min()ile takip ederiz
Bu, insan oyuncunun YZ’nin kazanmasını önlemek için en iyi hamleleri yapmaya çalışmasını simüle eder. İnsan, puanları en aza indirmek ister; çünkü pozitif puanlar YZ zaferlerini temsil eder. Maksimizasyon ve minimizasyon turları arasında dönüşümlü ilerleyerek algoritma, her iki oyuncu için de en iyi hamle dizisini belirleyebilir.
Adım 4: Minimax ile YZ için en iyi hamleyi bulma
Artık algoritma hazır olduğuna göre, her insan hamlesinden sonra YZ için en iyi hamleyi belirlemek üzere minimax yöntemini kullanan başka bir yönteme ihtiyacımız var:
class TicTacToe:
...
def get_best_move(self):
"""Find the best move for AI using minimax"""
best_score = float("-inf")
best_move = None
for move in self.available_moves():
# Make a calculating move
self.board[move] = self.ai_player
# Recursively call minimax with the next depth and the minimizing player
score = self.minimax(0, False)
# Reset the move
self.board[move] = " "
# Update the best score
if score > best_score:
best_score = score
best_move = move
return best_move
get_best_move yöntemi, minimax algoritmasını kullanarak YZ oyuncusu için en uygun hamleyi belirlemekten sorumludur. Şöyle çalışır:
1. En iyi puan olarak eksi sonsuz ve seçili bir hamle olmadan başlar
2. Tahtadaki her mevcut hamle için:
- YZ’nin sembolünü geçici olarak o konuma yerleştirir
- Minimax’i kullanarak geri kalan oyunu simüle eder ve hamlenin ne kadar iyi olduğunu değerlendirir
- Geçici hamleyi geri alır
- Bu hamle daha önce gördüğümüzden daha iyi bir puana yol açarsa, hem en iyi puanı hem de en iyi hamleyi günceller
3. Son olarak en yüksek puana yol açan hamleyi döndürür
Bu yaklaşım, insan oyuncunun da en iyi şekilde oynadığı varsayımı altında, YZ’nin kendisine en iyi kazanma şansını veren hamleyi seçmesini sağlar. Yöntem, tüm olası gelecek oyun durumlarını dikkate alır ve YZ’nin şansını maksimize ederken insanın kazanma şansını en aza indiren yolu seçer.
Bunu örnek bir oyun durumunda test edelim:
game = TicTacToe()
# Make a couple of moves
game.make_move(0, "X")
game.make_move(1, "O")
# Print the board
>>> game.print_board()
X | O |
---------
| |
---------
| |
>>> game.get_best_move()
3
# AI moves
>>> game.make_move(3, "X")
# I move
>>> game.make_move(4, "O")
>>> game.print_board()
X | O |
---------
X | O |
---------
| |
# Get the best move for AI
>>> game.get_best_move()
6
Gördüğünüz gibi, YZ benim hamlelerime göre kazanan kombinasyonu buldu (örnek durumdu ama algoritmamızın çalıştığını kanıtlıyor).
Adım 5: Bir oyun döngüsü uygulama
Artık minimax algoritmamızı uygulayıp test ettiğimize göre, YZ’ye karşı oynamamıza olanak tanıyan bir oyun döngüsü oluşturalım.
class TicTacToe:
...
def play_game(self):
"""Main game loop"""
print("Welcome to Tic Tac Toe!")
print("You are 'O' and the AI is 'X'")
print("Enter positions (0-8) as shown below:")
print("0 | 1 | 2")
print("---------")
print("3 | 4 | 5")
print("---------")
print("6 | 7 | 8")
print("\n")
play_game metodu, bir karşılama mesajı ve oyuncuya yönelik talimatları göstererek başlar. İnsan oyuncunun ‘O’, YZ’nin ise ‘X’ kullandığını belirtir. Ardından, oyuncuya tahtadaki hangi konumun hangi sayıya karşılık geldiğini göstermek için numaralandırılmış bir ızgara (0–8) yazdırır. Bu, oyuncuların istedikleri hamle için doğru sayıyı girmelerini kolaylaştırır.
# ... the rest of the class
def play_game(self):
...
# Randomly decide who goes first
import random
ai_turn = random.choice([True, False])
while not self.game_over():
self.print_board()
if ai_turn:
print("\nAI's turn...")
move = self.get_best_move()
self.make_move(move, self.ai_player)
else:
while True:
try:
move = int(input("\nYour turn (0-8): "))
if 0 <= move <= 8 and self.make_move(move, self.human_player):
break
else:
print("Invalid move! Try again.")
except ValueError:
print("Please enter a number between 0 and 8!")
ai_turn = not ai_turn
Başlangıç talimatlarını gösterdikten sonra oyun ana döngüsüne girer. Oyun, her oyunun başında adil ve öngörülemez bir başlangıç oluşturmak için random.choice([True, False]) kullanarak ilk kimin oynayacağına (YZ ya da insan) rastgele karar verir.
Ana oyun döngüsü, game_over() True dönene kadar (biri kazanır ya da tahta dolar) devam eder. Her turda, print_board() ile tahtanın mevcut durumu gösterilir.
Eğer sıra YZ’deyse (ai_turn True ise), program:
- YZ’nin düşündüğünü belirten bir mesaj yazdırır
get_best_move()çağrısıyla minimax algoritmasını kullanarak en uygun hamleyi belirler- Seçilen konuma YZ’nin sembolünü (‘X’) yerleştirerek hamleyi yapar
Sıra insandaysa (ai_turn False ise), program:
1. Oyuncudan geçerli bir girdi almak için bir döngüye girer2. 0–8 arasında bir hamle numarası ister3. Girdiyi doğrular:
- Geçerli bir tam sayı mı (try/except ile)
- 0–8 aralığında mı
- Tahtada boş bir konuma mı işaret ediyor
4. Geçerli giriş alınana kadar sormaya devam eder. Seçilen konuma oyuncunun sembolünü (‘O’) yerleştirerek hamleyi yapar
ai_turn, her turdan sonra not kullanılarak tersine çevrilir ve oyuncular arasında sırayla ilerlenir. Bu, biri kazanana ya da oyun berabere bitene kadar oyunun karşılıklı ilerleyişini sağlar.
Girdi doğrulaması, geçersiz kullanıcı girdilerinin oyunu çökertmesini engeller ve oyuncuyu doğru hamleleri girmeye yönlendiren faydalı hata mesajları sağlar. Bu da sağlam ve kullanıcı dostu bir oyun deneyimi yaratır.
def play_game(self):
...
# Game over
self.print_board()
winner = self.check_winner()
if winner == self.ai_player:
print("\nAI wins!")
elif winner == self.human_player:
print("\nCongratulations! You win!")
else:
print("\nIt's a tie!")
Oyun bittiğinde, print_board() ile son tahta durumu gösterilir ve check_winner() ile kazanan belirlenir. Oyun üç şekilde bitebilir:
- YZ kazanır —
check_winner()YZ’nin sembolünü (‘X’) döndürürse, YZ’nin bir kazanç hattı elde ettiği anlamına gelir - İnsan kazanır —
check_winner()insanın sembolünü (‘O’) döndürürse, oyuncunun bir kazanç hattı elde ettiği anlamına gelir - Beraberlik — Hiçbir oyuncu kazanmadıysa ve tahta doluysa, artık hamle yapılamaz
Oyun sonucunu duyurmak için uygun mesaj gösterilir. Böylece oyunun nasıl sonuçlandığı oyuncuya net biçimde bildirilir.
Adım 6: Her şeyi bir araya getirmek
Şimdiye kadar yazdığımız tüm kodu, en sonda aşağıdaki if/main koşuluyla birlikte bir Python betiğine koyma zamanı:
# Start the game
if __name__ == "__main__":
game = TicTacToe()
game.play_game()
Bu, betiği python script.py ile çalıştırdığınız anda oyunun başlamasını sağlar. Tüm açıklamalar ve kod blokları arasında kaybolduysanız, oyunun tam kodunu bu GitHub gist’inde bulabilirsiniz.
İşte oynadığım örnek bir oyun:
❯ python tic-tac-toe.py
Welcome to Tic Tac Toe!
You are 'O' and the AI is 'X'
Enter positions (0-8) as shown below:
0 | 1 | 2
---------
3 | 4 | 5
---------
6 | 7 | 8
| |
---------
| |
---------
| |
Your turn (0-8): 4
| |
---------
| O |
---------
| |
AI's turn...
X | |
---------
| O |
---------
| |
Your turn (0-8): 5
X | |
----------
| O | O
----------
| |
AI's turn...
X | |
---------
X | O | O
---------
| |
Your turn (0-8): 6
X | |
---------
X | O | O
---------
O | |
AI's turn...
X | | X
---------
X | O | O
---------
O | |
Your turn (0-8): 1
X | O | X
---------
X | O | O
---------
O | |
AI's turn...
X | O | X
---------
X | O | O
---------
O | X |
Your turn (0-8): 8
X | O | X
---------
X | O | O
---------
O | X | O
It's a tie!
Unutmayın, XOX basit bir oyun olduğundan YZ’yi yenme şansı yoktur. Oyun ya berabere biter ya da kaybedersiniz!
Mini-max Algoritmasını Biçimselleştirme
Şimdi, basit XOX örneğinin ötesinde algoritmanın genel tanımını gözden geçirelim.
Minimax algoritması, sıfır toplamlı bir oyundaki konumları değerlendiren özyinelemeli bir fonksiyon olarak biçimsel şekilde tanımlanabilir. Biçimsel bileşenlerini ve özelliklerini inceleyelim.
Matematiksel tanım
Bir oyun durumu s için minimax değeri V(s) şu şekilde tanımlanır:
V(s) =
utility(s) if s is terminal
max(V(s')) for all s' in S if player = MAX
min(V(s')) for all s' in S if player = MIN
Burada:
- s’, s’nin ardıl durumlarını temsil eder
- S, s durumundan yapılan tüm yasal hamlelerin kümesidir
- utility(s), terminal durumlar için değerlendirme fonksiyonudur
Temel özellikler
1. Mükemmel bilgi
- Tüm oyuncular oyun durumunu tamamen bilir
- Gizli bilgi veya şans unsuru yoktur
- Sonuçlar deterministiktir
2. Sıfır toplamlı yapı
- Bir oyuncunun kazancı, diğerinin kaybına tam olarak eşittir
- Tüm oyuncuların faydalarının toplamı her zaman sıfırdır
- İki oyunculu oyunlarda faydalar genellikle {-1, 0, 1} şeklindedir
3. Optimal oyun
- Her iki oyuncunun da en iyi kararları verdiği varsayılır
- Kusursuz oyuna karşı en iyi mümkün sonucu garanti eder
- Oyun kuramı açısından Nash dengesine götürür
Karmaşıklık analizi
Zaman karmaşıklığı: O(b^m)
- b = dallanma faktörü (her durumda yasal hamle sayısı)
- m = oyun ağacının en büyük derinliği
Uzay karmaşıklığı: O(bm)
- Her seviyede oyun durumunun saklanması gerekir
- Yinelemeli derinleştirme ile optimize edilebilir
Değerlendirme fonksiyonu
Terminal olmayan durumlar için değerlendirme fonksiyonu f(s) şunları sağlamalıdır:
- Kazanma olasılığıyla ilişkili olmalı
- Hesaplama açısından verimli olmalı
- Oyun boyunca tutarlı bir ölçeklendirme sürdürmeli
Biçimsel tanım:
f(s) = w₁x₁ + w₂x₂ + ... + wₙxₙ
Burada:
- wᵢ farklı özellikler için ağırlıklardır
- xᵢ oyun durumundan elde edilen özellik değerleridir
- n, değerlendirilen özelliklerin sayısıdır
Optimalite garantisi
Minimax algoritması şu koşullar altında optimal oyunu garanti eder:
- Mükemmel bilgi
- Deterministik sonuçlar
- Terminal durumlara kadar eksiksiz arama
- Doğru terminal durum değerlendirmesi
Bu da onu, bu koşulların sağlandığı satranç, XOX ve dama gibi oyunlar için özellikle uygun kılar.
Gelişmiş Varyasyonlar ve Sınırlamalar
Minimax, XOX gibi basit oyunlar için harikadır; ancak daha büyük oyunlarda bazı sorunları vardır. Nasıl hızlandırılabileceğine ve nerelerde zorlandığına bakalım.
Minimax’i hızlandırmak: Alfa-beta budama
Satranç oynarken hamlelerinizi düşünün. Kazandıran bir hamle bulduysanız, diğer tüm olası hamleleri incelemeniz gerekmez, değil mi? Alfa-Beta Budama da aynı şekilde çalışır — bulduğumuzdan daha iyi olmayacağını bildiğimiz hamleleri kontrol etmeyi atlamaya yardımcı olur.
Şöyle düşünün:
- En ucuz çikolatayı arıyorsunuz
- Harcamak için 1$’ınız var
- 50¢’lik bir çikolata bulursanız, 1$’dan pahalı olanların hiçbirine bakmanıza gerek yok
- Bu da size zaman kazandırır!
Derinlik sınırları: Fazla ileriye bakmamak
Satranç gibi büyük oyunlarda tüm olası hamleleri kontrol etmek için çok fazla olasılık vardır. Bu nedenle bir derinlik sınırı ekleriz:
- Oyunun sonuna kadar değil, yalnızca 4–5 hamle öteye bakın
- O noktadaki konumun ne kadar iyi olduğuna dair iyi bir tahmin yapın
- Bu tahminlere göre en iyi hamleyi seçin
Oyunun sonuna kadar tüm hamleleri planlayamazsınız; ama birkaç hamleyi önden planlayabilirsiniz!
Minimax’in zorlandığı yerler
Minimax kusursuz değildir. Başlıca sorunları şunlardır:
1. Fazla seçenek
- Go gibi oyunlarda aşırı sayıda olası hamle vardır
- Hızlı bilgisayarlar bile hepsini kontrol edemez
- Bu yüzden çok karmaşık oyunlar için başka yöntemlere ihtiyaç duyarız
2. Zaman sorunları
- Ne kadar fazla hamleyi önden incelerseniz, o kadar uzun sürer
- Satrançta bilgisayarlar her olası hamleyi inceleyemez
- Hangi hamlelerin kontrol edileceği konusunda akıllı davranmaları gerekir
3. Belirsiz oyunlar için uygun değil
- Minimax, her şeyi görebildiğiniz durumlarda en iyi çalışır
- Diğerlerinin hangi kartlara sahip olduğunu bilmediğiniz kart oyunları için uygun değildir
- Zar atışı gibi rastgele olayları iyi yönetemez
Modern çözümler
Günümüzün oyun yapay zekâları sıklıkla Minimax’i başka yöntemlerle birleştirir:
1. Makine öğrenimi
- Bilgisayarlar çok sayıda oyunu izleyerek öğrenebilir
- Bu da iyi hamleler hakkında daha iyi tahminler yapmalarını sağlar
AlphaGogibi oyunlar, insan şampiyonları yenmek için bunu kullanır
2. Örüntü tanıma
- Her hamleyi kontrol etmek yerine örüntülere bakın
- Tıpkı insanların iyi hamleleri tanıması gibi
- Bu, bilgisayarı çok daha hızlı yapar
3. Bellek bankası
- Daha önce görülen konumları hatırlayın
- Aynı şeyi iki kez hesaplayarak zaman kaybetmeyin
- İyi hamleler için bir “ipuçları kâğıdı”na sahip olmak gibi!
En güzel yanı? Bu iyileştirmeler, bilgisayarların oyunları insanlar kadar iyi, hatta bazen daha iyi oynamasına yardımcı olur! Ama unutmayın — tüm bu gelişmiş eklemelere rağmen, Minimax hâlâ her şeyin temelini oluşturan yöntemdir.
Sonuç
Bu eğitimde, Minimax algoritmasını temel kavramlarından pratik uygulamaya kadar inceledik. Öğrendiklerimiz:
1. Temel kavramlar
- Minimax’in bilgisayarların oyunlarda karar vermesine nasıl yardımcı olduğu
- Minimize eden ve maksimize eden oyuncu arasındaki fark
- Neden “minimax” olarak adlandırıldığı ve nasıl çalıştığı
2. Uygulama becerileri
- Sıfırdan bir XOX oyunu geliştirme
- Python’da Minimax algoritmasını yazma
- Oyun mantığını test etme ve hata ayıklama
3. İleri konular
- Algoritmayı Alfa-Beta Budama ile hızlandırma
- Karmaşık oyunlardaki sınırlamaları ele alma
- Makine öğrenimi ile modern iyileştirmeler
Sırada ne var?
Minimax algoritması, yapay zekâ bulmacasının yalnızca bir parçasıdır. Yapay zekâ ve algoritmalar hakkında daha fazla öğrenmek istiyorsanız, yolculuğunuza devam etmek için harika kaynaklar burada:
1. İlgili Algoritmalar
- A* Algoritması Eğitimi — Yol bulma algoritmalarını öğrenin
- Gradient Boosting Rehberi — Makine öğrenimi algoritmalarını keşfedin
2. Makine Öğrenimi Uygulamaları
- Makine Öğrenimi Kullanım Alanları — Gerçek dünya uygulamalarını görün
3. Tam Öğrenim Yolları
- Yapay Zekâ Uygulamaları Geliştirme — Pratik YZ projeleri geliştirin
- YZ Temelleri — YZ’nin temellerinde ustalaşın
Unutmayın, ister basit bir oyun ister karmaşık bir YZ sistemi geliştiriyor olun, Minimax gibi algoritmaları anlamak yapay zekâda daha ileri konular için güçlü bir temel sağlar. Pratik yapmaya, öğrenmeye ve en önemlisi kod yazmaya devam edin!
Minimax Algoritması SSS
Minimax algoritmasını anlamak ve uygulamak ne kadar zor?
Minimax algoritması, özellikle XOX gibi basit oyunlar için uygulandığında anlaşılması görece kolaydır. Özyineleme kavramı yeni başlayanlar için zorlayıcı olabilir; ancak hamleleri sırayla maksimize etme ve minimize etme fikri sezgiseldir. Bu eğitim, uygulamayı yönetilebilir adımlara ayırarak temel Python bilgisine sahip programcılar için erişilebilir kılar.
Bu algoritmayı XOX dışında başka oyunlarda da kullanabilir miyim?
Evet, Minimax algoritması, Satranç, Dama veya Connect Four gibi mükemmel bilgiye sahip iki oyunculu, sıfır toplamlı birçok oyuna uyarlanabilir. Ancak daha karmaşık oyunlar için, olası hamle sayısı katlanarak arttığından Alfa-Beta budama ve derinlik sınırlama gibi ek optimizasyonları uygulamanız gerekir.
YZ XOX’ta nasıl oluyor da hiç kaybetmiyor?
Minimax algoritması, tüm olası gelecek oyun durumlarını simüle ederek ve en iyi sonuca götüren hamleleri seçerek çalışır. XOX gibi basit bir oyunda, olası hamle sayısı görece azdır; bu da YZ’nin her durumda en iyi hamleyi hesaplamasına olanak tanır. XOX “çözümlenmiş bir oyun” olduğundan, iki taraf da kusursuz oynarsa oyun her zaman berabere biter; bu yüzden YZ asla kaybetmez.
Bu eğitimi takip etmek için önceden hangi bilgileri bilmeliyim?
Temel Python programlama bilgisine sahip olmalısınız, bunlar dahil:
Fonksiyonlar ve sınıflar hakkında anlayış
Listeler ve temel veri yapılarıyla aşinalık
Temel kontrol akışı (if ifadeleri, döngüler)
Özyineleme bilgisi faydalıdır ancak şart değildir; eğitim bu kavramı açıklar.
Bu algoritma YZ geliştirme için neden önemlidir?
Minimax algoritması, oyun kuramını ve yapay zekâda karar vermeyi anlamanın temelidir. Özyinelemeli ağaç araması, karşıt düşünme ve mükemmel bilgi altında optimal karar verme gibi önemli kavramları tanıtır. Bu ilkeler; oyun oynamadan stratejik planlama ve karar destek sistemlerine kadar modern uygulamalarda kullanılan daha gelişmiş YZ algoritmalarının temelini oluşturur.

2 yılı aşkın deneyime sahip bir veri bilimi içerik üreticisiyim ve Medium'da en büyük takipçi kitlelerinden birine sahibim. Yapay zeka ve makine öğrenimi üzerine, biraz da alaycı bir üslupla, ayrıntılı yazılar yazmayı seviyorum; çünkü bu konuları biraz olsun sıkıcılıktan çıkarmak gerekiyor. 130'dan fazla makale ve bir DataCamp kursu hazırladım; bir diğeri de yolda. İçeriklerim 5 milyondan fazla kişi tarafından görüntülendi; bunların 20 bini Medium ve LinkedIn'de takipçim oldu.