• בלוג
  • ביטוי רגולרי לזיהוי מנצח במשחק איקס עיגול

ביטוי רגולרי לזיהוי מנצח במשחק איקס עיגול

13/08/2015

פוסט זה כולל טיפ קצר לעבודה יעילה עם Python. אם אתם רוצים ללמוד פייתון יותר לעומק אני ממליץ על קורס Python כאן באתר.
הקורס כולל עשרות שיעורי וידאו והמון תרגול מעשי וילמד אתכם Python בצורה מקצועית מההתחלה ועד הנושאים המתקדמים.

כשצריך ללמוד שפת תכנות או טכנולוגיה חדשה אחד המשחקים שאני אוהב לבנות הוא איקס-עיגול. המשחק פשוט מספיק כדי לראות תוצאה עובדת בזמן קצר, ומורכב מספיק בשביל שיהיה אפשר ללמוד משהו על הטכנולוגיה. הבעייה היחידה של המשחק היא בדיקת המנצח, שלרוב מורכבת מרצף מייגע של לולאות. כל זה לפחות עד שאתם לומדים להשתמש נכון בביטויים רגולאריים...

1. לוח המשחק

בואו ניקח פייתון לדוגמא ונסתכל על הקוד הבא שמייצר לוח משחק, כל משבצת מתחילה בסימן רווח:

data = []

for i in range(3):
    row = []
    for j in range(3):
        row.append(" ")
    data.append(row)

print data

כששחקן משחק במקום מסוים נרשום את הסימן המתאים במשבצת, כך לדוגמא השחקן X ישתלט על המשבצת האמצעית בלוח:

data[1][1] = "X"

 

2. זיהוי נצחון באמצעות ביטוי רגולרי

מסתבר שאם נסתכל על הלוח הזה בתור מחרוזת אפשר בקלות לזהות בו תבניות. הנה הקוד שמדפיס את מצב הלוח הנוכחי כמחרוזת:

print ''.join([data[i][j] for i in range(3) for j in range(3)])

וכך אם שחקן X השתלט על כל השורה הראשונה, שלושת התווים הראשונים יהיו X. אם שחקן O ישתלט על העמודה האמצעית, התו השני, החמישי והשמיני יהיו O. אפשר לקחת את האפשרויות השונות ש X ינצח ולבנות מהן את אוסף הביטויים הרגולריים הבא:

WINNERS_X = [
    r'X..X..X..',
    r'.X..X..X.',
    r'..X..X..X',
    r'XXX......',
    r'...XXX...',
    r'......XXX',
    r'X...X...X',
    r'..X.X.X..',
]

בשביל לתפוס גם את המצב שהשחקן השני מנצח, או שהתו הוא כלל לא X אלא סימן אחר, אפשר להחליף את סימני ה X בקבוצת כל התווים פרט לרווח. המופע השני והשלישי בביטוי יהפכו ל Back Reference כדי לוודא שמדובר באותו הסימן (ולא מתחלף שחקן באמצע). כך זה ייראה:

WINNERS = [
    r'([^.])..\1..\1..',
    r'.([^.])..\1..\1.',
    r'..([^.])..\1..\1',
    r'([^.])\1\1......',
    r'...([^.])\1\1...',
    r'......([^.])\1\1',
    r'([^.])...\1...\1',
    r'..([^.]).\1.\1..',
]

 

3. בדיקת הלוח וחיפוש מנצחים

זיהוי לוח מנצח הפך לבעיית חיפוש ביטוי רגולרי פשוטה. הלולאה הבאה למשל תרוץ על כל הביטויים ותחפש האם יש מנצח בלוח:

import re
for state in WINNERS:
    if re.search(state, board_str):
        print "We have a winner!"

וכך נראה הקוד המלא למי שירצה להריץ על המחשב בבית:

data = []

for i in range(3):
    row = []
    for j in range(3):
        row.append(".")
    data.append(row)

data[0][1] = "O"
data[1][1] = "O"
data[2][1] = "O"

WINNERS = [
    r'([^.])..\1..\1..',
    r'.([^.])..\1..\1.',
    r'..([^.])..\1..\1',
    r'([^.])\1\1......',
    r'...([^.])\1\1...',
    r'......([^.])\1\1',
    r'([^.])...\1...\1',
    r'..([^.]).\1.\1..',
]


board_str = ''.join([data[i][j] for i in range(3) for j in range(3)])

import re
for state in WINNERS:
    if re.search(state, board_str):
        print "We have a winner!"


 

רוצים לנסות את הקוד בלי לעזוב את הדפדפן? מוזמנים להריץ באמצעות הקלדת python tictactoe.py בטרמינל: