יסודות בינה מלאכותית ויישומיה (096210)

‫יסודות בינה מלאכותית ויישומיה (‪)096210‬‬
‫תרגיל בית ‪ -2‬פתרון בעיות ‪MDP‬‬
‫תאריך הגשה‪ :‬ראו באתר הקורס‬
‫תרגיל בית ‪ 2‬אינו תלוי בתרגיל מספר ‪.1‬‬
‫מטרה‪:‬‬
‫מטרת התרגיל היא להתנסות בבניית פותר בעיית תכנון סטוכסטי ספציפית‪ ,‬תוך שימוש הן‬
‫ביסודות של השיטות הסטנדרטיות לפתרון ‪ MDP‬והן ברעיונות יצירתיים שלכם‪.‬‬
‫העיקרון של כל לוח משחק הוא זהה‪ Bomberman ,‬צריך "להרוג" את כל המפלצות שעל‬
‫גבי הלוח מבלי להיאכל על ידי אחת מהן‪.‬‬
‫לוח המשחק מורכב מ – ‪ NxM‬משבצות ומכיל‪:‬‬
‫‪ 4 ‬סוגים של אובייקטים‪ :‬קירות‪ ,‬שחקן‪ ,‬פצצה ומפלצות‪.‬‬
‫‪ 2 ‬סוגים של קירות‪:‬‬
‫‪ o‬קירות שניתנים לפיצוץ‪.‬‬
‫‪ o‬קירות שאינם ניתנים לפיצוץ‪.‬‬
‫על גבי הלוח‪ ,‬נמצא שחקן אחד ‪ ,Bomberman -‬ומספר כלשהו של מפלצות (שימו לב‪,‬‬
‫בניגוד לת"ב ‪ 1‬יכולות להיות יותר מארבע מפלצות)‪.‬‬
‫המערכת אותה תממשו תתקשר בצורה איטרטיבית עם הקוד אותו אנחנו מספקים‪ .‬הקוד‬
‫שלנו מסמלץ את הסביבה של ‪ ,Bomberman‬כלומר לוח המשחק‪ .‬לאחר יצירת אובייקט‬
‫מהמחלקה שתבנו‪ ,‬הקוד שלכם יקבל את המצב הנוכחי של הלוח ויחזיר את הפעולה שעל‬
‫ה‪ Bomberman -‬לבצע‪.‬‬
‫המשחק רץ מספר מוגדר של צעדים ומחולק לתת‪-‬משחקים כאשר כל תת‪-‬משחק מתחיל‬
‫במצב ההתחלתי של הלוח‪ ,‬ויכול להסתיים בשני אופנים‪:‬‬
‫הצלחה – ‪ Bomberman‬פוצץ את כל המפלצות‪.‬‬
‫כשלון – אחת המפלצות "אוכלת" את ‪( Bomberman‬יכול להגרם על ידי כניסה של‬
‫‪ Bomberman‬למשבצת בה יש מפלצת‪ ,‬או כניסה של מפלצת אל המשבצת של‬
‫‪ ,)Bomberman‬או ‪ Bomberman‬פוצץ את עצמו (גם אם המפלצות הנותרות פוצצו עמו)‪.‬‬
‫אם תת‪-‬משחק מסתיים‪ ,‬הלוח חוזר למצב ההתחלתי והכל חוזר חלילה עד ש‪-‬‬
‫‪ Bomberman‬יסיים את צעדיו‪.‬‬
‫המדיניות שעליכם לספק לאו דווקא חייבת להיות סטציונרית‪ ,‬כלומר אתם לא חייבים להחזיר‬
‫כל פעם את אותה הפעולה כאשר המערכת מגיעה למצב נתון כלשהו‪.‬‬
‫תיאור כללי של הבעיה‪:‬‬
‫הסוכן בבעיה שלנו הוא שחקן ‪ .Bomberman‬מטרתו היא "לפוצץ" את כל המפלצות על לוח‬
‫המשחק‪ .‬בכל עת‪ ,‬מצבו של המשחק מיוצג ע"י מטריצה )‪ (game‬בגודל ‪ NxM‬שמייצגת את‬
‫לוח המשחק‪ ,‬הכניסות במטריצה מסמנות את המצב של האובייקטים בו‪.‬‬
‫ייצוג הלוח ופעולות‬
‫הקלט שמתאר את הבעיה מועבר למחלקה ‪ Controller‬כאשר‪:‬‬
‫‪ - game‬מטריצה ‪ MxN‬שמייצגת את לוח המשחק‪ .‬כל כניסה במטריצה מקבלת את אחד‬
‫מהערכים הבאים‪:‬‬
‫‪ – 99 ‬קיר שלא ניתן לפוצץ (‪ – firewall‬חומת אש)‪.‬‬
‫‪ – 90 ‬קיר שניתן לפוצץ‪.‬‬
‫‪ Bomberman – 18 ‬במשבצת ריקה‪.‬‬
‫‪ Bomberman – 88 ‬במשבצת עם פצצה‪.‬‬
‫‪ – 80 ‬משבצת עם פצצה‪.‬‬
‫‪ – 12 ‬מפלצת במשבצת‪.‬‬
‫‪ – 10 ‬משבצת ריקה‪.‬‬
‫שימו לב‪ :‬לא תקבלו מצב בו ‪" Bomberman‬מת"‪ .‬במקום זה יתחיל תת‪-‬משחק חדש‪.‬‬
‫לדוגמא המטריצה‪:‬‬
‫)‪(12, 99, 18‬‬
‫)‪(10, 99, 10‬‬
‫)‪(10, 90, 10‬‬
‫מתארת משחק ‪ .Bomberman 3X3‬שיש בו ‪ 2‬חומות אש‪ ,‬קיר רגיל‪ 4 ,‬משבצות ריקות‪,‬‬
‫מפלצת אחת‪ ,‬ואת ‪.bomberman‬‬
‫חוקים לתזוזה‬
‫בכל צעד יש לבחור פעולה של ‪ .Bomberman‬בביצוע ‪ -‬ראשית ‪ Bomberman‬פועל (ראה‬
‫רשימת הפעולות בהמשך)‪ ,‬ולאחר מכן כל אחת מן המפלצות זזה משבצת אחת (המפלצות‬
‫מוזזות ע"י המערכת)‪.‬‬
‫בכל פעולה‪ ,‬אם ‪ Bomberman‬נכנס למשבצת בה יש מפלצת זה נחשב לכישלון במשחק‪.‬‬
‫אחרי כל תזוזה של מפלצת‪ ,‬אם היא נכנסה למשבצת בה נמצא ‪ Bomberman‬זה נחשב‬
‫לכישלון במשחק‪ .‬יתר על כן‪ ,‬המצב יחשב ככשלון אם ‪ Bomberman‬בעצמו נפגע מהפיצוץ‪.‬‬
‫כל פעולה מיוצגת על ידי מחרוזת‪ .‬המחרוזת מייצגת את המהלך של ‪.Bomberman‬‬
‫‪ ‬הזזה של ‪ Bomberman‬למעלה – מיוצג על ידי “‪”U‬‬
‫‪ ‬הזזה של ‪ Bomberman‬למטה – מיוצג על ידי “‪”D‬‬
‫‪ ‬הזזה של ‪ Bomberman‬ימינה – מיוצג על ידי “‪”R‬‬
‫‪ ‬הזזה של ‪ Bomberman‬שמאלה – מיוצג על ידי “‪”L‬‬
‫‪ ‬חוסר תזוזה של ‪ – Bomberman‬מיוצג על ידי “‪”W‬‬
‫‪ ‬הטמנת פצצה ע"י ‪ – Bomberman‬מיוצג על ידי “‪”S‬‬
‫‪ ‬פיצוץ פצצה ע"י ‪ – Bomberman‬מיוצג על ידי “‪”B‬‬
‫אלו הן הפעולות היחידות המותרות ל – ‪.Bomberman‬‬
‫חוקים‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬
‫‪.4‬‬
‫‪.5‬‬
‫לפצצות‪:‬‬
‫בכל זמן נתון על הלוח יכולה להימצא לכל היותר פצצה אחת‪.‬‬
‫‪ Bomberman‬מטמין את הפצצה במשבצת שהוא נמצא בה‪.‬‬
‫גם ‪ Bomberman‬וגם המפלצות לא יכולים להיכנס למשבצת בה יש פצצה‪.‬‬
‫פצצה מפוצצת את המשבצת בה היא נמצאת ובנוסף את כל המשבצות הסמוכות‬
‫אליה (למעלה‪ ,‬למטה‪ ,‬ימינה ושמאלה)‪ .‬סך הכל‪ ,‬פיצוץ משפיע על חמש משבצות‬
‫לכל היותר‪.‬‬
‫פיצוץ משמיד את כל הנמצא במשבצות פרט לחומות אש (המסומנות במספר ‪.)99‬‬
‫שימו לב שאם הפעולה של ‪ Bomberman‬היא פיצוץ פצצה‪ ,‬המפלצות זזות לאחר שהפצצה‬
‫התפוצצה (והשמידה את כל מה שברדיוס הפיצוץ) – כלומר קירות שפוצצו כבר לא קיימים‪,‬‬
‫ומפלצות שהתפוצצו כבר לא זזות (כי הן כבר מתו)‪.‬‬
‫במסגרת התרגיל אתם יכולים לנסות להזיז את ‪ Bomberman‬לתוך‪ ,‬לפוצץ פצצה לא קיימת‬
‫או לנסות לשים פצצה שנייה‪ ,‬זה לא יזיז את ‪ Bomberman‬אך יגרע נקודה אחת מסכום כל‬
‫הנקודות‪ .‬לדוגמה‪ :‬בהינתן ו‪ Bomberman -‬מפוצץ מפלצת ו‪"-‬מת"‪ ,‬ה"פרס" עבור מהלך זה‬
‫הוא ‪( 5 – 10 = -5‬ראו פירוט ניקוד בהמשך)‪.‬‬
‫חוקים לתזוזת המפלצות‪:‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬
‫‪.4‬‬
‫בכל מהלך כל מפלצת זזה משבצת אחת‪ ,‬באחד מארבעת הכיוונים‪ :‬למעלה‪ ,‬למטה‪,‬‬
‫שמאלה‪ ,‬או ימינה‪.‬‬
‫סדר תזוזת המפלצות נקבע באקראי ואין עדיפות לאחת המפלצות‪.‬‬
‫כמובן יש לזכור כי מפלצות אינן יכולות להימצא אחת על השנייה או לזוז אל משבצת‬
‫שיש בה קיר או פצצה‪.‬‬
‫בכל מהלך כל מפלצת זזה משבצת אחת אל המשבצת שהכי מקרבת אותה אל‬
‫‪ ,Bomberman‬כאשר הקרבה אל ‪ Bomberman‬נמדדת במרחק מנהטן (בשיטה זו‬
‫מדידת המרחק נעשית רק במקביל לצירים‪ ,‬המרחק בין ‪ 2‬נקודות הוא הסכום של‬
‫ההפרש בציר ה – ‪ X‬וההפרש בציר ה –‪ .)Y‬אם יש יותר ממשבצת אחת עם מרחק‬
‫מנהטן מינימלי אל ‪ ,Bomberman‬המפלצת בוחרת אחת מהן בהתפלגות אחידה‬
‫(יוניפורמית)‪ .‬לדוגמה‪ :‬אם יש שלוש משבצות באותו מרחק מנהטן‪ ,‬המפלצת תבחר‬
‫כל אחת מהן בהסתברות ‪.1/3‬‬
‫‪ .5‬אם אין למפלצת משבצות פנויות לזוז אליהם היא נשארת במקום‪.‬‬
‫ניקוד‬
‫הניקוד המצטבר במשחק יחולק באופן הבא‪:‬‬
‫‪ ‬הטמנת פצצה – מפחית נקודה אחת‪.‬‬
‫‪ ‬פיצוץ מפלצות – חמש נקודות לכל מפלצת שהוסרה מהלוח‪.‬‬
‫‪ ‬סיום המשחק בהצלחה – חמישים נקודות‪.‬‬
‫‪ ‬ניסיון לפעולה לא חוקית – מפחית נקודה אחת‪.‬‬
‫‪ ‬כישלון במשחק – מפחית עשר נקודות‪.‬‬
‫ארכיטקטורה כללית של המערכת‪:‬‬
‫בכל מהלך ה‪ controller-‬שבניתם בוחר פעולה לביצוע של ‪ ,Bomberman‬מעביר אותה‬
‫לקוד הסביבה (שאנו מספקים)‪ .‬לאחר שהסביבה מעדכנת את לוח המשחק בהתאם למהלך‬
‫שקיבלה (והסתברויות שכתובות לעיל) היא מחזירה את המצב המעודכן של הלוח ל‪-‬‬
‫‪ .controller‬לתשומת לבכם‪ ,‬אם ‪ Bomberman‬מת או כל המפלצות "פוצצו" המערכת‬
‫תחזיר את המצב ההתחלתי של הלוח‪( .‬כזכור‪ ,‬מצב מיוצג ע"י מטריצה (טופל של טופלים)‬
‫עם הקידוד שניתן למעלה‪ ,‬ופעולה תיוצג ע"י מחרוזת בעלת תו אחד מבין התווים‪:‬‬
‫'‪.'U', 'D', 'R', 'L', 'W', 'S', 'B‬‬
‫מימוש‬
‫עליכם לממש מחלקה בשם ‪ Controller‬בתוך קובץ בשם ‪ .ex2.py‬מחלקה זו צריכה להכיל‬
‫את שתי הפונקציות הבאות (לפחות)‪:‬‬
‫‪‬‬
‫)‪__init__(self, board, steps‬‬
‫פונקצית אתחול ה‪ .controller-‬מקבלת כפרמטר ‪, board‬מטריצה מייצגת את המצב‬
‫ההתחלתי של המשחק כרשום למעלה‪ .‬ו‪ steps-‬מספר הצעדים שהמערכת תרוץ על‬
‫המשחק‪ .‬פונקציה זו צריכה לחשב מדיניות (‪ )policy‬לבחירת התזוזה של ‪Bomeberman‬‬
‫בהתחשב במצב הנוכחי של הלוח‪ .‬שימו לב‪ :‬פונקציה זו תורץ עם הגבלת זמן של ‪ 60‬שניות‪,‬‬
‫והיא חייבת לסיים עד אז‪.‬‬
‫קבלת השעה הנוכחית בפייתון (מיוצגת כמספר שניות מאז ‪ )1.1.1970‬מתבצעת ע"י קריאה‬
‫ל )(‪ .time.time‬מומלץ בחום לקרוא לפונקציה זו בתחילת הקריאה ל__‪ ,__init‬ובמקומות‬
‫אסטרטגיים בזמן הריצה‪ ,‬לקרוא לה שוב‪ ,‬ולבדוק כמה זמן עבר‪ .‬אנחנו נריץ את הקוד שלכם‬
‫על בעיות שבהן ‪ value iteration‬לא מסיים את הריצה בתוך ‪ 60‬שניות‪ ,‬ולכן תצטרכו לממש‬
‫פתרון מתוחכם יותר‪.‬‬
‫‪‬‬
‫)‪choose_next_move(self, board, steps, reward‬‬
‫פונקציה זו משמשת לעדכון המצב הנוכחי ובחירת פעולה‪ .‬תכנית הבדיקה תקרא לפונקציה‬
‫זו‪ ,‬כאשר ‪ board‬הוא המצב הנוכחי של המשחק‪ steps ,‬הוא מספר הצעדים שנשארו ל‬
‫‪ ,Bomberman‬ו ‪ reward‬הוא סכום הפרסים שנצבר עד כה‪ .‬פונקציה זו צריכה להחזיר את‬
‫הפעולה לביצוע במצב הנתון‪ .‬הפעולה מיוצגת ע"י מחרוזת בעלת תו אחד ( ‪'U', 'D', 'R', 'L',‬‬
‫'‪ .)'W', 'S', 'B‬שימו לב‪ :‬פונקציה זו תורץ עם הגבלת זמן של ‪ 1‬שנייה‪ ,‬והיא חייבת לסיים עד‬
‫אז‪.‬‬
‫בנוסף‪ ,‬הקובץ ‪ ex2.py‬צריך להכיל משתנה בשם ‪ ,ids‬שמכיל רשימה עם מספרי הזהות‬
‫שלכם‪.‬‬
‫קבצים נוספים‬
‫הקובץ ‪ bomberman.py‬מכיל את המחלקה ‪.Game‬‬
‫מחלקה ‪ Game‬מייצגת משחק בלוח הנתון‪ ,‬ומכילה את בשדות הבאים‪:‬‬
‫‪‬‬
‫‪ – steps‬מספר הצעדים‪.‬‬
‫‪‬‬
‫‪ – init‬המצב ההתחלתי של הלוח‪.‬‬
‫‪‬‬
‫‪ – board‬המצב הנוכחי של הלוח‪.‬‬
‫‪‬‬
‫‪ – locations‬מיקום הנוכחי של המפלצות‪ Bomberman ,‬ופצצה‪.‬‬
‫‪‬‬
‫‪ – done‬האם תת‪-‬המשחק הנוכחי הסתיים‪.‬‬
‫‪‬‬
‫‪ – actions‬הפעולות האפשריות‪.‬‬
‫המתודה‪:‬‬
‫‪‬‬
‫)‪__init__(self, steps, board‬‬
‫מאתחלת את המחלקה‪.‬‬
‫‪‬‬
‫)‪set_locations(self‬‬
‫מאתחלת את המילון ‪.locations‬‬
‫‪‬‬
‫)‪reset(self‬‬
‫מאתחל את ההמשחק‪.‬‬
‫‪‬‬
‫)‪there_is_cell(self, move‬‬
‫מחזירה ‪ True‬אם ורק אם המהלך אינו חורג מהלוח‪.‬‬
‫‪‬‬
‫)‪move_bomberman (self, act‬‬
‫מזיזה את ‪( Bomberman‬אם אפשר) ומחזירה את התגמול על כך‪.‬‬
‫‪‬‬
‫)‪set_bomb (self‬‬
‫מטמין פצצה במשבצת בה נמצא ‪) Bomberman‬אם אין פצצה אחרת על הלוח)‪.‬‬
‫‪‬‬
‫)‪blowup (self‬‬
‫מפוצץ פצצה בהינתן והיא נטמנה‪.‬‬
‫‪‬‬
‫)‪choose_monster_move (self, monster_location‬‬
‫בוחרת באופן אקראי את אחת המשבצות שהכי מקרבות את המפלצת אל ‪,Bomberman‬‬
‫‪ Bomberman‬נמדדת במרחק מנהטן‪.‬‬
‫‪‬‬
‫)‪move_monster (self, monster_location‬‬
‫מזיזה את המפלצת על משבצות שנבחרה ע"י ‪.choose_monster_move‬‬
‫‪‬‬
‫)‪move_all_monster s(self‬‬
‫מזיזה את כל המפלצות בסדר שרירותי‪.‬‬
‫‪‬‬
‫)‪update_board(self, move‬‬
‫מבצעת את המהלך הנתון‪ .‬מזיזה את ‪ ,Bomberman‬ומפלצות בסדר הזה ומחזירה את‬
‫התגמול‪.‬‬
‫‪‬‬
‫)‪play_game(self, policy, visualize = True‬‬
‫מריצה את המשחק מספר צעדים נתון‪.‬‬
‫‪‬‬
‫)‪evaluate_policy(self, policy, times, visualize = True‬‬
‫מבצעת הערכה של ה‪ Controller-‬שבניתם ע"י הרצה של ‪ 30 play_game‬פעם‪ ,‬ומחזירה‬
‫את הממוצע החשבוני‪.‬‬
‫בנוסף למחלקה ‪ ,Game‬אנו מספקים לכם קוד למימוש ‪ MDP‬ושיטות פתרון שונות שלו‪,‬‬
‫בקובץ ‪ .mdp.py‬שימו לב שכנראה תצטרכו לשנות חלקים מקובץ זה‪ .‬אם שיניתם פונקציה‬
‫מסוימת‪ ,‬עליכם להעתיק אותה לקובץ ‪ – ex2.py‬אתם מגישים רק קובץ זה‪.‬‬
‫הסבר על הקובץ ‪:mdp.py‬‬
‫המחלקה ‪ MDP‬היא מחלקת בסיס עבור ‪ .MDP‬והיא מכילה את הפונקציות הבאות‪:‬‬
‫‪‬‬
‫)‪__init__(self, init, actlist, terminals, gamma‬‬
‫מאתחל ‪ MDP‬עם מצב התחלתי ‪ ,init‬רשימת פעולות ‪ ,actlist‬קבוצת מצבים סופיים‬
‫‪( terminals‬אובייקט מסוג ‪ ,set‬שמכיל מצבים)‪ ,‬ופרמטר ‪ gamma‬עבור ‪discount factor‬‬
‫(גורם מהוון)‪.‬‬
‫‪‬‬
‫)‪R(self, state‬‬
‫מחזיר את ה‪ reward-‬המידי במצב ‪state‬‬
‫‪‬‬
‫)‪T(self, state, action‬‬
‫מחזיר רשימה של המצבים שאליהם ניתן לעבור לאחר הפעלת הפעולה ‪ action‬במצב‬
‫‪ .state‬הרשימה צריכה להכיל זוגות מהצורה )’‪ (pr, s‬כאשר ’‪ s‬הוא מצב שניתן לעבור אליו‬
‫בהסתברות ‪.pr‬‬
‫‪‬‬
‫)‪actions(self, state‬‬
‫מחזיר את רשימת הפעולות שניתן להפעיל במצב ‪.state‬‬
‫שימו לב‪ :‬על מנת להשתמש במחלקת ‪ ,MDP‬עליכם לרשת ממחלקה זו‪ ,‬ולדרוס (לפחות)‬
‫את הפונקציה ‪ .T‬בנוסף‪ ,‬בפונקצית ה __‪ __init‬עליכם למלא את קבוצת המצבים של ה‪-‬‬
‫‪ ,MDP‬הנמצאת ב ‪ self.states .self.states‬הוא אובייקט מסוג ‪ set‬של מצבים‪ .‬מצב יכול‬
‫להיות כל אובייקט שהוא ‪( hashable‬כמו בתרגיל בית ‪.)1‬‬
‫תיעוד על ‪ set‬ניתן למצוא ב‪ .http://docs.python.org/library/stdtypes.html#set-‬דוגמא‬
‫למימוש של ‪ MDP‬ניתן למצוא באותו קובץ‪ ,‬במחלקה ‪ ,GridMDP‬שמתארת ‪ MDP‬של ניווט‬
‫ב‪ grid-‬ע"י פעולות תנועה למעלה‪/‬למטה‪/‬ימינה‪/‬שמאלה‪.‬‬
‫בנוסף‪ ,‬יש בקובץ ‪ mdp.py‬מימוש של ‪ value_iteration‬ושל ‪ ,policy_iteration‬יחד עם‬
‫פונקציות עזר‪ .‬מותר להיעזר בקוד שמסופק שם על מנת לבנות את ה‪ policy-‬שלכם‪.‬‬
‫בדיקה‬
‫אנחנו נשתמש בקוד שלכם‪ ,‬ונבנה ‪ policy‬למספר לוחות משחק שונים‪ .‬על כל תכניות נריץ‬
‫את ה‪ policy-‬שבניתם ‪ 30‬פעמים‪ ,‬ונחשב את הרווח הממוצע שלכם‪ .‬זה מתבצע בקובץ‬
‫‪ .check.py‬על מנת שתוכלו לראות את כל המצבים שה‪ policy-‬שלו מוביל אליהם‪ ,‬אתם‬
‫יכולים להחליף את הערך של ‪ visualize‬ל‪ True-‬בקריאה ל‪bomberman. -‬‬
‫)…(‪.run_evaluate_policy‬‬
‫התחרות בתרגיל זה תהיה ע"פ הניקוד הממוצע הגדול ביותר‪ ,‬כאשר הניקוד של כל לוח‬
‫משחק מנורמל ל‪( 1-‬כלומר‪ ,‬מי שקיבל את הרווח הגבוה ביותר בכל מסלול יקבל ניקוד של ‪1‬‬
‫עבור המשחק הזה‪ ,‬מי שקיבל רווח נמוך פי ‪ 2‬יקבל ניקוד של ‪ 0.5‬עבור המשחק‪ ,‬וכן הלאה)‪.‬‬
‫דרישות מהעבודה המוגשת והוראות הגשה‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬
‫‪.4‬‬
‫‪.5‬‬
‫‪.6‬‬
‫הגשה בזוגות או בודדים בלבד! אין הגשה עם יותר משני אנשים – אין טעם לשאול‪.‬‬
‫ההגשה היא אלקטרונית בלבד ותתבצע דרך אתר ה‪ moodle-‬של הקורס בלבד‪.‬‬
‫יש להגיש אך ורק את קובץ ‪ ex2.py‬שלכם‪ .‬אין להגיש את קבצי העזר המצורפים‪,‬‬
‫הבדיקה תדרוס קבצים עם שמות זהים‪ .‬אין להגיש קובץ ‪zip/rar/7z/ace/whatever‬‬
‫– הגישו את הקובץ ‪ ex2.py‬לא מכווץ‪.‬‬
‫אל תשכחו לכתוב את מספרי ת"ז שלכם במשתנה ‪( ids‬כמפורט למעלה)‪ ,‬אחרת לא‬
‫נוכל לדעת מי הגיש את התרגיל‪.‬‬
‫אם יש מגיש בודד – ‪ ids‬צריך להיות רשימה באורך אחד (]”‪,)ids = [“000000000‬‬
‫לא רשימה באורך ‪ 2‬עם מחרוזת ריקה‪.‬‬
‫מספיק שאחד מבני הזוג יגיש – אין צורך ששני בני הזוג יגישו‪.‬‬
‫עצור‬
‫האם קראת את הוראות ההגשה?‬
‫האם פעלת על פי הוראות ההגשה?‬