תרגיל – איקס מיקס דריקס

February 22, 2019

תרגיל – איקס מיקס דריקס

בתרגיל הזה ננסה לבנות באמצעות מחלקה (וכמה שטיקים שלמדנו בסעיפים מוקדמים יותר), מודל פשוט של לוח המשחק איקס מיקס דריקס (איקס עיגול או באנגלית tic tac toe). על הלוח להיות מיוצג באופן שנוכל לראות אם בלוח יש תא ריק, תא שיש בו X או תא שיש בו O . כמו כן, נוכל להכניס X  או O בתא שנבחר וכן למחוק במידה והתחרטנו. אפשר לנסות לבד (מומלץ) ואפשר להבין את הפתרון שלנו.

נתחיל בכך שנקים את מפעל הלוחות שלנו –

 

class BoardTicTacToe:
    def __init__(self):
        self.board=[f"{i}" for i in range (1,10)]

 

 

קראנו למחלקה שלנו BoardTicTacToe, היות שבהקמת המפעל, אין צורך להכניס פנימה משתנים, אנו לא צריכים את הסוגריים אחרי שמה של המחלקה, פייתון יודעת לעשות את העבודה גם בלי זה. הלוח במציאות הוא דו מימדי (3X3), אבל לצורך המודל, אנו יכולים לייצג את הלוח כרשימה. המצב ההתחלתי של הלוח הוא שכל תשעת התאים שלו ריקים ולכן בחרנו בשורת קוד של list comprehension המכניסה מחרוזת קטנה המכילה מספר (המדמה תא ריק - אחד מתשע בלוח שלנו), כאשר כל מספר מייצג מקום מסוים על גבי הלוח שלנו. באמצעות הפקודה for ו- range אנו מייצרים תשעה איברים ברשימה שכל אחד מהם מכיל מחרוזת עם רווח אחד.

האיבר הראשון ברשימה (צד שמאל למעלה בלוח) מיקומו על פי פייתון – 0 אבל, היות שהמשחק שלנו כולל את האות האנגלית O וזה עלול לבלבל את השחקן שלנו, אנו לא נתחיל את המספור של התאים באפס אלא ב- 1. בהמשך נצטרך להודיע לפייתון שכאשר אנו רושמים את המיקום 1, אנו בעצם מתכוונים למיקום 0 ברשימה. האיבר האחרון ברשימה שלנו המייצג את התא הימני ביותר למטה מיקומו 8 אבל מיוצג באמצעות הספרה 9. עכשיו כדי לראות מה יצא לנו, אנו צריכים ייצוג נורמלי וקריא של הלוח, ולכן נוסיף מתודה מיוחדת __str__ למחלקה, וגם נרצה שהתוכנית תייצג את הרשימה בצורה של שלוש שורות ולא בשורה אחת – כאן גם נלמד ש n\  (בקסלש backslash ולא ה- slash הרגיל) בתוך מחרוזת מייצר לנו שורה חדשה.

לאחר מכן נייצר מופע של הלוח שלנו בשם ticTac  - נא לשים לב שכאן כבר צריך את הסוגריים אחרי שם המחלקה כדי לקרוא לה לייצר את המופע-  ticTac=BoardTicTacToe() - ונדפיס לוח ריק (בלי X או O ) ונראה איך הוא נראה.

 

class BoardTicTacToe:
    def __init__(self):
        self.board=[f"{i}" for i in range (1,10)]
    def __str__(self):
        return f"{self.board[0:3]}\n{self.board[3:6]}\n{self.board[6:9]}\n"


ticTac=BoardTicTacToe()
print(ticTac)

 

וכך נראה הלוח שלנו אחרי הדפסה –

 

['1', '2', '3']

['4', '5', '6']

['7', '8', '9']

 

מה עשינו עד כה ? לקחנו לוח בצורך רשימה הלוח שלנו מוגדר במחלקה כ- self.board וביקשנו להדפיס כל פעם שלושה איברים אחרים מתוך הרשימה ולרדת לשורה חדשה (עשינו זאת גם אחרי הדפסת השורה האחרונה משום שאם מדפיסים כמה לוחות אנו רוצים שיהיה מרווח בין לוח ללוח). באמצעות format שלמדנו קודם לכן, כל תא מכיל מספר מתוך פקודת ה-range שלנו החל מ- 1 ועד 9.

עכשיו הבה נוסיף מתודות ללוח שלנו על מנת שנוכל לכתוב X או O או למחוק אותם.

 

 

class BoardTicTacToe:
    def __init__(self):
        self.board=[f"{i}" for i in range (1,10)]
    def __str__(self):
        return f"{self.board[0:3]}\n{self.board[3:6]}\n{self.board[6:9]}\n"

    def writeX(self,location):
        self.board[location-1]="X"


    def writeO(self,location):
        self.board[location-1]="O"


    def del_location(self,location):
        self.board[location-1] = str(location)

ticTac=BoardTicTacToe()

ticTac.writeX(1)
ticTac.writeO(2)
ticTac.writeX(3)
ticTac.writeO(7)
ticTac.writeX(5)
ticTac.writeO(9)
print(ticTac)

 

למעלה אנו רואים הוספת 3 מתודות, writeX שמוסיפה ללוח X במיקום שאנו בוחרים בין 1-9 (באמצעות המשתנה location). אותו הדבר לגבי writeO המוסיפה את האות האנגלית O במיקום שאנו בוחרים. המתודה השלישית (del_location) תפקידה למחוק את הסימן (X או O) שרשמנו בטעות (אחרי שגילינו שככה נפסיד) ולהחזיר את המספר (המייצג בעצם תא ריק) שהיה שם קודם לכן. את עניין השבת המספר עשינו הפעם בלי format אלא עם הפקודה ()str אשר לעניין זה של ייצוג תא ריק בלוח עושה בדיוק את אותה עבודה – זה שם לנו מחרוזת של מספר.

כזכור כל מיקום בין 1-9  צריך להיות מתורגם למיקום אמיתי ברשימה בין 0-8 ולכן אנו רואים את הקוד - [self.board[location-1, כלומר אם אנו רוצים לכתוב X בתא מספר 1  הרישום יתבצע בתא מס' 0 ברשימה (כפי שפייתון מבין את המיקומים ולא כפי שאנו החלטנו), כלומר בתא השמאלי העליון בלוח.

לאחר שביצענו סדרה של פעולות בלוח ורשמנו x  ו- o בכמה מיקומים – נראה איך הלוח שלנו נראה –

 

התוצאה

 

['X', 'O', 'X']

['4', 'X', '6']

['O', '8', 'O']

 

כמעט כל הלוח מלא מלבד המקומות 4, 6, ו- 8 שעדיין ריקים.

כעת נניח שהתחרטנו על הפעולה האחרונה שהיתה לרשום O במיקום 9 – נבצע מחיקה של מה שרשום במיקום 9 ונראה מה מתקבל – אם לאחר הכנסת O למיקום 9 נרשום -

 

class BoardTicTacToe:

. . .

. . .

ticTac.writeO(9)

 

ticTac.del_location(9)
print(ticTac)

 

למעלה, מימשנו את המתודה del_location וקיבלנו לאחר הדפסת הלוח –

 

התוצאה

 

['X', 'O', 'X']

['4', 'X', '6']

['O', '8', '9']

 

 

לאן ממשיכים מכאן –

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

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

 

 

class BoardTicTacToe:

. . .

. . .

ticTac=BoardTicTacToe()

def takeInputFromX():
    x=int(input("mr.X where would you like your X?\nnumber between 1 and 9"))
    ticTac.writeX(x)
    print(ticTac)


takeInputFromX()

 

 

אנו כותבים פונקציה בשם takeInputFromX() אשר, כשמה, מבקשת מהשחקן את המיקום שבו הוא רוצה לכתוב את x.

בחרנו במשתנה פנימי בשםx  לתוכו עתידה התוכנית להכניס את המספר שהשחקן יבחר (1-9). כדאי לשים לב שלפני שרשמנו input רשמנו את הפקודה ()int וזאת משום שב- input התוכנה לוקחת בחשבון שהמשתמש מקליד מחרוזת, ואם לא נגיד לה שאנו מתכוונים למספר, בהמשך לא נוכל לבצע פעולות כמו חיסור וחיבור המיועדים למספרים ונקבל באג. לאחר מכן אנו מבקשים שהמספר הנבחר יכנס לתוך המתודה writeX במופע המחלקה BoardTicTacToe שנקרא ticTac , אשר כאמור מקבלת פרמטר של המיקום בו אנו רוצים לסמן את ה – x, ולאחר מכן אנו מבקשים להדפיס את מופע הלוח ticTac (בהתאם לאופן שבו בחרנו לייצג אותו).

לאחר כתיבת הפונקציה ()takeInputFromX  אנו צריכים לקרוא לפונקציה כדי שתתחיל לעבוד – וזאת פשוט על ידי כתיבת שם הפונקציה (עם הסוגריים אחרי שם הפונקציה, הסוגריים צריכים להופיע גם בעת כתיבת קוד הפונקציה ולא לבלבל עם מחלקה שאפשר בלי סוגריים בעת כתיבת קוד המחלקה).

נקבל את השאלה של המחשב בשתי שורות משום שכתבנו   n \  אחרי סימן השאלה–

 

התוצאה

 

mr.X where would you like your X?

number between 1 and 9

 

לוחצים עם המקש השמאלי של העכבר במקום שצריך לכתוב את התשובה שלנו.

מקלידים למשל את הספרה 6

לוחצים על Enter

ובום...

['1', '2', '3']

['4', '5', 'X']

['7', '8', '9']

 

 יש לנו x במיקום מספר 6 והלוח כבר מודפס.

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

Please reload

Please reload

רעננו את הדף והקליקו למעבר לנושא הבא: