
كيفية برمجة لعبة الداما الرقمية باستخدام بايثون : دليل شامل
في هذا المقال الشامل، سنستكشف خطوات برمجة لعبة الداما الرقمية
باستخدام لغة البرمجة بايثون ومكتبة Tkinter لإنشاء واجهة المستخدم
الرسومية (GUI). سنغطي كل شيء بدءًا من تصميم وإنشاء الواجهة وحتى حفظ حالة
اللعبة ونشر التطبيق النهائي.
خطوات برمجة لعبة الداما الرقمية باستخدام بايثون
الخطوة 1: تخطيط وتصميم اللعبة
قبل كتابة أي سطر من التعليمات البرمجية، من الضروري تخطيط وتصميم لعبة الداما .
ضع في اعتبارك ما يلي:
*قواعد اللعبة: قواعد الداما القياسية (حركات القطع، الأكل الإلزامي، التتويج).
*واجهة المستخدم: كيف ستبدو لوحة الداما رقميًا؟ ما هي العناصر التفاعلية التي
سيحتاجها المستخدمون (مربعات اللوحة، عرض القطع، عرض النقاط/الرسائل)؟
*بنية البيانات: كيف ستمثل حالة اللعبة (موقع القطع، نوع القطعة، اللاعب الحالي، النقاط)
في التعليمات البرمجية؟
الخطوة 2: إعداد بيئة التطوير بايثون
تأكد من تثبيت بايثون وبيئة تطوير مناسبة على جهازك.
يمكنك استخدام محرر نصوص بسيط أو بيئة تطوير متكاملة (IDE) مثل
PyCharm أو VS Code مع ملحقات بايثون.
الخطوة 3: بناء واجهة المستخدم الرسومية (GUI) باستخدام Tkinter
سنستخدم مكتبة Tkinter المضمنة في بايثون لإنشاء واجهة المستخدم الرسومية للعبة الداما.
الكود (الخطوة الأولى - إنشاء النافذة الرئيسية) :
Python
import tkinter as tk
root = tk.Tk()
root.title("لعبة الداما")
root.mainloop()
--
* شرح الكود :
- import tkinter as tk: يستورد مكتبة Tkinter ويعطيها الاسم المستعار tk.
- root = tk.Tk(): ينشئ النافذة الرئيسية للتطبيق.
- root.title("لعبة الداما"): يضع عنوان النافذة.
- root.mainloop(): يبدأ حلقة حدث Tkinter، مما يجعل الواجهة قابلة للتفاعل.
* الكود (الخطوة الثانية - إنشاء لوحة الداما):
سنقوم بإنشاء مربعات لوحة الداما كأزرار :
import tkinter as tk
BOARD_SIZE = 8SQUARE_SIZE = 60COLORS = ["white", "gray"]
root = tk.Tk()root.title("لعبة الداما")
board = []for row in range(BOARD_SIZE): row_buttons = [] for col in range(BOARD_SIZE): color = COLORS[(row + col) % 2] button = tk.Button(root, width=SQUARE_SIZE // 10, height=SQUARE_SIZE // 20, bg=color, command=lambda r=row, c=col: handle_click(r, c)) button.grid(row=row, column=col) row_buttons.append(button) board.append(row_buttons)
player_turn_label = tk.Label(root, text="دور اللاعب: الأسود")player_turn_label.grid(row=BOARD_SIZE, column=0, columnspan=BOARD_SIZE, pady=10)
black_score_label = tk.Label(root, text="نقاط الأسود: 0")black_score_label.grid(row=BOARD_SIZE + 1, column=0, columnspan=BOARD_SIZE // 2, pady=5)
white_score_label = tk.Label(root, text="نقاط الأبيض: 0")white_score_label.grid(row=BOARD_SIZE + 1, column=BOARD_SIZE // 2, columnspan=BOARD_SIZE // 2, pady=5)
def handle_click(row, col): print(f"تم النقر على المربع: ({row}, {col})") # سيتم تنفيذ منطق اللعبة هنا
root.mainloop()
* شرح الكود :
- BOARD_SIZE, SQUARE_SIZE, COLORS: ثوابت لتحديد حجم اللوحة وحجم المربعات والألوان.
- board: قائمة ثنائية الأبعاد لتخزين كائنات زر المربعات.
- حلقات التكرار for: لإنشاء صفوف وأعمدة الأزرار.
- tk.Button: ينشئ زرًا جديدًا مع لون خلفية وإجراء عند النقر (command).
- button.grid: يضع الزر في تخطيط الشبكة.
- player_turn_label, black_score_label, white_score_label: تسميات لعرض معلومات اللعبة.
- handle_click: دالة سيتم استدعاؤها عند النقر فوق مربع (سيتم تنفيذ منطق اللعبة هنا).
الخطوة 4: تنفيذ منطق اللعبة
الآن، قم بتنفيذ منطق اللعبة الأساسي، بما في ذلك وضع القطع الأولية، وتحديد
الحركات المتاحة، ومعالجة نقرات المستخدم لتحريك القطع وأكلها، وتتويج الملكات، وتسجيل النقاط :
# ... (الكود السابق لواجهة المستخدم) ...
INITIAL_BOARD = [ [None, 'black', None, 'black', None, 'black', None, 'black'], ['black', None, 'black', None, 'black', None, 'black', None], [None, 'black', None, 'black', None, 'black', None, 'black'], [None, None, None, None, None, None, None, None], [None, None, None, None, None, None, None, None], ['white', None, 'white', None, 'white', None, 'white', None], [None, 'white', None, 'white', None, 'white', None, 'white'], ['white', None, 'white', None, 'white', None, 'white', None]]
current_board = [row[:] for row in INITIAL_BOARD]current_player = 'black'black_score = 0white_score = 0selected_piece = Nonepossible_moves = []
def update_board_gui(): for row in range(BOARD_SIZE): for col in range(BOARD_SIZE): piece = current_board[row][col] text = "" fg_color = "black" if piece == 'black': text = "●" elif piece == 'white': text = "○" fg_color = "white" elif piece == 'black_king': text = "♚" elif piece == 'white_king': text = "♛" fg_color = "white" board[row][col]['text'] = text board[row][col]['fg'] = fg_color
def switch_player(): global current_player current_player = 'white' if current_player == 'black' else 'black' player_turn_label['text'] = f"دور اللاعب: {current_player.capitalize()}"
def get_possible_moves(row, col): moves = [] piece = current_board[row][col] player = 'black' if piece in ['black', 'black_king'] else 'white' opponent = 'white' if player == 'black' else 'black' king = '_king' in piece
directions = [(1, 1), (1, -1), (-1, 1), (-1, -1)]
for dr, dc in directions: # حركات عادية new_row, new_col = row + dr, col + dc if 0 <= new_row < BOARD_SIZE and 0 <= new_col < BOARD_SIZE and current_board[new_row][new_col] is None and (king or (player == 'black' and dr > 0) or (player == 'white' and dr < 0)): moves.append((new_row, new_col))
# قفزات jumped_row, jumped_col = row + dr, col + dc landing_row, landing_col = row + 2 * dr, col + 2 * dc if 0 <= jumped_row < BOARD_SIZE and 0 <= jumped_col < BOARD_SIZE and current_board[jumped_row][jumped_col] in [opponent, opponent + '_king'] and \ 0 <= landing_row < BOARD_SIZE and 0 <= landing_col < BOARD_SIZE and current_board[landing_row][landing_col] is None: moves.append((landing_row, landing_col, (jumped_row, jumped_col))) # تخزين المربع الذي تم القفز فوقه
return moves
def highlight_moves(moves): for r, c, *jumped in moves: board[r][c]['bg'] = "yellow"
def clear_highlights(): for row in range(BOARD_SIZE): for col in range(BOARD_SIZE): color = COLORS[(row + col) % 2] board[row][col]['bg'] = color
def move_piece(start_row, start_col, end_row, end_col, jumped=None): piece = current_board[start_row][start_col] current_board[start_row][start_col] = None current_board[end_row][end_col] = piece if jumped: jumped_row, jumped_col = jumped current_board[jumped_row][jumped_col] = None update_score(piece.split('_')[0]) # تحديث النقاط بعد الأكل # فحص ما إذا كانت هناك قفزات أخرى متاحة بنفس القطعة next_jumps = get_possible_jumps(end_row, end_col, piece.split('_')[0]) if next_jumps: global selected_piece, possible_moves selected_piece = (end_row, end_col) possible_moves = next_jumps clear_highlights() highlight_moves(possible_moves) return # لا يتم تبديل اللاعب إذا كان هناك المزيد من القفزات # التتويج if (piece == 'black' and end_row == BOARD_SIZE - 1) or (piece == 'white' and end_row == 0): current_board[end_row][end_col] = piece + '_king' switch_player()
def get_possible_jumps(row, col, player): jumps = [] piece = current_board[row][col] opponent = 'white' if player == 'black' else 'black' king = '_king' in piece directions = [(1, 1), (1, -1), (-1, 1), (-1, -1)] for dr, dc in directions: jumped_row, jumped_col = row + dr, col + dc landing_row, landing_col = row + 2 * dr, col + 2 * dc if 0 <= jumped_row < BOARD_SIZE and 0 <= jumped_col < BOARD_SIZE and current_board[jumped_row][jumped_col] in [opponent, opponent + '_king'] and \ 0 <= landing_row < BOARD_SIZE and 0 <= landing_col < BOARD_SIZE and current_board[landing_row][landing_col] is None and (king or (player == 'black' and dr > 0) or (player == 'white' and dr < 0)): jumps.append((landing_row, landing_col, (jumped_row, jumped_col))) return jumps
def update_score(player): global black_score, white_score if player == 'black': black_score += 1 black_score_label['text'] = f"نقاط الأسود: {black_score}" else: white_score += 1 white_score_label['text'] = f"نقاط الأبيض: {white_score}"
def handle_click(row, col): global selected_piece, possible_moves clicked_square = (row, col)
if selected_piece: start_row, start_col = selected_piece for end_row, end_col, *jumped in possible_moves: if (end_row, end_col) == clicked_square: move_piece(start_row, start_col, end_row, end_col, jumped[0] if jumped else None) clear_highlights() selected_piece = None possible_moves = [] update_board_gui() return
clear_highlights() selected_piece = clicked_square piece = current_board[row][col] if piece and piece.startswith(current_player): possible_moves = get_possible_moves(row, col) highlight_moves(possible_moves) else: selected_piece = None possible_moves = []
update_board_gui()root.mainloop()
* شرح الكود :
- INITIAL_BOARD, current_board: لتمثيل الحالة الأولية والحالية للوحة.
- current_player, black_score, white_score, selected_piece, possible_moves:
متغيرات لتتبع حالة اللعبة.
- update_board_gui: يحدث تمثيل الواجهة للوحة بناءً على current_board.
- switch_player: يبدل اللاعب الحالي ويحدث التسمية.
- get_possible_moves: يحسب الحركات المتاحة لقطعة في موقع معين.
- highlight_moves, clear_highlights: لتظليل وإزالة تظليل المربعات المتاحة.
- move_piece: ينفذ حركة القطعة ويتحقق من التتويج والقفزات المتعددة.
- get_possible_jumps: يحسب القفزات المتاحة بشكل خاص (للقفزات المتعددة).
- update_score: يحدث نقاط اللاعبين في الواجهة.
- handle_click: يعالج نقرات المستخدم لتحديد القطع وتحريكها.
الخطوة 5: حفظ حالة اللعبة (اختياري)
لحفظ حالة اللعبة واستئنافها لاحقًا، يمكنك استخدام مكتبات بايثون مثل pickle أو json.
الكود (حفظ وتحميل الحالة باستخدام pickle):
أضف أزرار "حفظ" و "تحميل" إلى واجهة المستخدم:
# ... (الكود السابق لواجهة المستخدم) ...import pickle
def save_game(): game_state = { 'current_board': current_board, 'current_player': current_player, 'black_score': black_score, 'white_score': white_score } with open("checkers_save.pkl", "wb") as f: pickle.dump(game_state, f) tk.messagebox.showinfo("حفظ", "تم حفظ اللعبة!")
def load_game(): global current_board, current_player, black_score, white_score try: with open("checkers_save.pkl", "rb") as f: game_state = pickle.load(f) current_board = game_state['current_board'] current_player = game_state['current_player'] black_score = game_state['black_score'] white_score = game_state['white_score'] update_board_gui() player_turn_label['text'] = f"دور اللاعب: {current_player.capitalize()}" black_score_label['text'] = f"نقاط الأسود: {black_score}" white_score_label['text'] = f"نقاط الأبيض: {white_score}" tkinter.messagebox.showinfo("تحميل", "تم تحميل اللعبة!") except FileNotFoundError: tkinter.messagebox.showerror("تحميل", "لا يوجد ملف حفظ موجود!")
save_button = tk.Button(root, text="حفظ اللعبة", command=save_game)save_button.grid(row=BOARD_SIZE + 2, column=0, columnspan=BOARD_SIZE // 2, pady=5)
load_button = tk.Button(root, text="تحميل اللعبة", command=load_game)load_button.grid(row=BOARD_SIZE + 2, column=BOARD_SIZE // 2, columnspan=BOARD_SIZE // 2, pady=5)
update_board_gui()root.mainloop()
* شرح الكود :
- import pickle: يستورد مكتبة pickle لتسلسل الكائنات وحفظها في ملف.
- import tkinter.messagebox: يستورد وحدة messagebox
لعرض رسائل معلومات أو خطأ.
- save_game: ينشئ قاموسًا (dict) يحتوي على حالة اللعبة الحالية ويحفظه في
ملف checkers_save.pkl باستخدام pickle.dump().
- load_game: يحاول فتح ملف checkers_save.pkl وتحميل حالة اللعبة باستخدام
pickle.load(). إذا لم يتم العثور على الملف، يتم عرض رسالة خطأ.
يتم تحديث متغيرات حالة اللعبة وواجهة المستخدم بناءً على البيانات المحملة.
- تم إنشاء زري "حفظ اللعبة" و "تحميل اللعبة" وإضافتهما إلى الواجهة باستخدام tk.Button() و grid().
الخطوة 6: نشر التطبيق (اختياري)
لنشر تطبيق بايثون Tkinter، يمكنك استخدام أدوات مثل PyInstaller.
الخطوات الأساسية للنشر باستخدام PyInstaller:
- تثبيت PyInstaller: افتح سطر الأوامر أو الطرفية وقم بتشغيل:
pip install pyinstaller
- إنشاء ملف قابل للتنفيذ: انتقل إلى دليل مشروعك وقم بتشغيل:
pyinstaller --onefile your_game_file.py
- استبدل your_game_file.py باسم ملف بايثون الرئيسي الخاص بك.
- سيقوم PyInstaller بإنشاء مجلد dist يحتوي على ملف تنفيذي
(.exe على Windows، وتطبيق على macOS، وملف تنفيذي على Linux) يمكنك توزيعه.
* ملاحظات النشر :
قد تحتاج إلى ضبط خيارات PyInstaller الإضافية لتضمين أي
ملفات وسائط أو مكتبات خارجية أخرى يستخدمها تطبيقك.
قد تختلف عملية النشر قليلاً اعتمادًا على نظام التشغيل الخاص بك.
* الخلاصة
لقد سرنا خلال الخطوات الأساسية لبرمجة لعبة الداما الرقمية باستخدام بايثون ومكتبة Tkinter.
بدءًا من تخطيط اللعبة وبناء واجهة المستخدم، وصولًا إلى تنفيذ منطق
اللعبة وحفظ حالتها ونشرها كتطبيق مستقل. باستخدام بايثون و Tkinter،
يمكنك إنشاء ألعاب لوحية رقمية تفاعلية وممتعة. تذكر أن هذا مثال أساسي للعبة الداما،
ويمكنك توسيعه ليشمل ميزات أكثر تعقيدًا، وتحسينات في واجهة المستخدم،
وإضافة خصوم من الذكاء الاصطناعي إذا لزم الأمر.
آمل أن يكون هذا المقال كاملاً ومفيدًا لك في رحلتك لتطوير ألعاب بايثون! .