
كيفية برمجة لعبة الشطرنج باستخدام Python و Pygame
يُعد تطوير لعبة الشطرنج باستخدام مكتبة Pygame في Python
مشروعًا تعليميًا وترفيهيًا ممتازًا. يتيح لك هذا المشروع فهم أساسيات تطوير الألعاب،
وتصميم واجهات المستخدم الرسومية، وتنفيذ منطق اللعبة المعقد، وحتى دمج ذكاء اصطناعي بسيط.
يقدم هذا المقال دليلًا شاملاً بالخطوات لكل مرحلة، بدءًا من
تصميم واجهة المستخدم وصولًا إلى نشر تطبيقك القابل للتوزيع.
خطوات برمجة لعبة الشطرنج باستخدام Python و Pygame
هل تحلم بإنشاء لعبتك التفاعلية الخاصة؟ يعتبر مشروع برمجة لعبة
الشطرنج باستخدام لغة Python ومكتبة Pygame نقطة انطلاق مثالية لتحقيق هذا الحلم.
ستغوص في أعماق أساسيات تطوير الألعاب، بدءًا من تصميم واجهة مستخدم جذابة
ووصولًا إلى تنفيذ قواعد اللعبة المعقدة، وحتى إضافة لمسة من الذكاء الاصطناعي لتحدي اللاعب.
هذا الدليل المفصل سيرافقك خطوة بخطوة في رحلة بناء لعبة الشطرنج الخاصة بك
لكل مرحلة ليتحول شغفك بالبرمجة إلى لعبة شطرنج كاملة وقابلة للعب.
الخطوات الأساسية لتطوير لعبة الشطرنج:
1. تهيئة بيئة التطوير وتثبيت Pygame:
# التأكد من تثبيت Python
python --version
# تثبيت pip (إذا لم يكن مثبتًا)
# (عادةً ما يأتي مع Python)
# إنشاء بيئة افتراضية (اختياري ولكن موصى به)
python -m venv chess_env
source chess_env/bin/activate # لنظام Linux/macOS
# chess_env\Scripts\activate # لنظام Windows
# تثبيت Pygame
pip install pygame
pip show pygame
--
2. تصميم واجهة المستخدم الرسومية (GUI):
* (ملف chess_gui.py):
import pygame
# تهيئة Pygamepygame.init()
# أبعاد النافذة ولوحة الشطرنجSQUARE_SIZE = 80BOARD_SIZE = 8 * SQUARE_SIZEWIDTH, HEIGHT = BOARD_SIZE, BOARD_SIZESCREEN = pygame.display.set_mode((WIDTH, HEIGHT))pygame.display.set_caption("Pygame Chess")
# ألوان مربعات الشطرنجLIGHT_SQUARE = (240, 217, 181)DARK_SQUARE = (181, 136, 99)
# تحميل صور القطع (يجب أن تكون الصور في نفس مجلد المشروع أو تحديد المسار)pieces_images = { 'wP': pygame.image.load('assets/wp.png'), 'wR': pygame.image.load('assets/wr.png'), 'wN': pygame.image.load('assets/wn.png'), 'wB': pygame.image.load('assets/wb.png'), 'wQ': pygame.image.load('assets/wq.png'), 'wK': pygame.image.load('assets/wk.png'), 'bP': pygame.image.load('assets/bp.png'), 'bR': pygame.image.load('assets/br.png'), 'bN': pygame.image.load('assets/bn.png'), 'bB': pygame.image.load('assets/bb.png'), 'bQ': pygame.image.load('assets/bq.png'), 'bK': pygame.image.load('assets/bk.png')}
# تغيير حجم الصور لتناسب مربعات الشطرنجfor key in pieces_images: pieces_images[key] = pygame.transform.scale(pieces_images[key], (SQUARE_SIZE, SQUARE_SIZE))
def draw_board(): for row in range(8): for col in range(8): color = LIGHT_SQUARE if (row + col) % 2 == 0 else DARK_SQUARE pygame.draw.rect(SCREEN, color, (col * SQUARE_SIZE, row * SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE))
def draw_pieces(board): for row in range(8): for col in range(8): piece = board[row][col] if piece: SCREEN.blit(pieces_images[piece], (col * SQUARE_SIZE, row * SQUARE_SIZE))
def main_loop(): # تمثيل مبدئي للوحة الشطرنج (سيتم استبداله بمنطق اللعبة) board = [ ['bR', 'bN', 'bB', 'bQ', 'bK', 'bB', 'bN', 'bR'], ['bP', 'bP', 'bP', 'bP', 'bP', 'bP', 'bP', 'bP'], ['', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', ''], ['wP', 'wP', 'wP', 'wP', 'wP', 'wP', 'wP', 'wP'], ['wR', 'wN', 'wB', 'wQ', 'wK', 'wB', 'wN', 'wR'] ]
running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False
draw_board() draw_pieces(board) pygame.display.flip()
pygame.quit()
if __name__ == '__main__': main_loop()
--
* شرح الكود:
- pygame.init(): تهيئة جميع وحدات Pygame المستوردة.
- pygame.display.set_mode(): إنشاء نافذة العرض.
- pygame.display.set_caption(): تعيين عنوان النافذة.
- LIGHT_SQUARE, DARK_SQUARE: تعريف ألوان مربعات الشطرنج.
- pieces_images: قاموس لتخزين صور قطع الشطرنج المحملة وتغيير حجمها.
تأكد من وجود مجلد assets في نفس المجلد مع صور القطع بتسميات مثل
wp.png (بيدق أبيض)، br.png (رخ أسود)، إلخ.
- draw_board(): دالة لرسم لوحة الشطرنج عن طريق رسم مستطيلات ملونة بالتناوب.
- draw_pieces(): دالة لرسم قطع الشطرنج على اللوحة بناءً على تمثيل المصفوفة للوحة.
- main_loop(): الحلقة الرئيسية للعبة التي تعالج الأحداث وترسم الإطار الحالي.
- board: تمثيل مبدئي للوحة الشطرنج كمصفوفة ثنائية الأبعاد.
3. تنفيذ منطق الشطرنج:
* (ملف chess_logic.py):
Python
class ChessLogic: def __init__(self): self.board = [ ['bR', 'bN', 'bB', 'bQ', 'bK', 'bB', 'bN', 'bR'], ['bP', 'bP', 'bP', 'bP', 'bP', 'bP', 'bP', 'bP'], ['', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', ''], ['wP', 'wP', 'wP', 'wP', 'wP', 'wP', 'wP', 'wP'], ['wR', 'wN', 'wB', 'wQ', 'wK', 'wB', 'wN', 'wR'] ] self.current_player = 'w' self.selected_piece = None self.possible_moves = []
def get_piece(self, row, col): return self.board[row][col]
def is_valid_move(self, start_pos, end_pos): # سيتم تنفيذ منطق التحقق من صحة الحركة هنا لكل قطعة # يتضمن التحقق من حدود اللوحة، وقواعد حركة القطعة، وعدم وجود قطع صديقة في المربع الهدف start_row, start_col = start_pos end_row, end_col = end_pos piece = self.board[start_row][start_col] if not piece or piece[0] != self.current_player: return False
# منطق حركة البيدق if piece[1] == 'P': direction = -1 if self.current_player == 'w' else 1 start_row_pawn = 6 if self.current_player == 'w' else 1 # حركة للأمام بمربع واحد if end_col == start_col and self.board[end_row][end_col] == '': if end_row == start_row + direction or (start_row == start_row_pawn and end_row == start_row + 2 * direction and self.board[start_row + direction][start_col] == ''): return True # أكل قطريًا elif abs(end_col - start_col) == 1 and end_row == start_row + direction and self.board[end_row][end_col] != '' and self.board[end_row][end_col][0] != self.current_player: return True # ... تنفيذ منطق حركة القطع الأخرى (الرخ، الحصان، الفيل، الملكة، الملك) ... elif piece[1] == 'R': if start_row == end_row: # حركة أفقية step = 1 if end_col > start_col else -1 for c in range(start_col + step, end_col, step): if self.board[start_row][c] != '': return False return self.board[end_row][end_col] == '' or self.board[end_row][end_col][0] != self.current_player elif start_col == end_col: # حركة رأسية step = 1 if end_row > start_row else -1 for r in range(start_row + step, end_row, step): if self.board[r][start_col] != '': return False return self.board[end_row][end_col] == '' or self.board[end_row][end_col][0] != self.current_player elif piece[1] == 'N': possible_knight_moves = [(start_row - 2, start_col - 1), (start_row - 2, start_col + 1), (start_row - 1, start_col - 2), (start_row - 1, start_col + 2), (start_row + 1, start_col - 2), (start_row + 1, start_col + 2), (start_row + 2, start_col - 1), (start_row + 2, start_col + 1)] return (end_row, end_col) in possible_knight_moves and \ (self.board[end_row][end_col] == '' or self.board[end_row][end_col][0] != self.current_player) elif piece[1] == 'B': row_diff = abs(end_row - start_row) col_diff = abs(end_col - start_col) if row_diff != col_diff: return False row_step = 1 if end_row > start_row else -1 col_step = 1 if end_col > start_col else -1 r, c = start_row + row_step, start_col + col_step while r != end_row: if self.board[r][c] != '': return False r += row_step c += col_step
return self.board[end_row][end_col] == '' or self.board[end_row][end_col][0] != self.current_player elif piece[1] == 'Q': # يمكن للملكة التحرك كالرخ أو الفيل rook_move = (start_row == end_row or start_col == end_col) bishop_move = (abs(end_row - start_row) == abs(end_col - start_col)) if rook_move: # ... (نسخ ولصق منطق حركة الرخ مع تعديلات طفيفة) ... if start_row == end_row: step = 1 if end_col > start_col else -1 for c in range(start_col + step, end_col, step): if self.board[start_row][c] != '': return False return self.board[end_row][end_col] == '' or self.board[end_row][end_col][0] != self.current_player elif start_col == end_col: step = 1 if end_row > start_row else -1 for r in range(start_row + step, end_row, step): if self.board[r][start_col] != '': return False return self.board[end_row][end_col] == '' or self.board[end_row][end_col][0] != self.current_player elif bishop_move: # ... (نسخ ولصق منطق حركة الفيل) ... row_diff = abs(end_row - start_row) col_diff = abs(end_col - start_col) if row_diff != col_diff: return False row_step = 1 if end_row > start_row else -1 col_step = 1 if end_col > start_col else -1 r, c = start_row + row_step, start_col + col_step while r != end_row: if self.board[r][c] != '': return False r += row_step c += col_step return self.board[end_row][end_col] == '' or self.board[end_row][end_col][0] != self.current_player elif piece[1] == 'K': possible_king_moves = [(start_row - 1, start_col - 1), (start_row - 1, start_col), (start_row - 1, start_col + 1), (start_row, start_col - 1), (start_row, start_col + 1), (start_row + 1, start_col - 1), (start_row + 1, start_col), (start_row + 1, start_col + 1)] return (end_row, end_col) in possible_king_moves and \ (self.board[end_row][end_col] == '' or self.board[end_row][end_col][0] != self.current_player)
return False
def move_piece(self, start_pos, end_pos): if self.is_valid_move(start_pos, end_pos): start_row, start_col = start_pos end_row, end_col = end_pos self.board[end_row][end_col] = self.board[start_row][start_col] self.board[start_row][start_col] = '' self.current_player = 'b' if self.current_player == 'w' else 'w' return True return False
def get_possible_moves(self, row, col): piece = self.board[row][col] if not piece or piece[0] != self.current_player: return [] possible_moves = [] # ... تنفيذ منطق توليد الحركات الممكنة لكل قطعة ... return possible_moves
# ... تنفيذ وظائف إضافية للتحقق من كش ملك، إزاحة الملك، الترقية، التبييت ...
--
* شرح الكود:
- ChessLogic class: يحتوي على منطق اللعبة وحالة اللوحة واللاعب الحالي.
- __init__(): تهيئة اللوحة واللاعب الحالي.
- get_piece(): إرجاع القطعة الموجودة في مربع معين.
- is_valid_move(): (يجب إكمال هذا الجزء بشكل كامل) يتحقق من صحة الحركة
بناءً على قواعد الشطرنج لكل قطعة. هذا هو الجزء الأكثر تعقيدًا ويتطلب
تنفيذ دقيق لقواعد حركة كل قطعة (البيدق، الرخ، الحصان، الفيل، الملكة، الملك)
بالإضافة إلى التحقق من عدم وجود قطع صديقة في المربع الهدف.
- move_piece(): ينفذ الحركة إذا كانت صالحة ويغير دور اللاعب الحالي.
- get_possible_moves(): (يجب إكمال هذا الجزء) يولد قائمة بالحركات الممكنة لقطعة في مربع معين.
- وظائف إضافية مطلوبة: يجب تنفيذ وظائف للتحقق من حالات كش ملك
(is_king_in_check())، وإزاحة الملك (is_checkmate(), is_stalemate())، والترقية (handle_pawn_promotion())، والتبييت (can_castle(), perform_castling()).
4. ربط واجهة المستخدم بمنطق اللعبة:
* (تعديل chess_gui.py):
Python
import pygamefrom chess_logic import ChessLogic
# ... (بقية تهيئة Pygame والمتغيرات من ملف chess_gui.py) ...
def main_loop(): game = ChessLogic() selected_square = None running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False if event.type == pygame.MOUSEBUTTONDOWN: col = event.pos[0] // SQUARE_SIZE row = event.pos[1] // SQUARE_SIZE clicked_square = (row, col)
if selected_square: if clicked_square in game.get_possible_moves(*selected_square): game.move_piece(selected_square, clicked_square) selected_square = None game.possible_moves = [] else: piece = game.get_piece(*clicked_square) if piece and piece[0] == game.current_player: selected_square = clicked_square game.possible_moves = game.get_possible_moves(*selected_square)
draw_board() # تظليل المربع المحدد والحركات الممكنة if selected_square: pygame.draw.rect(SCREEN, (0, 255, 0, 128), (selected_square[1] * SQUARE_SIZE, selected_square[0] * SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE)) for move in game.possible_moves: pygame.draw.rect(SCREEN, (0, 0, 255, 128), (move[1] * SQUARE_SIZE, move[0] * SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE)) draw_pieces(game.board) pygame.display.flip()
pygame.quit()
if __name__ == '__main__': main_loop()
--
* شرح الكود:
- استيراد ChessLogic من chess_logic.py.
- إنشاء مثيل (game) من ChessLogic.
- selected_square: لتتبع المربع الذي تم النقر عليه لتحديد قطعة.
- عند النقر بالماوس (pygame.MOUSEBUTTONDOWN):
يتم حساب الصف والعمود للمربع الذي تم النقر عليه.
- إذا كان هناك مربع محدد بالفعل (selected_square):
يتم التحقق مما إذا كانت النقرة الحالية تمثل حركة ممكنة للقطعة المحددة.
إذا كانت الحركة صالحة، يتم تنفيذها باستخدام game.move_piece().
يتم إعادة تعيين selected_square و game.possible_moves.
- إذا لم يكن هناك مربع محدد:
يتم الحصول على القطعة الموجودة في المربع الذي تم النقر عليه.
إذا كانت القطعة مملوكة للاعب الحالي، يتم تحديد المربع ويتم الحصول على الحركات الممكنة باستخدام game.get_possible_moves().
يتم رسم تظليل للمربع المحدد والحركات الممكنة على الشاشة.
5. دمج الذكاء الاصطناعي البسيط (اختياري):
* (تعديل chess_logic.py وإضافة AI logic):
Python
import random
class ChessLogic: # ... (بقية كود ChessLogic) ... def get_opponent_move_random(self): possible_opponent_moves = [] for r in range(8): for c in range(8): piece = self.board[r][c] if piece and piece[0] != self.current_player: moves = self.get_possible_moves(r, c) for move in moves: possible_opponent_moves.append(((r, c), move)) if possible_opponent_moves: return random.choice(possible_opponent_moves) return None
def make_ai_move(self): move = self.get_opponent_move_random() if move: start_pos, end_pos = move self.move_piece(start_pos, end_pos)
# تعديل main_loop في chess_gui.py لاستدعاء make_ai_move() بعد حركة اللاعبdef main_loop(): game = ChessLogic() selected_square = None running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False if event.type == pygame.MOUSEBUTTONDOWN: # ... (معالجة نقرات اللاعب) ... if not selected_square and game.current_player == 'w': # مثال: اللاعب الأبيض piece = game.get_piece(*clicked_square) if piece and piece[0] == game.current_player: selected_square = clicked_square game.possible_moves = game.get_possible_moves(*selected_square) elif selected_square: if clicked_square in game.possible_moves: game.move_piece(selected_square, clicked_square) selected_square = None game.possible_moves = [] # جعل الكمبيوتر يتحرك بعد حركة اللاعب if game.current_player == 'b': # مثال: الكمبيوتر الأسود pygame.time.delay(500) # تأخير بسيط game.make_ai_move() else: selected_square = None game.possible_moves = []
draw_board() # ... (بقية رسم الواجهة) ... pygame.display.flip()
pygame.quit()
--
* شرح الكود:
- get_opponent_move_random(): دالة بسيطة للذكاء
الاصطناعي تقوم باختيار حركة عشوائية صالحة للخصم.
- make_ai_move(): تستدعي
get_opponent_move_random() وتقوم بتنفيذ الحركة.
- يتم تعديل main_loop لاستدعاء
game.make_ai_move() بعد أن يقوم اللاعب البشري بحركته.
6. نشر التطبيق باستخدام PyInstaller:
* (استخدام سطر الأوامر):
pip install pyinstaller
pyinstaller --onefile chess_gui.py --add-data "assets:assets"
--
* شرح الكود:
- pip install pyinstaller: تثبيت مكتبة PyInstaller.
- pyinstaller --onefile chess_gui.py --add-data "assets:assets":
- --onefile: لإنشاء ملف تنفيذي واحد.
- chess_gui.py: ملف الدخول الرئيسي لتطبيقك.
- --add-data "assets:assets": لتضمين مجلد assets (الذي يحتوي على صور القطع
) داخل الملف التنفيذي. سيتم استخراج المجلد assets إلى مجلد مؤقت
عند تشغيل التطبيق. يمكنك الوصول إلى مسار المجلد assets باستخدام
pygame.file.get_config_dir().
- بعد التشغيل: سيتم إنشاء مجلد dist يحتوي على الملف التنفيذي
(chess_gui أو chess_gui.exe). يمكنك توزيع هذا الملف لتشغيل لعبتك
على أنظمة أخرى (قد تحتاج إلى اختبار توافقية النظام).
* ملاحظات مهمة:
- إكمال منطق الشطرنج: الجزء الأكثر تحديًا هو تنفيذ وظيفة
is_valid_move() بشكل كامل ودقيق لجميع قطع الشطرنج، بالإضافة إلى التعامل
مع الحالات الخاصة مثل الترقية، والتبييت، وكش ملك، وإزاحة الملك.
- الذكاء الاصطناعي المتقدم: لإنشاء ذكاء اصطناعي أقوى، ستحتاج إلى تطبيق
خوارزميات بحث وتقييم أكثر تعقيدًا (مثل Minimax أو Alpha-Beta Pruning).
- تحسين واجهة المستخدم: يمكنك تحسين واجهة المستخدم بإضافة رسومات متحركة،
ومؤشرات للحركات الممكنة بشكل أفضل، ومعلومات حول حالة اللعبة (مثل دور اللاعب الحالي).
- التعامل مع الأخطاء: قم بتضمين معالجة للأخطاء المحتملة في تفاعل المستخدم ومنطق اللعبة.
* الخلاصة:
يعد تطوير لعبة الشطرنج باستخدام Pygame مشروعًا مثمرًا يغطي
جوانب متعددة من تطوير الألعاب. من خلال تصميم واجهة المستخدم، وتنفيذ
منطق اللعبة، وربط الاثنين معًا، وحتى دمج ذكاء اصطناعي ، يمكنك إنشاء
لعبة شطرنج تفاعلية كاملة. باستخدام PyInstaller، يمكنك تجميع تطبيقك ليصبح
قابلاً للتوزيع بسهولة. يتطلب إكمال منطق الشطرنج بشكل صحيح اهتمامًا دقيقًا بقواعد
اللعبة، ولكن النتيجة النهائية هي تطبيق ممتع وتعليمي. استمر في تطوير وتحسين
لعبتك بإضافة المزيد من الميزات والذكاء الاصطناعي الأكثر تقدمًا.