コード例 #1
0
ファイル: tasks.py プロジェクト: nalipour/Fuxenpruefung
def show_statistics(qdicts, qdictsAll, categories):
    tot_n_questions = len(qdictsAll)
    # create message
    lines = []
    lines.append(i18n.statisticsHeader[i18n.lang()][0])
    lines.append(i18n.statisticsColHeader[i18n.lang()])
    for default, longName, shortName in categories:
        lines.append(
            (longName + ': ', str(len(qdicts[shortName])), '{:.0f} %'.format(
                100 * len(qdicts[shortName]) / tot_n_questions)))

    lines.append(i18n.statisticsHeader[i18n.lang()][1])
    lines.append(i18n.statisticsColHeader[i18n.lang()])
    count_dict = collections.Counter([x[2] for x in qdictsAll.values()])
    keys = list(count_dict.keys())
    keys.sort()
    for key in keys:
        lines.append(
            (key + ': ', str(count_dict[key]),
             '{:.0f} %'.format(100 * count_dict[key] / tot_n_questions)))

    root = tk.Tk()
    if sys.platform == 'win32':
        root.iconbitmap(files.FOX_ICO_PATH)
    root.title('F*x!')
    gui.InfoWindow(root, lines)
    root.focus_force()
    root.mainloop()
    root.destroy()
コード例 #2
0
ファイル: data.py プロジェクト: nalipour/Fuxenpruefung
def read_data(questNumbers, questionFile, zipFile, zipPasswd):
    zipPasswd_bytes = str.encode(zipPasswd)

    qdicts = {}
    for key in questNumbers.keys():
        qdicts[key] = {}
    qdictsAll = {}

    questCounter = 0
    questLines = []

    if questionFile.endswith('.zip'):
        base = os.path.basename(questionFile)
        with zipFile.open(os.path.splitext(base)[0]+'.txt', pwd=zipPasswd_bytes) as data:
            for byteLine in data:
                line = byteLine.decode('utf8')
                questLines.append(line)
    else:
        with open(questionFile, 'r', encoding='utf8') as data:
            for line in data:
                questLines.append(line)

    for line in questLines:
        line = line.rstrip()
        if line.startswith('#') or not len(line):
            continue
        splitlist = []
        try:
            splitlist = line.split("#", 4)
        except ValueError:
            continue
        splitlist = [x for x in map(lambda a: a.strip(), splitlist)]
        try:
            difficulty, question, answer, category, vspace = splitlist
        except ValueError:
            errorIdx = 2
            root = tk.Tk()
            if sys.platform == 'win32':
                root.iconbitmap(files.FOX_ICO_PATH)
            root.title(i18n.errorTitle[i18n.lang()])
            lines = []
            lines.append(i18n.errorText[i18n.lang()][errorIdx] + ' ' + line)
            gui.InfoWindow(root, lines)
            root.focus_force()
            root.mainloop()
            root.destroy()
            zipPasswd = ''
            questionFile = ''
            continue

        qdicts[difficulty][len(qdicts[difficulty])] = question, answer, category, vspace
        qdictsAll[questCounter] = question, answer, category, difficulty, vspace
        questCounter += 1

    return qdicts, qdictsAll
コード例 #3
0
ファイル: tasks.py プロジェクト: nalipour/Fuxenpruefung
def interactive_quiz(qdicts, questNumbers):
    ran_qdicts = randomize_questions(qdicts, questNumbers, exclude=['J', 'P'])
    questionList = functools.reduce(operator.add, ran_qdicts.values())
    questionList = map(lambda x: x[0], questionList)
    answersCount = [0, 0, 0]

    root = tk.Tk()
    if sys.platform == 'win32':
        root.iconbitmap(files.FOX_ICO_PATH)
    root.title(i18n.quizTitle[i18n.lang()])
    questionList = [
        str(idx + 1) + '. ' + question
        for idx, question in enumerate(questionList)
    ]
    app = gui.QuizWindow(root, questionList)
    root.focus_force()
    root.mainloop()
    root.destroy()
    if app.quit.get():
        return
    success = app.success.get()
    failure = app.failure.get()
    skip = app.skip.get()
    if not (success + failure):
        return

    answersCount = [success, failure, skip]

    lines = []
    lines.append(i18n.quizHeader[i18n.lang()][0])
    lines.append(i18n.statisticsColHeader[i18n.lang()])
    tot_n_questions = functools.reduce(operator.add, answersCount)
    successRate = answersCount[0] / (tot_n_questions - answersCount[2])
    successIndex = int(successRate *
                       (len(i18n.quizInterpretation[i18n.lang()]) - 1))
    quizInterpretation = i18n.quizInterpretation[i18n.lang()][successIndex]
    if successRate == 1:
        quizInterpretation = i18n.quizInterpretation[i18n.lang()][-1]

    keys = i18n.answerCorrect[i18n.lang()]
    for idx, key in enumerate(keys):
        lines.append(
            (key + ': ', str(answersCount[idx]),
             '{:.0f} %'.format(100 * answersCount[idx] / tot_n_questions)))
    interpretationText = i18n.quizHeader[i18n.lang()][1] + ': '
    interpretationText += str(int(100 * successRate)) + ' % '
    interpretationText += i18n.quizCorrect[i18n.lang()] + '. '
    interpretationText += quizInterpretation + '!'
    lines.append(interpretationText)

    root = tk.Tk()
    if sys.platform == 'win32':
        root.iconbitmap(files.FOX_ICO_PATH)
    root.title('F*x!')
    app = gui.InfoWindow(root, lines)
    root.focus_force()
    root.mainloop()
    root.destroy()
コード例 #4
0
 def _set_username():
     userName = simpledialog.askstring(
         i18n.snakeUserNameRequest[i18n.lang()][2],
         i18n.snakeUserNameRequest[i18n.lang()][0] + ':')
     if not userName:
         return
     self.userName = userName
     self.userNameButton['text'] = self.userName + ' ({0})'.format(
         i18n.snakeUserNameRequest[i18n.lang()][1])
     with open(files.SNAKE_CONFIG_FILE, 'w') as outfile:
         yaml.dump({'username': self.userName},
                   outfile,
                   default_flow_style=False)
コード例 #5
0
ファイル: data.py プロジェクト: nalipour/Fuxenpruefung
def open_data(questionFile, zipPasswd):
    fileOpenOptions = dict(initialdir='.', defaultextension='.txt', filetypes=[('', '*.txt;*.zip')])
    if not questionFile:
        questionFile = filedialog.askopenfilename(**fileOpenOptions)

    passwordError = False
    if questionFile != () and questionFile.endswith('.zip'):
        zipFile = zipfile.ZipFile(questionFile)
        for zinfo in zipFile.infolist():
            isEncrypted = zinfo.flag_bits & 0x1
        if isEncrypted and zipPasswd == '':
            zipPasswd = simpledialog.askstring(i18n.passwordText[i18n.lang()][0],
                                               i18n.passwordText[i18n.lang()][1], show='*')
            try:
                zipPasswd_bytes = str.encode(zipPasswd)
            except TypeError:
                zipPasswd_bytes = b'1234'
            print(os.path.splitext(questionFile)[0])
            base = os.path.basename(questionFile)
            try:
                with zipFile.open(os.path.splitext(base)[0]+'.txt', pwd=zipPasswd_bytes):
                    pass
            except RuntimeError:
                print('Bad password!')
                passwordError = True
    else:
        zipFile = ''

    if passwordError:
        errorIdx = 1
        root = tk.Tk()
        if sys.platform == 'win32':
            root.iconbitmap(files.FOX_ICO_PATH)
        root.title(i18n.errorTitle[i18n.lang()])
        lines = []
        lines.append(i18n.errorText[i18n.lang()][errorIdx])
        gui.InfoWindow(root, lines)
        root.focus_force()
        root.mainloop()
        root.destroy()
        zipPasswd = ''
        questionFile = ''
        return

    if not questionFile:
        return

    return zipFile, zipPasswd, questionFile
コード例 #6
0
ファイル: snake.py プロジェクト: Vorathel/Fuxenpruefung
 def _init_start(event):
     reset(self)
     _draw_new_fox(BOX_X_MAX * 0.15, BOX_Y_MIN * 0.4, 'scoreFox', 0.5)
     canv.create_text(BOX_X_MAX * 0.25,
                      BOX_Y_MIN * 0.4,
                      text=':' + str(self._nFoxes),
                      font='b',
                      tags=('foxText'))
     _draw_new_beer(BOX_X_MAX * 0.45, BOX_Y_MIN * 0.4, 'scoreBeer', 0.5)
     canv.create_text(BOX_X_MAX * 0.55,
                      BOX_Y_MIN * 0.4,
                      text=':' + str(self._nBeers) + ' / ' +
                      str(MAX_BEER - 1),
                      font='b',
                      tags=('beerText'))
     _draw_new_star(BOX_X_MAX * 0.75, BOX_Y_MIN * 0.4, 'scoreStar', 0.5)
     canv.create_text(BOX_X_MAX * 0.85,
                      BOX_Y_MIN * 0.4,
                      text=':' + str(self._nBeers),
                      font='b',
                      tags=('starText'))
     canv.create_text(BOX_X_MAX / 2,
                      BOX_Y_MIN * 0.73,
                      fill='red',
                      text=i18n.snakeEventInfo[i18n.lang()][0],
                      tags=('eventInfoText'))
     _start(event)
コード例 #7
0
ファイル: snake.py プロジェクト: Vorathel/Fuxenpruefung
 def _change_direction(event):
     if event.keysym == 'w':
         event.keysym = 'Up'
     if event.keysym == 'a':
         event.keysym = 'Left'
     if event.keysym == 's':
         event.keysym = 'Down'
     if event.keysym == 'd':
         event.keysym = 'Right'
     if not self._direction:
         canv.itemconfig('eventInfoText',
                         text=i18n.snakeEventInfo[i18n.lang()][3])
     if not self._nFoxes:
         self._direction = 'measingless'
     if event.keysym == 'Up' and self._direction != 'Down':
         self._yVel = -MOVEMENT_STEP_SIZE
         self._xVel = 0
         self._direction = event.keysym
     if event.keysym == 'Down' and self._direction != 'Up':
         self._yVel = MOVEMENT_STEP_SIZE
         self._xVel = 0
         self._direction = event.keysym
     if event.keysym == 'Right' and self._direction != 'Left':
         self._yVel = 0
         self._xVel = MOVEMENT_STEP_SIZE
         self._direction = event.keysym
     if event.keysym == 'Left' and self._direction != 'Right':
         self._yVel = 0
         self._xVel = -MOVEMENT_STEP_SIZE
         self._direction = event.keysym
コード例 #8
0
ファイル: snake.py プロジェクト: Vorathel/Fuxenpruefung
def main():
    print('Executing only snake!')
    root = tk.Tk()
    root.iconbitmap(foxIco)
    root.title(i18n.snakeWelcome[i18n.lang()])
    SnakeWindow(root)
    root.focus_force()
    root.mainloop()
    root.destroy()
コード例 #9
0
ファイル: tasks.py プロジェクト: nalipour/Fuxenpruefung
def play_snake():
    root = tk.Tk()
    if sys.platform == 'win32':
        root.iconbitmap(files.FOX_ICO_PATH)
    root.title(i18n.snakeWelcome[i18n.lang()])
    snake.SnakeWindow(root)
    root.focus_force()
    root.mainloop()
    root.destroy()
コード例 #10
0
    def __init__(self, master, lines):

        self.OKvalue = tk.IntVar()
        self.OKvalue.set(0)
        thisOKvalue = self.OKvalue

        center_window(master)
        master.protocol("WM_DELETE_WINDOW", master.quit)

        _row_count = 0
        for line in lines:
            one_msg = tk.Message(master, text=line, width=400)
            one_msg.grid(row=_row_count, column=0, columnspan=2)
            _row_count += 1

        def _quit():
            thisOKvalue.set(0)
            master.quit()

        def _go():
            thisOKvalue.set(1)
            master.quit()

        _OK_button = tk.Button(master,
                               text=i18n.yesNo[i18n.lang()][0],
                               command=_go,
                               width=25)
        _OK_button.grid(row=_row_count, column=0)

        _cancel_button = tk.Button(master,
                                   text=i18n.yesNo[i18n.lang()][1],
                                   command=_quit,
                                   width=25)
        _cancel_button.grid(row=_row_count, column=1)

        def _quit_bind(self):
            _quit()

        def _go_bind(self):
            _go()

        master.bind('<Return>', _go_bind)
        master.bind('<Escape>', _quit_bind)
コード例 #11
0
def main():
    print('Executing snake game!')
    root = tk.Tk()
    if sys.platform == 'win32':
        root.iconbitmap(files.FOX_ICO_PATH)
    root.title(i18n.snakeWelcome[i18n.lang()])
    SnakeWindow(root)
    root.focus_force()
    root.mainloop()
    root.destroy()
コード例 #12
0
ファイル: tasks.py プロジェクト: nalipour/Fuxenpruefung
def show_questions(qdictsAll):
    header = i18n.allquestionsHeader[i18n.lang()]
    lines = []
    lines.append(i18n.allquestionsColHeader[i18n.lang()])
    for key in qdictsAll:
        lines.append((
            qdictsAll[key][0],
            qdictsAll[key][1],
            qdictsAll[key][2],
            qdictsAll[key][3],
            qdictsAll[key][4],
        ))
    root = tk.Tk()
    if sys.platform == 'win32':
        root.iconbitmap(files.FOX_ICO_PATH)
    root.title('F*x!')
    gui.TextWindow(root, header, lines)
    root.focus_force()
    root.mainloop()
    root.destroy()
コード例 #13
0
ファイル: snake.py プロジェクト: Vorathel/Fuxenpruefung
 def _end_game():
     cancel()
     remove_items()
     canv.itemconfig('eventInfoText', text='R.I.P.')
     canv.create_text(BOX_X_MAX / 2,
                      BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.5,
                      fill='red',
                      font='b',
                      text=i18n.gameOver[i18n.lang()][0],
                      tags=('gameOverText'))
     canv.create_text(BOX_X_MAX / 2,
                      BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.6,
                      fill='red',
                      text=i18n.gameOver[i18n.lang()][1],
                      tags=('gameOverCancelText'))
     canv.create_text(BOX_X_MAX / 2,
                      BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.7,
                      fill='red',
                      text=i18n.gameOver[i18n.lang()][2],
                      tags=('gameOverRestartText'))
     master.bind('<Return>', _restart)
コード例 #14
0
ファイル: tasks.py プロジェクト: nalipour/Fuxenpruefung
def new_exam(qdicts, questNumbers, categories):
    ran_qdicts = randomize_questions(qdicts, questNumbers)

    with open(i18n.examFile[i18n.lang()][0], 'w', encoding='utf8') as myfile:
        print(i18n.examTitle[i18n.lang()][0] + "\n", file=myfile)
        count = 0
        for default, longName, shortName in categories:
            for question, answer, vspace in ran_qdicts[shortName]:
                count += 1
                questionlines = question.split("\\\\")
                print('{}.'.format(count), questionlines[0], file=myfile)
                for item in questionlines[1:]:
                    print('\to ' + item, file=myfile)
                print('\n' * int(vspace), file=myfile)

    with open(i18n.examFile[i18n.lang()][1], 'w', encoding='utf8') as myfile:
        print(i18n.examTitle[i18n.lang()][1] + "\n", file=myfile)
        count = 0
        for default, longName, shortName in categories:
            for question, answer, vspace in ran_qdicts[shortName]:
                count += 1
                print('{}.'.format(count), answer, file=myfile)

    if sys.platform == 'win32':
        sys_command = 'notepad ' + i18n.examFile[i18n.lang()][1]
        subprocess.Popen(sys_command)
        time.sleep(0.1)
        sys_command = 'notepad ' + i18n.examFile[i18n.lang()][0]
        subprocess.Popen(sys_command)
コード例 #15
0
        def display_highscore():
            canv.create_text(self.infoBoxXCenter,
                             BOX_Y_MIN + self.boxHeight * 0.5,
                             text=i18n.snakeHighScore[i18n.lang()][0] + '...',
                             font='b',
                             tags=('load_highscore'))
            scores = web_client.read_highscore()
            keys = None
            errText = None
            try:
                keys = sorted(scores[0].keys())
            except IndexError:
                errText = i18n.snakeWebErr[i18n.lang()][0]
            except TypeError:
                errText = i18n.snakeWebErr[i18n.lang()][1]
            delete_widget('load_highscore')
            hSpace = 10
            vSpace = 20
            subBoxXMin = self.infoBoxXMin + hSpace
            subBoxXMax = self.infoBoxXMax - hSpace

            topBoxYMin = BOX_Y_MIN + vSpace
            topBoxYMax = topBoxYMin + self.boxHeight * 0.4
            gui_utils.draw_table(master,
                                 canv,
                                 subBoxXMin,
                                 subBoxXMax,
                                 topBoxYMin,
                                 topBoxYMax,
                                 headers=keys,
                                 values=scores,
                                 nRows=N_HIGHSCORES + 1,
                                 title=i18n.snakeHighScore[i18n.lang()][2],
                                 tags='global_highscore',
                                 errText=errText)

            try:
                userScores = [
                    score for score in scores
                    if score['username'] == self.userName
                ]
            except TypeError:
                userScores = None
            lowBoxYMin = BOX_Y_MIN + self.boxHeight * 0.5 + vSpace * 0.5
            lowBoxYMax = lowBoxYMin + self.boxHeight * 0.4
            if not self.userName:
                errText = i18n.snakeWebErr[i18n.lang()][2]
            gui_utils.draw_table(master,
                                 canv,
                                 subBoxXMin,
                                 subBoxXMax,
                                 lowBoxYMin,
                                 lowBoxYMax,
                                 headers=keys,
                                 values=userScores,
                                 nRows=N_HIGHSCORES + 1,
                                 title=i18n.snakeHighScore[i18n.lang()][1],
                                 tags='personal_highscore',
                                 errText=errText)
コード例 #16
0
 def _end_game():
     cancel()
     remove_items()
     canv.create_text(BOX_X_MAX / 2,
                      BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.4,
                      fill='orange',
                      font=("Times", 25, "bold"),
                      text=i18n.gameOver[i18n.lang()][0],
                      tags=('gameOverText'))
     canv.create_text(BOX_X_MAX / 2,
                      BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.5,
                      fill='orange',
                      font=("Times", 25, "bold"),
                      text=i18n.gameOver[i18n.lang()][1],
                      tags=('gameOverCancelText'))
     canv.create_text(BOX_X_MAX / 2,
                      BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.6,
                      fill='orange',
                      font=("Times", 25, "bold"),
                      text=i18n.gameOver[i18n.lang()][2],
                      tags=('gameOverRestartText'))
     post_score()
     master.bind('<Return>', _restart)
コード例 #17
0
 def _end_game():
     _cancel()
     canv.create_text(BOX_X_MAX / 2,
                      BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.4,
                      fill='red',
                      font=("Times", 25, "bold"),
                      text=i18n.hitKey[i18n.lang()][1],
                      tags=('gameOverText'))
     canv.create_text(BOX_X_MAX / 2,
                      BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.5,
                      fill='red',
                      font=("Times", 25, "bold"),
                      text=i18n.hitKey[i18n.lang()][2],
                      tags=('gameOverCancelText'))
     canv.create_text(BOX_X_MAX / 2,
                      BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.6,
                      fill='red',
                      font=("Times", 25, "bold"),
                      text=i18n.hitKey[i18n.lang()][3],
                      tags=('gameOverRestartText'))
     _remove_objects()
     _post_score()
     master.bind('<Return>', _restart)
コード例 #18
0
 def _display_alerts():
     self.webAlerts = web_client.read_alerts()
     if not self.webAlerts:
         return
     canv.create_text(self.infoBoxXCenter,
                      BOX_Y_MIN + self.newsBoxYMax * 0.5,
                      text=i18n.webNews[i18n.lang()][2],
                      tags=('webAlertsHeader'),
                      fill='red',
                      font=("Times", 25, "bold"))
     for alert in self.webAlerts:
         alert = alert['message']
         canv.create_text(self.infoBoxXCenter,
                          BOX_Y_MIN + self.newsBoxYMax,
                          text=utils.break_lines(
                              alert, MAX_INFO_LINE_CHARS),
                          tags=('webAlerts'))
コード例 #19
0
 def set_switch_language():
     i18n.switch_language()
     set_image(_lang_button, i18n.lang_button_image(), 1, 20)
     set_text(_head_label, i18n.appHeader[i18n.lang()])
     for idx, rad in enumerate(_radioButton):
         set_text(rad, i18n.dictInit[i18n.lang()][idx])
     for idx, cat in enumerate(_cat_label):
         if cat is None:
             continue
         set_text(cat, i18n.longNames[i18n.lang()][idx])
     set_text(_start_button, i18n.startButtonText[i18n.lang()][0])
     set_text(_quit_button, i18n.startButtonText[i18n.lang()][1])
     set_text(_link_label, i18n.linkLabelText[i18n.lang()])
コード例 #20
0
ファイル: snake.py プロジェクト: Vorathel/Fuxenpruefung
 def _restart(event):
     reset(self)
     delete_widget('gameOverText')
     delete_widget('gameOverCancelText')
     delete_widget('gameOverRestartText')
     delete_widget('bucket')
     tailFoxes = [item for item in itemRegister if 'tail' in item]
     for item in tailFoxes:
         delete_widget(item)
     canv.itemconfig('foxText', text=': ' + str(self._nFoxes))
     canv.itemconfig('beerText',
                     text=': ' + str(self._nBeers) + ' / ' +
                     str(MAX_BEER - 1))
     canv.itemconfig('starText', text=': ' + str(self._score))
     canv.itemconfig('eventInfoText',
                     text=i18n.snakeEventInfo[i18n.lang()][0])
     canv.coords('major', FULL_WIDTH / 2,
                 BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) / 2)
     canv.majorImg = ImageTk.PhotoImage(majorImgObj.rotate(0))
     canv.itemconfig('major', image=canv.majorImg)
     _start(event)
コード例 #21
0
    def __init__(self, master):
        gui_utils.center_window(master)

        master.geometry('%sx%s+%s+%s' % (FULL_WIDTH, FULL_HEIGHT, 100, 100))
        master.resizable(0, 0)

        itemRegister = []
        self._activeFoxes = []
        self._currentRotation = 0
        self._direction = None
        self._foxlastXvec = []
        self._foxlastYvec = []
        self._goldFox = None
        self._goldFoxLife = 0
        self._job = {}
        self._nBeers = 0
        self._nBucket = 0
        self._nFoxes = 0
        self._nJaegers = 0
        self._nScoreStars = 0
        self._rotationSpeed = 0
        self._score = 0
        self._speed = START_SPEED
        self._tumbleAngle = START_TUMBLE_ANGLE
        self._xPath = deque([], MAX_QUEUE_LEN)
        self._xVel = 0
        self._xVelTumble = 0
        self._yPath = deque([], MAX_QUEUE_LEN)
        self._yVel = 0
        self._yVelTumble = 0

        def _reset(self):
            self._activeFoxes = []
            self._currentRotation = 0
            self._direction = None
            self._foxlastXvec = []
            self._foxlastYvec = []
            self._goldFox = None
            self._goldFoxLife = 0
            self._job = {}
            self._nBeers = 0
            self._nBucket = 0
            self._nFoxes = 0
            self._nJaegers = 0
            self._nScoreStars = 0
            self._rotationSpeed = 0
            self._score = 0
            self._speed = START_SPEED
            self._tumbleAngle = START_TUMBLE_ANGLE
            self._xPath = deque([], MAX_QUEUE_LEN)
            self._xVel = 0
            self._xVelTumble = 0
            self._yPath = deque([], MAX_QUEUE_LEN)
            self._yVel = 0
            self._yVelTumble = 0
            for _ in range(N_FREE_FOXES):
                self._foxlastXvec.append(random.random())
                self._foxlastYvec.append(random.random())

        def _delete_widget(name):
            canv.delete(name)
            try:
                itemRegister.remove(name)
            except ValueError:
                pass

        def _check_box_boundary(x, y, xSize=FOX_SIZE, ySize=FOX_SIZE):
            if x > BOX_X_MAX - xSize / 2 or \
               x < BOX_X_MIN + xSize / 2 or \
               y > BOX_Y_MAX - ySize / 2 or \
               y < BOX_Y_MIN + ySize / 2:
                return True

        def _check_clipping(x,
                            y,
                            xSize=MAJOR_SIZE,
                            ySize=MAJOR_SIZE,
                            exclude=None,
                            include=None):
            for item in itemRegister:
                if exclude and item in exclude:
                    continue
                if include and item not in include:
                    continue
                itemX, itemY = canv.coords(item)
                x0, y0, x1, y1 = canv.bbox(item)
                itemSizeX = x1 - x0
                itemSizeY = y1 - y0
                # print('New item x/y', round(x), '/', round(y), item, itemX, '/', itemY)
                PROXIMITY = 3
                isCloseX = abs(itemX -
                               x) < xSize / PROXIMITY + itemSizeX / PROXIMITY
                isCloseY = abs(itemY -
                               y) < ySize / PROXIMITY + itemSizeY / PROXIMITY
                if isCloseX and isCloseY:
                    return item
            return ''

        def _get_new_random_pos(xSize, ySize):
            nTries = 0
            while True:
                newX = BOX_X_MAX * random.random()
                newY = BOX_Y_MAX * random.random()
                # print(nTries, 'Trying newX newY', newX, '/', newY)
                if nTries > MAX_POSITION_LOOPS:
                    return (None, None)
                else:
                    nTries += 1
                if _check_box_boundary(newX, newY, xSize, ySize):
                    continue
                if _check_clipping(newX, newY, xSize, ySize):
                    continue
                return (newX, newY)

        def _draw_new_fox(newX=None,
                          newY=None,
                          name='fox',
                          size=1,
                          gold=False):
            if not newX and not newY:
                newX, newY = _get_new_random_pos(FOX_SIZE, FOX_SIZE)
                if not newX and not newY:
                    print('Warning: no new free fox position found!')
                    return
            _delete_widget(name)
            if gold:
                thisFoxImgObj = goldFoxImgObj.resize(
                    (int(FOX_SIZE * size), int(FOX_SIZE * size)),
                    Image.ANTIALIAS)
            else:
                thisFoxImgObj = foxImgObj.resize(
                    (int(FOX_SIZE * size), int(FOX_SIZE * size)),
                    Image.ANTIALIAS)
            canv.foxImg[name] = ImageTk.PhotoImage(thisFoxImgObj)
            canv.create_image(newX, newY, image=canv.foxImg[name], tags=(name))
            if name not in itemRegister:
                itemRegister.append(name)
            raise_top_objects()

        def _draw_new_beer(newX=None, newY=None, name='beer', size=1):
            if not newX and not newY:
                newX, newY = _get_new_random_pos(BEER_SIZE, BEER_SIZE)
                if not newX and not newY:
                    print('Warning: no new free beer position found!')
                    return
            _delete_widget(name)
            thisBeerImgObj = beerImgObj.resize(
                (int(BEER_SIZE * size), int(BEER_SIZE * size)),
                Image.ANTIALIAS)
            canv.beerImg[name] = ImageTk.PhotoImage(thisBeerImgObj)
            canv.create_image(newX,
                              newY,
                              image=canv.beerImg[name],
                              tags=(name))
            if name not in itemRegister:
                itemRegister.append(name)
            raise_top_objects()

        def _draw_new_bucket(newX=None, newY=None, name='bucket', size=1):
            if not newX and not newY:
                newX, newY = _get_new_random_pos(BUCKET_SIZE, BUCKET_SIZE)
                if not newX and not newY:
                    print('Warning: no new free bucket position found!')
                    return
            _delete_widget(name)
            thisBucketImgObj = bucketImgObj.resize(
                (int(BUCKET_SIZE * size), int(BEER_SIZE * size)),
                Image.ANTIALIAS)
            canv.bucketImg[name] = ImageTk.PhotoImage(thisBucketImgObj)
            canv.create_image(newX,
                              newY,
                              image=canv.bucketImg[name],
                              tags=(name))
            if name not in itemRegister:
                itemRegister.append(name)
            raise_top_objects()

        def _draw_new_jaeger(newX=None, newY=None, name='jaeger', size=1):
            if not newX and not newY:
                newX, newY = _get_new_random_pos(JAEGER_SIZE, JAEGER_SIZE)
                if not newX and not newY:
                    print('Warning: no new free jaeger position found!')
                    return
            _delete_widget(name)
            thisJaegerImgObj = jaegerImgObj.resize(
                (int(JAEGER_SIZE * size), int(BEER_SIZE * size)),
                Image.ANTIALIAS)
            canv.jaegerImg[name] = ImageTk.PhotoImage(thisJaegerImgObj)
            canv.create_image(newX,
                              newY,
                              image=canv.jaegerImg[name],
                              tags=(name))
            if name not in itemRegister:
                itemRegister.append(name)
            raise_top_objects()

        def _draw_new_star(newX=None, newY=None, name='star', size=1):
            if not newX and not newY:
                newX, newY = _get_new_random_pos(STAR_SIZE, STAR_SIZE)
                if not newX and not newY:
                    print('Warning: no new free star position found!')
                    return
            _delete_widget(name)
            thisStarImgObj = starImgObj.resize(
                (int(STAR_SIZE * size), int(STAR_SIZE * size)),
                Image.ANTIALIAS)
            canv.starImg[name] = ImageTk.PhotoImage(thisStarImgObj)
            canv.create_image(newX,
                              newY,
                              image=canv.starImg[name],
                              tags=(name))
            if name not in itemRegister:
                itemRegister.append(name)
            raise_top_objects()

        def _move_fox_tail():
            for idx in range(self._nFoxes):
                thisFoxTag = 'tail' + str(idx)
                try:
                    canv.coords(thisFoxTag,
                                self._xPath[(idx + 1) * TAIL_STEP_DISTANCE],
                                self._yPath[(idx + 1) * TAIL_STEP_DISTANCE])
                except IndexError:
                    return
                self._activeFoxes.append(idx)

        def _keep_in_box(item):
            itemX, itemY = canv.coords(item)
            if itemX < BOX_X_MIN:
                canv.coords(item, BOX_X_MAX, itemY)
            if itemX > BOX_X_MAX:
                canv.coords(item, BOX_X_MIN, itemY)
            if itemY < BOX_Y_MIN:
                canv.coords(item, itemX, BOX_Y_MAX)
            if itemY > BOX_Y_MAX:
                canv.coords(item, itemX, BOX_Y_MIN)

        def _move_free_fox():
            for idx in range(N_FREE_FOXES):
                name = 'fox' + str(idx)
                x, y = canv.coords(name)
                MAX_ALLOWED_ANGLE = 60
                while True:
                    yShift = (1 - 2 * random.random()) * MOVEMENT_STEP_SIZE
                    xShift = (1 - 2 * random.random()) * MOVEMENT_STEP_SIZE
                    angle = maths.get_angle(xShift, yShift,
                                            self._foxlastXvec[idx],
                                            self._foxlastYvec[idx])
                    if abs(angle) < MAX_ALLOWED_ANGLE:
                        break
                x, y = x + xShift, y + yShift
                if not _check_clipping(
                        x, y, xSize=FOX_SIZE, ySize=FOX_SIZE, exclude=name):
                    self._foxlastXvec[idx] = xShift
                    self._foxlastYvec[idx] = yShift
                    canv.move(name, xShift, yShift)
                    _keep_in_box(name)
                else:
                    self._foxlastXvec[idx] = -self._foxlastXvec[idx]
                    self._foxlastYvec[idx] = -self._foxlastYvec[idx]
                    canv.move(name, self._foxlastXvec[idx],
                              self._foxlastYvec[idx])
                    _keep_in_box(name)
                if self._goldFox == name:
                    self._goldFoxLife += 1
                    if self._goldFoxLife > GOLD_FOX_LIFE_STEPS:
                        self._goldFox = None
                        self._goldFoxLife = 0
                        _delete_widget(name)
                        _draw_new_fox(x, y, name)
            self._job['move_free_fox'] = master.after(int(1 / START_SPEED),
                                                      _move_free_fox)

        def _get_new_tail_pos():
            newX, newY = canv.coords('major')
            try:
                newX = self._xPath[(self._nFoxes) * TAIL_STEP_DISTANCE]
                newY = self._yPath[(self._nFoxes) * TAIL_STEP_DISTANCE]
                return (newX, newY)
            except IndexError:
                try:
                    if self._nFoxes:
                        newX, newY = canv.coords('tail' +
                                                 str(self._nFoxes - 1))
                except ValueError:
                    pass
            return (newX, newY)

        def _raise_score(name):
            value = int(name.split('value_')[-1])
            self._score += value
            canv.itemconfig('starText', text=': ' + str(self._score))

        def _move_score_star(name, origX, origY, randVar=None):
            targetX, targetY = canv.coords('scoreStar')
            itemX, itemY = canv.coords(name)
            arrived = False
            if itemY > targetY:
                arrived = True
            if arrived:
                _delete_widget(name)
                _raise_score(name)
                return
            if randVar is None:
                randVar = 1 - 2 * random.random()
            if targetX != origX:
                xVel = SCORE_STAR_MOVEMENT_STEP_SIZE * (
                    targetX - origX) / targetX * (1 + randVar * 0.25)
                peakX = origX + randVar * (targetX - origX) / 4
                yVel = maths.get_parabola(
                    origX, origY, targetX, targetY, itemX + xVel,
                    peakX=peakX) - itemY
            else:
                xVel = 0
                yVel = SCORE_STAR_MOVEMENT_STEP_SIZE * (
                    1 + abs(origY - itemY) / targetY) * (1 + randVar * 0.25)
            canv.move(name, xVel, yVel)

            def helpFunc():
                return _move_score_star(name, origX, origY, randVar)

            self._job['move_' + name] = master.after(int(1 / SCORE_STAR_SPEED),
                                                     helpFunc)

        def raise_top_objects():
            for item in itemRegister:
                if item.startswith('scoreStar'):
                    canv.tag_raise(item)

        def _move():
            if self._direction is not None:
                canv.move('major', self._xVelTumble, self._yVelTumble)
                itemX, itemY = canv.coords('major')
                self._xPath.appendleft(itemX)
                self._yPath.appendleft(itemY)
                _keep_in_box('major')
                _move_fox_tail()
                beerList = list(map(lambda x: 'beer' + str(x), range(N_BEERS)))
                freeFoxList = list(
                    map(lambda x: 'fox' + str(x), range(N_FREE_FOXES)))
                # catch foxes
                foxCollision = _check_clipping(itemX,
                                               itemY,
                                               include=freeFoxList)
                if foxCollision:
                    sound.play_sound(files.BLOP_WAV_PATH)
                    self._nFoxes += 1
                    canv.itemconfig('foxText', text=': ' + str(self._nFoxes))
                    goldFoxTail = False
                    if foxCollision == self._goldFox:
                        goldFoxTail = True
                        self._goldFox = None
                        self._goldFoxLife = 0
                    newX, newY = _get_new_tail_pos()
                    _draw_new_fox(newX=newX,
                                  newY=newY,
                                  name='tail' + str(self._nFoxes - 1),
                                  gold=goldFoxTail)
                    for item in reversed(itemRegister):
                        canv.tag_raise(item)
                    goldFox = False
                    if self._goldFox is None and random.random(
                    ) < GOLD_FOX_CHANCE:
                        goldFox = True
                        self._goldFox = foxCollision
                    _draw_new_fox(name=foxCollision, gold=goldFox)
                    foxIdx = int(foxCollision.lstrip('fox'))
                    self._foxlastXvec[foxIdx] = random.random()
                    self._foxlastYvec[foxIdx] = random.random()
                    if not any(i in itemRegister for i in beerList):
                        for beerName in beerList:
                            if random.random() < BEER_RESPAWN_CHANCE:
                                _draw_new_beer(name=beerName)
                    if self._nJaegers == 0 and random.random() < JAEGER_CHANCE:
                        _draw_new_jaeger(name='jaeger')
                        self._nJaegers += 1
                    if self._nBeers > 0:
                        foxValue = self._nBeers
                        starScale = min(0.3 + self._nBeers / MAX_BEER * 0.3,
                                        0.7)
                        if goldFoxTail:
                            for _ in range(GOLD_FOX_MULTIPLIER):
                                starName = 'scoreStar_' + str(
                                    self._nScoreStars) + '_value_' + str(
                                        foxValue)
                                _draw_new_star(itemX, itemY, starName,
                                               starScale)
                                _move_score_star(starName, itemX, itemY)
                                self._nScoreStars += 1
                        else:
                            starName = 'scoreStar_' + str(
                                self._nScoreStars) + '_value_' + str(foxValue)
                            _draw_new_star(itemX, itemY, starName, starScale)
                            _move_score_star(starName, itemX, itemY)
                            self._nScoreStars += 1

                def set_alc_effect(weight=1):
                    for _ in range(weight):
                        step = (MAX_SPEED - START_SPEED) / N_SPEED_STEPS
                        self._speed = min(self._speed + step, MAX_SPEED)
                        if self._nBeers == MAX_BEER or (
                                self._rotationSpeed == 0
                                and self._nBeers > MAX_BEER):
                            self._rotationSpeed = START_ROTATION_SPEED
                        elif self._nBeers > MAX_BEER:
                            step = (MAX_ROTATION_SPEED - START_ROTATION_SPEED
                                    ) / N_ROTATION_SPEED_STEPS
                            self._rotationSpeed = min(
                                self._rotationSpeed + step, MAX_ROTATION_SPEED)
                            step = (MAX_TUMBLE_ANGLE -
                                    START_TUMBLE_ANGLE) / N_TUMBLE_STEPS
                            self._tumbleAngle = min(self._tumbleAngle + step,
                                                    MAX_TUMBLE_ANGLE)

                # drink beer
                beerCollision = _check_clipping(itemX, itemY, include=beerList)
                if beerCollision:
                    sound.play_sound(files.SLURP_WAV_PATH)
                    self._nBeers += 1
                    set_alc_effect()
                    canv.itemconfig('beerText',
                                    text=': ' + str(self._nBeers) + ' / ' +
                                    str(MAX_BEER - 1))
                    if self._nBeers >= MAX_BEER + 5 and self._nBucket == 0:
                        _draw_new_bucket(name='bucket')
                        self._nBucket += 1
                    if random.random() < BEER_RESPAWN_CHANCE:
                        _draw_new_beer(name=beerCollision)
                    else:
                        _delete_widget(beerCollision)
                    if self._nJaegers == 0 and random.random() < JAEGER_CHANCE:
                        _draw_new_jaeger(name='jaeger')
                        self._nJaegers += 1

                # drink jaeger
                if _check_clipping(itemX, itemY, include='jaeger'):
                    sound.play_sound(files.SLURP_WAV_PATH)
                    self._nBeers += JAEGER_MULTIPLIER
                    set_alc_effect(JAEGER_MULTIPLIER)
                    canv.itemconfig('beerText',
                                    text=': ' + str(self._nBeers) + ' / ' +
                                    str(MAX_BEER - 1))
                    if self._nBeers >= MAX_BEER + 5 and self._nBucket == 0:
                        _draw_new_bucket(name='bucket')
                        self._nBucket += 1
                    _delete_widget('jaeger')
                    self._nJaegers -= 1

                # hit bucket
                if _check_clipping(itemX, itemY, include='bucket'):
                    sound.play_sound(files.HICCUP_WAV_PATH)
                    self._nBeers = MAX_BEER - 1
                    canv.itemconfig('beerText',
                                    text=': ' + str(self._nBeers) + ' / ' +
                                    str(MAX_BEER - 1))
                    _delete_widget('bucket')
                    self._nBucket -= 1
                    self._currentRotation = 0
                    self._rotationSpeed = 0
                    self._tumbleAngle = START_TUMBLE_ANGLE

                # rotate major and its direction
                # print('speed', self._speed, 'rotationSpeed', self._rotationSpeed, 'tumbleDegree', self._tumbleAngle)
                self._currentRotation += self._rotationSpeed
                canv.majorImg = ImageTk.PhotoImage(
                    majorImgObj.rotate(self._tumbleAngle * 2 *
                                       math.sin(self._currentRotation)))
                canv.itemconfig('major', image=canv.majorImg)
                angle = maths.get_angle(1, 0, self._xVel, self._yVel)
                angle += self._tumbleAngle * math.sin(-self._currentRotation)
                angle = math.radians(angle)
                self._xVelTumble = MOVEMENT_STEP_SIZE * math.cos(angle)
                self._yVelTumble = MOVEMENT_STEP_SIZE * math.sin(angle)
                # check tail overlap
                noTailFoxes = [
                    item for item in itemRegister if 'tail' not in item
                ]
                noTailFoxes.extend(['tail' + str(idx) for idx in range(2)])
                noTailFoxes.extend([
                    'tail' + str(idx) for idx in range(self._nFoxes)
                    if idx not in self._activeFoxes
                ])
                crashFox = _check_clipping(itemX,
                                           itemY,
                                           exclude=noTailFoxes,
                                           xSize=MAJOR_SIZE * 0.1,
                                           ySize=MAJOR_SIZE * 0.1)

                if crashFox:
                    sound.play_sound(files.BLAST_WAV_PATH)
                    print('Overlapping with tail', crashFox)
                    _end_game()
                    return
            self._job['move'] = master.after(int(1 / self._speed), _move)

        def _set_username():
            userName = simpledialog.askstring(
                i18n.snakeUserNameRequest[i18n.lang()][2],
                i18n.snakeUserNameRequest[i18n.lang()][0] + ':')
            if not userName:
                return
            self.userName = userName
            self.userNameButton['text'] = self.userName + ' ({0})'.format(
                i18n.snakeUserNameRequest[i18n.lang()][1])
            with open(files.SNAKE_CONFIG_FILE, 'w') as outfile:
                yaml.dump({'username': self.userName},
                          outfile,
                          default_flow_style=False)

        def _post_score():
            if not self.userName:
                _set_username()
            if not self.userName:
                return
            web_client.post_score(username=self.userName, score=self._score)

        def _display_highscore():
            canv.create_text(self.infoBoxXCenter,
                             BOX_Y_MIN + self.boxHeight * 0.5,
                             text=i18n.snakeHighScore[i18n.lang()][0] + '...',
                             font='b',
                             tags=('load_highscore'))
            alertThread.join()
            newsThread.join()
            scores = web_client.read_highscore()
            keys = None
            errText = None
            try:
                keys = sorted(scores[0].keys())
            except IndexError:
                errText = i18n.snakeWebErr[i18n.lang()][0]
            except TypeError:
                errText = i18n.snakeWebErr[i18n.lang()][1]
            _delete_widget('load_highscore')
            hSpace = 10
            vSpace = 20
            subBoxXMin = self.infoBoxXMin + hSpace
            subBoxXMax = self.infoBoxXMax - hSpace

            topBoxYMin = BOX_Y_MIN + vSpace
            topBoxYMax = topBoxYMin + self.boxHeight * 0.4
            gui_utils.draw_table(master,
                                 canv,
                                 subBoxXMin,
                                 subBoxXMax,
                                 topBoxYMin,
                                 topBoxYMax,
                                 headers=keys,
                                 values=scores,
                                 nRows=N_HIGHSCORES + 1,
                                 title=i18n.snakeHighScore[i18n.lang()][2],
                                 tags='global_highscore',
                                 errText=errText)

            try:
                userScores = [
                    score for score in scores
                    if score['username'] == self.userName
                ]
            except TypeError:
                userScores = None
            lowBoxYMin = BOX_Y_MIN + self.boxHeight * 0.5 + vSpace * 0.5
            lowBoxYMax = lowBoxYMin + self.boxHeight * 0.4
            if not self.userName:
                errText = i18n.snakeWebErr[i18n.lang()][2]
            gui_utils.draw_table(master,
                                 canv,
                                 subBoxXMin,
                                 subBoxXMax,
                                 lowBoxYMin,
                                 lowBoxYMax,
                                 headers=keys,
                                 values=userScores,
                                 nRows=N_HIGHSCORES + 1,
                                 title=i18n.snakeHighScore[i18n.lang()][1],
                                 tags='personal_highscore',
                                 errText=errText)
            raise_top_objects()

        def _display_news():
            alertThread.join()
            news = web_client.read_news()
            if news is None:
                return
            self.webNews = news['message']
            canv.itemconfig('webNews',
                            text=utils.break_lines(self.webNews,
                                                   MAX_INFO_LINE_CHARS))

        def _display_alerts():
            self.webAlerts = web_client.read_alerts()
            if not self.webAlerts:
                return
            canv.create_text(self.infoBoxXCenter,
                             BOX_Y_MIN + self.newsBoxYMax * 0.5,
                             text=i18n.webNews[i18n.lang()][2],
                             tags=('webAlertsHeader'),
                             fill='red',
                             font=("Times", 25, "bold"))
            for alert in self.webAlerts:
                alert = alert['message']
                canv.create_text(self.infoBoxXCenter,
                                 BOX_Y_MIN + self.newsBoxYMax,
                                 text=utils.break_lines(
                                     alert, MAX_INFO_LINE_CHARS),
                                 tags=('webAlerts'))

        def _quit(event=None):
            time.sleep(0.1)
            master.quit()

        def _cancel():
            for job in self._job:
                master.after_cancel(self._job[job])
            self._job = {}

        def _remove_objects():
            removeList = []
            for item in itemRegister:
                if item.startswith('scoreStar_'):
                    _raise_score(item)
                    removeList.append(item)
            for item in removeList:
                _delete_widget(item)

        def _end_game():
            _cancel()
            canv.create_text(BOX_X_MAX / 2,
                             BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.4,
                             fill='red',
                             font=("Times", 25, "bold"),
                             text=i18n.hitKey[i18n.lang()][1],
                             tags=('gameOverText'))
            canv.create_text(BOX_X_MAX / 2,
                             BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.5,
                             fill='red',
                             font=("Times", 25, "bold"),
                             text=i18n.hitKey[i18n.lang()][2],
                             tags=('gameOverCancelText'))
            canv.create_text(BOX_X_MAX / 2,
                             BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.6,
                             fill='red',
                             font=("Times", 25, "bold"),
                             text=i18n.hitKey[i18n.lang()][3],
                             tags=('gameOverRestartText'))
            _remove_objects()
            _post_score()
            master.bind('<Return>', _restart)

        def _init_start(event):
            _reset(self)
            _start()

        def _start():
            _delete_widget('startKeystrokeText')
            _delete_widget('instructionText1')
            _delete_widget('instructionText2')
            _delete_widget('instructionText3')
            _delete_widget('instructionText4')
            _delete_widget('instructionText5')
            _delete_widget('instructionHeader')
            _delete_widget('instrBeer')
            _delete_widget('instrFox')
            _delete_widget('instrGoldFox')
            _delete_widget('instrJaeger')
            _delete_widget('instrBucket')
            _delete_widget('news_line')
            for widgetID in canv.find_all():
                widget = canv.gettags(widgetID)[0]
                if 'webAlerts' in widget or 'webNews' in widget:
                    _delete_widget(widget)
            for idx in range(N_FREE_FOXES):
                _draw_new_fox(name='fox' + str(idx))
            for idx in range(N_BEERS):
                _draw_new_beer(name='beer' + str(idx))
            master.bind('<Up>', _change_direction)
            master.bind('<Down>', _change_direction)
            master.bind('<Right>', _change_direction)
            master.bind('<Left>', _change_direction)
            master.bind('w', _change_direction)
            master.bind('a', _change_direction)
            master.bind('s', _change_direction)
            master.bind('d', _change_direction)
            master.unbind('<Return>')
            _move()
            _move_free_fox()
            highScoreThread = threading.Thread(target=_display_highscore)
            highScoreThread.start()

        def _restart(event):
            _reset(self)
            _delete_widget('gameOverText')
            _delete_widget('gameOverCancelText')
            _delete_widget('gameOverRestartText')
            _delete_widget('bucket')
            _delete_widget('jaeger')
            tailFoxes = [item for item in itemRegister if 'tail' in item]
            for item in tailFoxes:
                _delete_widget(item)
            canv.itemconfig('foxText', text=': ' + str(self._nFoxes))
            canv.itemconfig('beerText',
                            text=': ' + str(self._nBeers) + ' / ' +
                            str(MAX_BEER - 1))
            canv.itemconfig('starText', text=': ' + str(self._score))
            canv.coords('major', BOX_X_MIN + self.boxWidth * 0.5,
                        BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) / 2)
            canv.majorImg = ImageTk.PhotoImage(majorImgObj.rotate(0))
            canv.itemconfig('major', image=canv.majorImg)
            for widgetID in canv.find_all():
                widget = canv.gettags(widgetID)[0]
                if 'global_highscore' in widget:
                    _delete_widget(widget)
                if 'personal_highscore' in widget:
                    _delete_widget(widget)
            _start()

        def _change_direction(event):
            if event.keysym == 'w':
                event.keysym = 'Up'
            if event.keysym == 'a':
                event.keysym = 'Left'
            if event.keysym == 's':
                event.keysym = 'Down'
            if event.keysym == 'd':
                event.keysym = 'Right'
            if not self._nFoxes:
                self._direction = 'meaningless'
            if event.keysym == 'Up' and self._direction != 'Down':
                self._yVel = -MOVEMENT_STEP_SIZE
                self._xVel = 0
                self._direction = event.keysym
            if event.keysym == 'Down' and self._direction != 'Up':
                self._yVel = MOVEMENT_STEP_SIZE
                self._xVel = 0
                self._direction = event.keysym
            if event.keysym == 'Right' and self._direction != 'Left':
                self._yVel = 0
                self._xVel = MOVEMENT_STEP_SIZE
                self._direction = event.keysym
            if event.keysym == 'Left' and self._direction != 'Right':
                self._yVel = 0
                self._xVel = -MOVEMENT_STEP_SIZE
                self._direction = event.keysym

        canv = tk.Canvas(master, highlightthickness=0)
        canv.pack(fill='both', expand=True)

        self.userNameButton = tk.Button(
            master,
            text=i18n.snakeUserNameRequest[i18n.lang()][0],
            command=_set_username)
        if self.userName:
            self.userNameButton['text'] = self.userName + ' ({0})'.format(
                i18n.snakeUserNameRequest[i18n.lang()][1])
        self.userNameButton.place(x=FULL_WIDTH, y=BOX_Y_MIN * 0.4, anchor='e')

        majorImgObj = Image.open(files.MAJOR_IMG_PATH)
        majorImgObj = majorImgObj.resize((MAJOR_SIZE, MAJOR_SIZE),
                                         Image.ANTIALIAS)
        canv.majorImg = ImageTk.PhotoImage(majorImgObj)

        foxImgObj = Image.open(files.FOX_ICO_PATH)
        foxImgObj = foxImgObj.resize((FOX_SIZE, FOX_SIZE), Image.ANTIALIAS)

        goldFoxImgObj = Image.open(files.GOLD_FOX_ICO_PATH)
        goldFoxImgObj = goldFoxImgObj.resize((FOX_SIZE, FOX_SIZE),
                                             Image.ANTIALIAS)

        beerImgObj = Image.open(files.BEER_IMG_PATH)
        beerImgObj = beerImgObj.resize((BEER_SIZE, BEER_SIZE), Image.ANTIALIAS)

        starImgObj = Image.open(files.STAR_IMG_PATH)
        starImgObj = starImgObj.resize((STAR_SIZE, STAR_SIZE), Image.ANTIALIAS)

        bucketImgObj = Image.open(files.BUCKET_IMG_PATH)
        bucketImgObj = bucketImgObj.resize((BUCKET_SIZE, BUCKET_SIZE),
                                           Image.ANTIALIAS)

        jaegerImgObj = Image.open(files.JAEGER_IMG_PATH)
        jaegerImgObj = jaegerImgObj.resize((JAEGER_SIZE, JAEGER_SIZE),
                                           Image.ANTIALIAS)

        floorImgObj = Image.open(files.FLOOR_IMG_PATH)
        floorImgObj = floorImgObj.resize(
            (BOX_X_MAX - BOX_X_MIN, BOX_Y_MAX - BOX_Y_MIN), Image.ANTIALIAS)
        canv.floorImg = ImageTk.PhotoImage(floorImgObj)

        canv.foxImg = {}
        canv.beerImg = {}
        canv.starImg = {}
        canv.bucketImg = {}
        canv.jaegerImg = {}

        canv.create_image((BOX_X_MAX + BOX_X_MIN) / 2,
                          (BOX_Y_MAX + BOX_Y_MIN) / 2,
                          image=canv.floorImg,
                          tags=('floor'))

        canv.create_line(0,
                         BOX_Y_MIN,
                         FULL_WIDTH,
                         BOX_Y_MIN,
                         fill='black',
                         tags=('top'),
                         width=10)
        canv.create_line(BOX_X_MIN,
                         BOX_Y_MIN,
                         BOX_X_MIN,
                         BOX_Y_MAX,
                         fill='black',
                         tags=('left'),
                         width=10)
        canv.create_line(BOX_X_MAX - 1,
                         BOX_Y_MIN,
                         BOX_X_MAX - 1,
                         BOX_Y_MAX,
                         fill='black',
                         tags=('center'),
                         width=10)
        canv.create_line(FULL_WIDTH,
                         BOX_Y_MIN,
                         FULL_WIDTH,
                         BOX_Y_MAX,
                         fill='black',
                         tags=('right'),
                         width=10)
        canv.create_line(0,
                         BOX_Y_MAX - 2,
                         FULL_WIDTH,
                         BOX_Y_MAX - 2,
                         fill='black',
                         tags=('bottom'),
                         width=10)

        canv.create_text(FULL_WIDTH / 2,
                         BOX_Y_MIN * 0.4,
                         text=i18n.snakeWelcome[i18n.lang()],
                         tags=('welcomeText'),
                         font=("Times", 25, "bold"),
                         fill='orange')

        deltaY = self.boxHeight * 0.07
        instructionY = BOX_Y_MIN + self.boxHeight * 0.35

        canv.create_text(self.infoBoxXCenter,
                         instructionY,
                         text=i18n.snakeInstruction[i18n.lang()][0],
                         tags=('instructionHeader'),
                         fill='green',
                         font=("Times", 25, "bold"))

        instructionY += deltaY
        _draw_new_beer(self.infoBoxXMin + self.infoBoxWidth * 0.15,
                       instructionY, "instrBeer", 0.5)
        canv.create_text(self.infoBoxXMin + self.infoBoxWidth * 0.2,
                         instructionY,
                         tags=('instructionText1'),
                         anchor='w',
                         text=i18n.snakeInstruction[i18n.lang()][1])
        instructionY += deltaY
        _draw_new_fox(self.infoBoxXMin + self.infoBoxWidth * 0.15,
                      instructionY, "instrFox", 0.5)
        canv.create_text(self.infoBoxXMin + self.infoBoxWidth * 0.2,
                         instructionY,
                         tags=('instructionText2'),
                         anchor='w',
                         text=i18n.snakeInstruction[i18n.lang()][2])
        instructionY += deltaY
        _draw_new_fox(self.infoBoxXMin + self.infoBoxWidth * 0.15,
                      instructionY,
                      "instrGoldFox",
                      0.5,
                      gold=True)
        canv.create_text(self.infoBoxXMin + self.infoBoxWidth * 0.2,
                         instructionY,
                         tags=('instructionText3'),
                         anchor='w',
                         text=i18n.snakeInstruction[i18n.lang()][3].format(
                             GOLD_FOX_MULTIPLIER))
        instructionY += deltaY
        _draw_new_jaeger(self.infoBoxXMin + self.infoBoxWidth * 0.15,
                         instructionY, "instrJaeger", 0.5)
        canv.create_text(self.infoBoxXMin + self.infoBoxWidth * 0.2,
                         instructionY,
                         tags=('instructionText4'),
                         anchor='w',
                         text=i18n.snakeInstruction[i18n.lang()][4].format(
                             JAEGER_MULTIPLIER))
        instructionY += deltaY
        _draw_new_bucket(self.infoBoxXMin + self.infoBoxWidth * 0.15,
                         instructionY, "instrBucket", 0.5)
        canv.create_text(self.infoBoxXMin + self.infoBoxWidth * 0.2,
                         instructionY,
                         tags=('instructionText5'),
                         anchor='w',
                         text=i18n.snakeInstruction[i18n.lang()][5])

        canv.create_text(self.infoBoxXCenter,
                         BOX_Y_MAX - self.newsBoxYMax,
                         text=i18n.webNews[i18n.lang()][1],
                         tags=('webNewsHeader'),
                         fill='orange',
                         font=("Times", 25, "bold"))
        canv.create_text(self.infoBoxXCenter,
                         BOX_Y_MAX - self.newsBoxYMax * 0.5,
                         text=self.webNews,
                         tags=('webNews'))

        canv.create_image(BOX_X_MIN + self.boxWidth * 0.5,
                          BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) / 2,
                          image=canv.majorImg,
                          tags=('major'))
        itemRegister.append('major')

        canv.create_text(BOX_X_MAX * 0.5,
                         BOX_Y_MIN + self.boxHeight * 0.75,
                         fill='orange',
                         font=("Times", 25, "bold"),
                         text=i18n.hitKey[i18n.lang()][0],
                         tags=('startKeystrokeText'))

        _draw_new_fox(BOX_X_MIN + self.boxWidth * 0.25, self.bottomRowY,
                      'scoreFox', 0.5)
        canv.create_text(BOX_X_MIN + self.boxWidth * 0.28,
                         self.bottomRowY,
                         text=': ' + str(self._nFoxes),
                         font='b',
                         tags=('foxText'),
                         anchor="w")
        _draw_new_star(BOX_X_MIN + self.boxWidth * 0.5, self.bottomRowY,
                       'scoreStar', 0.5)
        canv.create_text(BOX_X_MIN + self.boxWidth * 0.53,
                         self.bottomRowY,
                         text=': ' + str(self._nBeers),
                         font='b',
                         tags=('starText'),
                         anchor="w")
        _draw_new_beer(BOX_X_MIN + self.boxWidth * 0.75, self.bottomRowY,
                       'scoreBeer', 0.5)
        canv.create_text(BOX_X_MIN + self.boxWidth * 0.77,
                         self.bottomRowY,
                         text=': ' + str(self._nBeers) + ' / ' +
                         str(MAX_BEER - 1),
                         font='b',
                         tags=('beerText'),
                         anchor="w")

        alertThread = threading.Thread(target=_display_alerts)
        alertThread.start()
        newsThread = threading.Thread(target=_display_news)
        newsThread.start()
        master.protocol("WM_DELETE_WINDOW", _quit)
        master.bind('<Up>', _init_start)
        master.bind('<Down>', _init_start)
        master.bind('<Right>', _init_start)
        master.bind('<Left>', _init_start)
        master.bind('w', _init_start)
        master.bind('a', _init_start)
        master.bind('s', _init_start)
        master.bind('d', _init_start)
        master.bind('<Escape>', _quit)
        master.bind('<Return>', _init_start)
コード例 #22
0
    def __init__(self, master):
        gui_utils.center_window(master)

        master.geometry('%sx%s+%s+%s' % (FULL_WIDTH, FULL_HEIGHT, 100, 100))
        master.resizable(0, 0)

        itemRegister = []
        self._score = 0
        self._nFoxes = 0
        self._nBeers = 0

        def reset(self):
            self._xPath = deque([], MAX_QUEUE_LEN)
            self._yPath = deque([], MAX_QUEUE_LEN)
            self._xVel = 0
            self._yVel = 0
            self._xVelTumble = 0
            self._yVelTumble = 0
            self._direction = None
            self._score = 0
            self._nFoxes = 0
            self._nBeers = 0
            self._speed = START_SPEED
            self._job = {}
            self._rotationSpeed = 0
            self._currentRotation = 0
            self._tumbleAngle = START_TUMBLE_ANGLE
            self._foxlastXvec = []
            self._foxlastYvec = []
            for idx in range(N_FREE_FOXES):
                self._foxlastXvec.append(random.random())
                self._foxlastYvec.append(random.random())

        def delete_widget(name):
            canv.delete(name)
            try:
                itemRegister.remove(name)
            except ValueError:
                pass

        def _set_username():
            userName = simpledialog.askstring(
                i18n.snakeUserNameRequest[i18n.lang()][2],
                i18n.snakeUserNameRequest[i18n.lang()][0] + ':')
            if not userName:
                return
            self.userName = userName
            self.userNameButton['text'] = self.userName + ' ({0})'.format(
                i18n.snakeUserNameRequest[i18n.lang()][1])
            with open(files.SNAKE_CONFIG_FILE, 'w') as outfile:
                yaml.dump({'username': self.userName},
                          outfile,
                          default_flow_style=False)

        def _draw_new_fox(newX=None, newY=None, name='fox', size=1):
            if not newX and not newY:
                newX, newY = get_new_random_pos(FOX_SIZE, FOX_SIZE)
                if not newX and not newY:
                    print('Warning: no new free fox position found!')
                    _end_game()
            delete_widget(name)
            thisFoxImgObj = foxImgObj.resize(
                (int(FOX_SIZE * size), int(FOX_SIZE * size)), Image.ANTIALIAS)
            canv.foxImg[name] = ImageTk.PhotoImage(thisFoxImgObj)
            canv.create_image(newX, newY, image=canv.foxImg[name], tags=(name))
            if name not in itemRegister:
                itemRegister.append(name)

        def _draw_new_beer(newX=None, newY=None, name='beer', size=1):
            if not newX and not newY:
                newX, newY = get_new_random_pos(BEER_SIZE, BEER_SIZE)
                if not newX and not newY:
                    print('Warning: no new free beer position found!')
                    _end_game()
            delete_widget(name)
            thisBeerImgObj = beerImgObj.resize(
                (int(BEER_SIZE * size), int(BEER_SIZE * size)),
                Image.ANTIALIAS)
            canv.beerImg[name] = ImageTk.PhotoImage(thisBeerImgObj)
            canv.create_image(newX,
                              newY,
                              image=canv.beerImg[name],
                              tags=(name))
            if name not in itemRegister:
                itemRegister.append(name)

        def _draw_new_bucket(newX=None, newY=None, name='bucket', size=1):
            if not newX and not newY:
                newX, newY = get_new_random_pos(BUCKET_SIZE, BUCKET_SIZE)
                if not newX and not newY:
                    print('Warning: no new free bucket position found!')
                    _end_game()
            delete_widget(name)
            thisBucketImgObj = bucketImgObj.resize(
                (int(BUCKET_SIZE * size), int(BEER_SIZE * size)),
                Image.ANTIALIAS)
            canv.bucketImg[name] = ImageTk.PhotoImage(thisBucketImgObj)
            canv.create_image(newX,
                              newY,
                              image=canv.bucketImg[name],
                              tags=(name))
            if name not in itemRegister:
                itemRegister.append(name)

        def _draw_new_star(newX=None, newY=None, name='star', size=1):
            if not newX and not newY:
                newX, newY = get_new_random_pos(STAR_SIZE, STAR_SIZE)
                if not newX and not newY:
                    print('Warning: no new free star position found!')
                    _end_game()
            delete_widget(name)
            thisStarImgObj = starImgObj.resize(
                (int(FOX_SIZE * size), int(FOX_SIZE * size)), Image.ANTIALIAS)
            canv.starImg[name] = ImageTk.PhotoImage(thisStarImgObj)
            canv.create_image(newX,
                              newY,
                              image=canv.starImg[name],
                              tags=(name))
            if name not in itemRegister:
                itemRegister.append(name)

        canv = tk.Canvas(master, highlightthickness=0)
        canv.pack(fill='both', expand=True)

        self.userNameButton = tk.Button(
            master,
            text=i18n.snakeUserNameRequest[i18n.lang()][0],
            command=_set_username)
        if self.userName:
            self.userNameButton['text'] = self.userName + ' ({0})'.format(
                i18n.snakeUserNameRequest[i18n.lang()][1])
        self.userNameButton.place(x=FULL_WIDTH, y=BOX_Y_MIN * 0.4, anchor='e')

        majorImgObj = Image.open(files.MAJOR_IMG_PATH)
        majorImgObj = majorImgObj.resize((MAJOR_SIZE, MAJOR_SIZE),
                                         Image.ANTIALIAS)
        canv.majorImg = ImageTk.PhotoImage(majorImgObj)

        foxImgObj = Image.open(files.FOX_ICO_PATH)
        foxImgObj = foxImgObj.resize((FOX_SIZE, FOX_SIZE), Image.ANTIALIAS)

        beerImgObj = Image.open(files.BEER_IMG_PATH)
        beerImgObj = beerImgObj.resize((BEER_SIZE, BEER_SIZE), Image.ANTIALIAS)

        starImgObj = Image.open(files.STAR_IMG_PATH)
        starImgObj = starImgObj.resize((STAR_SIZE, STAR_SIZE), Image.ANTIALIAS)

        bucketImgObj = Image.open(files.BUCKET_IMG_PATH)
        bucketImgObj = bucketImgObj.resize((BUCKET_SIZE, BUCKET_SIZE),
                                           Image.ANTIALIAS)

        floorImgObj = Image.open(files.FLOOR_IMG_PATH)
        floorImgObj = floorImgObj.resize(
            (BOX_X_MAX - BOX_X_MIN, BOX_Y_MAX - BOX_Y_MIN), Image.ANTIALIAS)
        canv.floorImg = ImageTk.PhotoImage(floorImgObj)

        canv.foxImg = {}
        canv.beerImg = {}
        canv.starImg = {}
        canv.bucketImg = {}

        canv.create_image((BOX_X_MAX + BOX_X_MIN) / 2,
                          (BOX_Y_MAX + BOX_Y_MIN) / 2,
                          image=canv.floorImg,
                          tags=('floor'))

        canv.create_line(0,
                         BOX_Y_MIN,
                         FULL_WIDTH,
                         BOX_Y_MIN,
                         fill='black',
                         tags=('top'),
                         width=10)
        canv.create_line(BOX_X_MIN,
                         BOX_Y_MIN,
                         BOX_X_MIN,
                         BOX_Y_MAX,
                         fill='black',
                         tags=('left'),
                         width=10)
        canv.create_line(BOX_X_MAX - 1,
                         BOX_Y_MIN,
                         BOX_X_MAX - 1,
                         BOX_Y_MAX,
                         fill='black',
                         tags=('middle'),
                         width=10)
        canv.create_line(FULL_WIDTH,
                         BOX_Y_MIN,
                         FULL_WIDTH,
                         BOX_Y_MAX,
                         fill='black',
                         tags=('right'),
                         width=10)
        canv.create_line(0,
                         BOX_Y_MAX - 2,
                         FULL_WIDTH,
                         BOX_Y_MAX - 2,
                         fill='black',
                         tags=('bottom'),
                         width=10)

        canv.create_text(FULL_WIDTH / 2,
                         BOX_Y_MIN * 0.4,
                         text=i18n.snakeWelcome[i18n.lang()],
                         tags=('welcomeText'),
                         font=("Times", 25, "bold"),
                         fill='orange')

        deltaY = self.boxHeight * 0.07
        instructionY = BOX_Y_MIN + self.boxHeight * 0.35
        canv.create_text(self.infoBoxXCenter,
                         instructionY,
                         text=i18n.snakeInstruction[i18n.lang()][0],
                         tags=('instructionText'))

        instructionY += deltaY
        canv.create_text(self.infoBoxXCenter,
                         instructionY,
                         text=i18n.snakeInstruction[i18n.lang()][1] + ':',
                         tags=('instructionText2'))

        instructionY += deltaY
        _draw_new_star(self.infoBoxXMin + self.infoBoxWidth * 0.30,
                       instructionY, "instrStar", 0.5)
        canv.create_text(self.infoBoxXMin + self.infoBoxWidth * 0.40,
                         instructionY,
                         text='=',
                         tags=('instructionEquals'))
        _draw_new_beer(self.infoBoxXMin + self.infoBoxWidth * 0.50,
                       instructionY, "instrBeer", 0.5)
        canv.create_text(self.infoBoxXMin + self.infoBoxWidth * 0.60,
                         instructionY,
                         text='X',
                         tags=('instructionTimes'))
        _draw_new_fox(self.infoBoxXMin + self.infoBoxWidth * 0.70,
                      instructionY, "instrFox", 0.5)

        instructionY += deltaY
        canv.create_text(self.infoBoxXCenter,
                         instructionY,
                         text=i18n.snakeInstruction[i18n.lang()][2],
                         tags=('instructionText3'))

        instructionY += deltaY
        canv.create_text(self.infoBoxXCenter,
                         instructionY,
                         text=i18n.snakeInstruction[i18n.lang()][3],
                         tags=('instructionText4'))

        canv.create_image(BOX_X_MIN + self.boxWidth * 0.5,
                          BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) / 2,
                          image=canv.majorImg,
                          tags=('major'))
        itemRegister.append('major')

        _draw_new_fox(FULL_WIDTH * 0.27, self.bottomRowY, 'scoreFox', 0.5)
        canv.create_text(FULL_WIDTH * 0.30,
                         self.bottomRowY,
                         text=': ' + str(self._nFoxes),
                         font='b',
                         tags=('foxText'))
        _draw_new_beer(FULL_WIDTH * 0.50, self.bottomRowY, 'scoreBeer', 0.5)
        canv.create_text(FULL_WIDTH * 0.55,
                         self.bottomRowY,
                         text=': ' + str(self._nBeers) + ' / ' +
                         str(MAX_BEER - 1),
                         font='b',
                         tags=('beerText'))
        _draw_new_star(FULL_WIDTH * 0.77, self.bottomRowY, 'scoreStar', 0.5)
        canv.create_text(FULL_WIDTH * 0.80,
                         self.bottomRowY,
                         text=': ' + str(self._nBeers),
                         font='b',
                         tags=('starText'))

        def move_fox_tail():
            for idx in range(self._nFoxes):
                thisFoxTag = 'tail' + str(idx)
                try:
                    canv.coords(thisFoxTag,
                                self._xPath[(idx + 1) * TAIL_STEP_DISTANCE],
                                self._yPath[(idx + 1) * TAIL_STEP_DISTANCE])
                except IndexError:
                    pass

        def move_free_fox():
            for idx in range(N_FREE_FOXES):
                name = 'fox' + str(idx)
                x, y = canv.coords(name)
                MAX_ALLOWED_ANGLE = 60
                while True:
                    yShift = (1 - 2 * random.random()) * MOVEMENT_STEP_SIZE
                    xShift = (1 - 2 * random.random()) * MOVEMENT_STEP_SIZE
                    angle = maths.get_angle(xShift, yShift,
                                            self._foxlastXvec[idx],
                                            self._foxlastYvec[idx])
                    if abs(angle) < MAX_ALLOWED_ANGLE:
                        break
                x, y = x + xShift, y + yShift
                if not check_clipping(
                        x, y, xSize=FOX_SIZE, ySize=FOX_SIZE, exclude=name):
                    self._foxlastXvec[idx] = xShift
                    self._foxlastYvec[idx] = yShift
                    canv.move(name, xShift, yShift)
                    keep_in_box(name)
                else:
                    self._foxlastXvec[idx] = -self._foxlastXvec[idx]
                    self._foxlastYvec[idx] = -self._foxlastYvec[idx]
                    canv.move(name, self._foxlastXvec[idx],
                              self._foxlastYvec[idx])
                    keep_in_box(name)
            self._job['move_free_fox'] = master.after(int(1 / START_SPEED),
                                                      move_free_fox)

        def get_new_tail_pos():
            newX, newY = canv.coords('major')
            try:
                newX = self._xPath[(self._nFoxes) * TAIL_STEP_DISTANCE]
                newY = self._yPath[(self._nFoxes) * TAIL_STEP_DISTANCE]
                return (newX, newY)
            except IndexError:
                try:
                    if self._nFoxes:
                        newX, newY = canv.coords('tail' +
                                                 str(self._nFoxes - 1))
                except ValueError:
                    pass
            return (newX, newY)

        def keep_in_box(item):
            itemX, itemY = canv.coords(item)
            if itemX < BOX_X_MIN:
                canv.coords(item, BOX_X_MAX, itemY)
            if itemX > BOX_X_MAX:
                canv.coords(item, BOX_X_MIN, itemY)
            if itemY < BOX_Y_MIN:
                canv.coords(item, itemX, BOX_Y_MAX)
            if itemY > BOX_Y_MAX:
                canv.coords(item, itemX, BOX_Y_MIN)

        def move():
            if self._direction is not None:
                canv.move('major', self._xVelTumble, self._yVelTumble)
                itemX, itemY = canv.coords('major')
                self._xPath.appendleft(itemX)
                self._yPath.appendleft(itemY)
                keep_in_box('major')
                move_fox_tail()
                beerList = list(map(lambda x: 'beer' + str(x), range(N_BEERS)))
                freeFoxList = list(
                    map(lambda x: 'fox' + str(x), range(N_FREE_FOXES)))
                # catch foxes
                foxCollision = check_clipping(itemX,
                                              itemY,
                                              include=freeFoxList)
                if foxCollision:
                    sound.play_sound(files.BLOP_WAV_PATH)
                    self._score += self._nBeers
                    self._nFoxes += 1
                    canv.itemconfig('foxText', text=': ' + str(self._nFoxes))
                    canv.itemconfig('starText', text=': ' + str(self._score))
                    newX, newY = get_new_tail_pos()
                    _draw_new_fox(newX=newX,
                                  newY=newY,
                                  name='tail' + str(self._nFoxes - 1))
                    for item in reversed(itemRegister):
                        canv.tag_raise(item)
                    _draw_new_fox(name=foxCollision)
                    foxIdx = int(foxCollision.lstrip('fox'))
                    self._foxlastXvec[foxIdx] = random.random()
                    self._foxlastYvec[foxIdx] = random.random()
                    if not any(i in itemRegister for i in beerList):
                        for beerName in beerList:
                            if random.random() < BEER_RESPAWN_CHANCE:
                                _draw_new_beer(name=beerName)
                # drink beer
                beerCollision = check_clipping(itemX, itemY, include=beerList)
                if beerCollision:
                    sound.play_sound(files.SLURP_WAV_PATH)
                    self._nBeers += 1
                    canv.itemconfig('beerText',
                                    text=': ' + str(self._nBeers) + ' / ' +
                                    str(MAX_BEER - 1))
                    canv.itemconfig('starText', text=': ' + str(self._score))
                    step = (MAX_SPEED - START_SPEED) / N_SPEED_STEPS
                    self._speed = min(self._speed + step, MAX_SPEED)
                    if self._nBeers == MAX_BEER:
                        self._rotationSpeed = START_ROTATION_SPEED
                    elif self._nBeers > MAX_BEER:
                        step = (MAX_ROTATION_SPEED -
                                START_ROTATION_SPEED) / N_ROTATION_SPEED_STEPS
                        self._rotationSpeed = min(self._rotationSpeed + step,
                                                  MAX_ROTATION_SPEED)
                        step = (MAX_TUMBLE_ANGLE -
                                START_TUMBLE_ANGLE) / N_TUMBLE_STEPS
                        self._tumbleAngle = min(self._tumbleAngle + step,
                                                MAX_TUMBLE_ANGLE)
                    if self._nBeers == MAX_BEER + 5:
                        _draw_new_bucket()
                    if random.random() < BEER_RESPAWN_CHANCE:
                        _draw_new_beer(name=beerCollision)
                    else:
                        delete_widget(beerCollision)
                # hit bucket
                if check_clipping(itemX, itemY, include='bucket'):
                    sound.play_sound(files.HICCUP_WAV_PATH)
                    self._nBeers = MAX_BEER - 1
                    canv.itemconfig('beerText',
                                    text=': ' + str(self._nBeers) + ' / ' +
                                    str(MAX_BEER - 1))
                    delete_widget('bucket')
                    self._currentRotation = 0
                    self._rotationSpeed = 0
                    self._tumbleAngle = START_TUMBLE_ANGLE
                # rotate major and its direction
                # print('speed', self._speed, 'rotationSpeed', self._rotationSpeed, 'tumbleDegree', self._tumbleAngle)
                self._currentRotation += self._rotationSpeed
                canv.majorImg = ImageTk.PhotoImage(
                    majorImgObj.rotate(self._tumbleAngle * 2 *
                                       math.sin(self._currentRotation)))
                canv.itemconfig('major', image=canv.majorImg)
                angle = maths.get_angle(1, 0, self._xVel, self._yVel)
                angle += self._tumbleAngle * math.sin(-self._currentRotation)
                angle = math.radians(angle)
                self._xVelTumble = MOVEMENT_STEP_SIZE * math.cos(angle)
                self._yVelTumble = MOVEMENT_STEP_SIZE * math.sin(angle)
                # check tail overlap
                noTailFoxes = [
                    item for item in itemRegister if 'tail' not in item
                ]
                noTailFoxes.extend(['tail' + str(idx) for idx in range(2)])
                crashFox = check_clipping(itemX,
                                          itemY,
                                          exclude=noTailFoxes,
                                          xSize=MAJOR_SIZE * 0.1,
                                          ySize=MAJOR_SIZE * 0.1)

                if crashFox:
                    sound.play_sound(files.BLAST_WAV_PATH)
                    print('Overlapping with tail', crashFox)
                    _end_game()
                    return
            self._job['move'] = master.after(int(1 / self._speed), move)

        def check_box_boundary(x, y, xSize=FOX_SIZE, ySize=FOX_SIZE):
            if x > BOX_X_MAX - xSize / 2 or \
               x < BOX_X_MIN + xSize / 2 or \
               y > BOX_Y_MAX - ySize / 2 or \
               y < BOX_Y_MIN + ySize / 2:
                return True

        def check_clipping(x,
                           y,
                           xSize=MAJOR_SIZE,
                           ySize=MAJOR_SIZE,
                           exclude=[],
                           include=[]):
            for item in itemRegister:
                if item in exclude:
                    continue
                if include and item not in include:
                    continue
                itemX, itemY = canv.coords(item)
                x0, y0, x1, y1 = canv.bbox(item)
                itemSizeX = x1 - x0
                itemSizeY = y1 - y0
                # print('New item x/y', round(x), '/', round(y), item, itemX, '/', itemY)
                PROXIMITY = 3
                isCloseX = abs(itemX -
                               x) < xSize / PROXIMITY + itemSizeX / PROXIMITY
                isCloseY = abs(itemY -
                               y) < xSize / PROXIMITY + itemSizeY / PROXIMITY
                if isCloseX and isCloseY:
                    return item
            return ''

        def get_new_random_pos(xSize, ySize):
            nTries = 0
            while True:
                newX = BOX_X_MAX * random.random()
                newY = BOX_Y_MAX * random.random()
                # print(nTries, 'Trying newX newY', newX, '/', newY)
                if nTries > MAX_POSITION_LOOPS:
                    return (None, None)
                else:
                    nTries += 1
                if check_box_boundary(newX, newY, xSize, ySize):
                    continue
                if check_clipping(newX, newY, xSize, ySize):
                    continue
                return (newX, newY)

        def post_score():
            if not self.userName:
                _set_username()
            if not self.userName:
                return
            web_client.post_score(username=self.userName, score=self._score)

        def display_highscore():
            canv.create_text(self.infoBoxXCenter,
                             BOX_Y_MIN + self.boxHeight * 0.5,
                             text=i18n.snakeHighScore[i18n.lang()][0] + '...',
                             font='b',
                             tags=('load_highscore'))
            scores = web_client.read_highscore()
            keys = None
            errText = None
            try:
                keys = sorted(scores[0].keys())
            except IndexError:
                errText = i18n.snakeWebErr[i18n.lang()][0]
            except TypeError:
                errText = i18n.snakeWebErr[i18n.lang()][1]
            delete_widget('load_highscore')
            hSpace = 10
            vSpace = 20
            subBoxXMin = self.infoBoxXMin + hSpace
            subBoxXMax = self.infoBoxXMax - hSpace

            topBoxYMin = BOX_Y_MIN + vSpace
            topBoxYMax = topBoxYMin + self.boxHeight * 0.4
            gui_utils.draw_table(master,
                                 canv,
                                 subBoxXMin,
                                 subBoxXMax,
                                 topBoxYMin,
                                 topBoxYMax,
                                 headers=keys,
                                 values=scores,
                                 nRows=N_HIGHSCORES + 1,
                                 title=i18n.snakeHighScore[i18n.lang()][2],
                                 tags='global_highscore',
                                 errText=errText)

            try:
                userScores = [
                    score for score in scores
                    if score['username'] == self.userName
                ]
            except TypeError:
                userScores = None
            lowBoxYMin = BOX_Y_MIN + self.boxHeight * 0.5 + vSpace * 0.5
            lowBoxYMax = lowBoxYMin + self.boxHeight * 0.4
            if not self.userName:
                errText = i18n.snakeWebErr[i18n.lang()][2]
            gui_utils.draw_table(master,
                                 canv,
                                 subBoxXMin,
                                 subBoxXMax,
                                 lowBoxYMin,
                                 lowBoxYMax,
                                 headers=keys,
                                 values=userScores,
                                 nRows=N_HIGHSCORES + 1,
                                 title=i18n.snakeHighScore[i18n.lang()][1],
                                 tags='personal_highscore',
                                 errText=errText)

        def _init_start(event):
            reset(self)
            _start(event)

        def _start(event):
            # delete_widget('welcomeText')
            delete_widget('instructionText')
            delete_widget('instructionText2')
            delete_widget('instructionText3')
            delete_widget('instructionText4')
            delete_widget('instrStar')
            delete_widget('instrBeer')
            delete_widget('instrFox')
            delete_widget('instructionEquals')
            delete_widget('instructionTimes')
            for idx in range(N_FREE_FOXES):
                _draw_new_fox(name='fox' + str(idx))
            for idx in range(N_BEERS):
                _draw_new_beer(name='beer' + str(idx))
            master.bind('<Up>', _change_direction)
            master.bind('<Down>', _change_direction)
            master.bind('<Right>', _change_direction)
            master.bind('<Left>', _change_direction)
            master.bind('w', _change_direction)
            master.bind('a', _change_direction)
            master.bind('s', _change_direction)
            master.bind('d', _change_direction)
            master.unbind('<Return>')
            move()
            move_free_fox()
            t1 = threading.Thread(target=display_highscore)
            t1.start()

        def _quit(self):
            time.sleep(0.1)
            master.quit()

        def _click_quit():
            _quit(self)

        def cancel():
            for job in self._job:
                master.after_cancel(self._job[job])
            self._job = {}

        def remove_items():
            # keepItems = ['scoreFox', 'scoreBeer', 'scoreStar']
            # for item in itemRegister:
            #     if item not in keepItems:
            #         canv.delete(item)
            pass

        def _end_game():
            cancel()
            remove_items()
            canv.create_text(BOX_X_MAX / 2,
                             BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.4,
                             fill='orange',
                             font=("Times", 25, "bold"),
                             text=i18n.gameOver[i18n.lang()][0],
                             tags=('gameOverText'))
            canv.create_text(BOX_X_MAX / 2,
                             BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.5,
                             fill='orange',
                             font=("Times", 25, "bold"),
                             text=i18n.gameOver[i18n.lang()][1],
                             tags=('gameOverCancelText'))
            canv.create_text(BOX_X_MAX / 2,
                             BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.6,
                             fill='orange',
                             font=("Times", 25, "bold"),
                             text=i18n.gameOver[i18n.lang()][2],
                             tags=('gameOverRestartText'))
            post_score()
            master.bind('<Return>', _restart)

        def _restart(event):
            reset(self)
            delete_widget('gameOverText')
            delete_widget('gameOverCancelText')
            delete_widget('gameOverRestartText')
            delete_widget('bucket')
            tailFoxes = [item for item in itemRegister if 'tail' in item]
            for item in tailFoxes:
                delete_widget(item)
            canv.itemconfig('foxText', text=': ' + str(self._nFoxes))
            canv.itemconfig('beerText',
                            text=': ' + str(self._nBeers) + ' / ' +
                            str(MAX_BEER - 1))
            canv.itemconfig('starText', text=': ' + str(self._score))
            canv.coords('major', BOX_X_MIN + self.boxWidth * 0.5,
                        BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) / 2)
            canv.majorImg = ImageTk.PhotoImage(majorImgObj.rotate(0))
            canv.itemconfig('major', image=canv.majorImg)
            for widgetID in canv.find_all():
                widget = canv.gettags(widgetID)[0]
                if 'global_highscore' in widget:
                    print('Deleting', widget)
                    delete_widget(widget)
                    if 'personal_highscore' in widget:
                        print('Deleting', widget)
                        delete_widget(widget)
            _start(event)

        def _change_direction(event):
            if event.keysym == 'w':
                event.keysym = 'Up'
            if event.keysym == 'a':
                event.keysym = 'Left'
            if event.keysym == 's':
                event.keysym = 'Down'
            if event.keysym == 'd':
                event.keysym = 'Right'
            if not self._nFoxes:
                self._direction = 'measingless'
            if event.keysym == 'Up' and self._direction != 'Down':
                self._yVel = -MOVEMENT_STEP_SIZE
                self._xVel = 0
                self._direction = event.keysym
            if event.keysym == 'Down' and self._direction != 'Up':
                self._yVel = MOVEMENT_STEP_SIZE
                self._xVel = 0
                self._direction = event.keysym
            if event.keysym == 'Right' and self._direction != 'Left':
                self._yVel = 0
                self._xVel = MOVEMENT_STEP_SIZE
                self._direction = event.keysym
            if event.keysym == 'Left' and self._direction != 'Right':
                self._yVel = 0
                self._xVel = -MOVEMENT_STEP_SIZE
                self._direction = event.keysym

        master.protocol("WM_DELETE_WINDOW", _click_quit)
        master.bind('<Up>', _init_start)
        master.bind('<Down>', _init_start)
        master.bind('<Right>', _init_start)
        master.bind('<Left>', _init_start)
        master.bind('w', _init_start)
        master.bind('a', _init_start)
        master.bind('s', _init_start)
        master.bind('d', _init_start)
        master.bind('<Escape>', _quit)
        master.bind('<Return>', _init_start)
コード例 #23
0
sound.start_sound()
taskVar = 0
zipPasswd = ''
questionFile = ''
categoryUpdate = {}
foxIco = files.resource_path('', r'images\fox.ico')


while True:

    lang_button_png = i18n.lang_button_image()
    sound_buttong_png = sound.sound_button_image()

    categories = [
                  [16, i18n.longNames[i18n.lang()][0], i18n.shortNames[i18n.lang()][0]],
                  [6, i18n.longNames[i18n.lang()][1], i18n.shortNames[i18n.lang()][1]],
                  [4, i18n.longNames[i18n.lang()][2], i18n.shortNames[i18n.lang()][2]],
                  [1000, i18n.longNames[i18n.lang()][3], i18n.shortNames[i18n.lang()][3]],
                  [5, i18n.longNames[i18n.lang()][4], i18n.shortNames[i18n.lang()][4]],
                  [0, i18n.longNames[i18n.lang()][5], i18n.shortNames[i18n.lang()][5]],
                 ]
    change_catagories(categories, categoryUpdate)
    category_numbers = map(lambda x: x[0], categories)
    mainroot = tk.Tk()
    mainroot.iconbitmap(foxIco)
    mainroot.title('F*x!')
    mainapp = gui.InitWindow(mainroot, category_numbers, taskVar)
    mainroot.focus_force()
    mainroot.mainloop()
    taskVar = mainapp.radio_var.get()
コード例 #24
0
    def __init__(self, master, categories, radioinit=0):

        center_window(master)

        master.protocol("WM_DELETE_WINDOW", sys.exit)

        self.inputDict = {}
        self.radio_var = tk.IntVar()
        self.radio_var.set(radioinit)

        _row_count = 0

        _head_label = tk.Label(master,
                               text=i18n.appHeader[i18n.lang()],
                               font=("Helvetica", 16))
        _head_label.grid(row=_row_count, columnspan=4)
        _row_count += 1

        _photo = tk.PhotoImage(file=foxPng)
        _photo = _photo.subsample(5, 5)
        _photo_label = tk.Label(master, image=_photo)
        _photo_label.photo = _photo
        _photo_label.grid(row=_row_count, columnspan=4)
        _row_count += 1

        _col_idx = 0
        _row_count += 2
        _cat_label = []
        for idx, default in enumerate(categories):
            longName = i18n.longNames[i18n.lang()][idx]
            shortName = i18n.shortNames[i18n.lang()][idx]
            if shortName == 'P' or shortName == 'A':
                _cat_label.append(None)
                continue
            _cat_label.append(tk.Label(master, text=longName))
            _cat_label[-1].grid(row=_row_count - 2,
                                column=_col_idx,
                                columnspan=2)
            string_val = tk.StringVar()
            string_val.set(default)
            cat_entry = tk.Entry(master, textvariable=string_val, width=5)
            cat_entry.grid(row=_row_count - 1, column=_col_idx, columnspan=2)
            self.inputDict[shortName] = string_val
            _col_idx = (_col_idx + 2) % 4
            if (_col_idx == 0):
                _row_count += 2

        _radioButton = []
        for idx, task in enumerate(i18n.dictInit[i18n.lang()]):
            _radioButton.append(
                tk.Radiobutton(master,
                               text=task,
                               variable=self.radio_var,
                               value=idx))
            _radioButton[idx].grid(row=_row_count, column=0, columnspan=4)
            _row_count += 1

        _start_button = tk.Button(master,
                                  text=i18n.startButtonText[i18n.lang()][0],
                                  fg="green",
                                  font="bold",
                                  command=master.quit)
        _start_button.grid(row=_row_count, column=0, columnspan=2)
        _quit_button = tk.Button(master,
                                 text=i18n.startButtonText[i18n.lang()][1],
                                 fg="red",
                                 font="bold",
                                 command=sys.exit)
        _quit_button.grid(row=_row_count, column=2, columnspan=2)
        _row_count += 1

        def set_switch_language():
            i18n.switch_language()
            set_image(_lang_button, i18n.lang_button_image(), 1, 20)
            set_text(_head_label, i18n.appHeader[i18n.lang()])
            for idx, rad in enumerate(_radioButton):
                set_text(rad, i18n.dictInit[i18n.lang()][idx])
            for idx, cat in enumerate(_cat_label):
                if cat is None:
                    continue
                set_text(cat, i18n.longNames[i18n.lang()][idx])
            set_text(_start_button, i18n.startButtonText[i18n.lang()][0])
            set_text(_quit_button, i18n.startButtonText[i18n.lang()][1])
            set_text(_link_label, i18n.linkLabelText[i18n.lang()])

        _lang_button = tk.Button(master,
                                 command=combine_funcs(set_switch_language))
        set_image(_lang_button, i18n.lang_button_image(), 1, 20)
        _lang_button.grid(row=_row_count, column=0)

        _github_button = tk.Button(master)
        set_image(_github_button, github_button_png, 5, 20)
        _github_button.bind("<Button-1>", callback_GitHub)
        _github_button.grid(row=_row_count, column=3)

        def set_toggle_sound():
            sound.toggle_sound()
            set_image(_sound_button, sound.sound_button_image(), 4, 20)

        _sound_button = tk.Button(master,
                                  command=combine_funcs(set_toggle_sound))
        set_image(_sound_button, sound.sound_button_image(), 4, 20)
        _sound_button.grid(row=_row_count, column=1)

        _link_label = tk.Label(master,
                               text=i18n.linkLabelText[i18n.lang()],
                               fg="blue",
                               cursor="hand2")
        _link_label.grid(row=_row_count, column=2)
        _link_label.bind("<Button-1>", callback_AGV)

        thisradio = self.radio_var

        def _toggleup(self):
            old = thisradio.get()
            new = max(old - 1, 0)
            thisradio.set(new)

        def _toggledown(self):
            old = thisradio.get()
            new = min(old + 1, len(i18n.dictInit[i18n.lang()]) - 1)
            thisradio.set(new)

        def _quit(self):
            master.quit()

        def _mute(self):
            set_toggle_sound()

        def _lang(self):
            set_switch_language()

        master.bind('<Escape>', sys.exit)
        master.bind('<Up>', _toggleup)
        master.bind('<Down>', _toggledown)
        master.bind('<Return>', _quit)
        master.bind('m', _mute)
        master.bind('l', _lang)
コード例 #25
0
    def __init__(self, master, questionList):

        self.quit = tk.IntVar()
        self.quit.set(0)
        thisQuit = self.quit

        self.success = tk.IntVar()
        self.success.set(0)
        thisSuccess = self.success

        self.failure = tk.IntVar()
        self.failure.set(0)
        thisFailure = self.failure

        self.skip = tk.IntVar()
        self.skip.set(0)
        thisSkip = self.skip

        self.currentQuestion = tk.IntVar()
        self.currentQuestion.set(0)
        thisCurrentQuestion = self.currentQuestion

        center_window(master)

        self.one_msg = []
        self._row_count = 0

        def _success():
            augment(thisSuccess)
            _new_question()

        def _failure():
            augment(thisFailure)
            _new_question()

        def _skip():
            augment(thisSkip)
            _new_question()

        def _quit():
            augment(thisQuit)
            master.quit()

        self._success_button = tk.Button(master,
                                         text=i18n.quizButton[i18n.lang()][0] +
                                         ' [k]',
                                         command=_success,
                                         width=15,
                                         font="bold")
        self._failure_button = tk.Button(master,
                                         text=i18n.quizButton[i18n.lang()][1] +
                                         ' [d]',
                                         command=_failure,
                                         width=15,
                                         font="bold")
        self._skip_button = tk.Button(master,
                                      text=i18n.quizButton[i18n.lang()][2] +
                                      ' [s]',
                                      command=_skip,
                                      width=15,
                                      font="bold")
        self._quit_button = tk.Button(master,
                                      text=i18n.quizButton[i18n.lang()][3] +
                                      ' [esc]',
                                      command=_quit,
                                      width=15,
                                      fg="red",
                                      font="bold")

        def print_question(one_msg):
            self._row_count = 0
            splitlist = questionList[self.currentQuestion.get()].split('\\\\')
            for idx, item in enumerate(splitlist):
                if idx > 0:
                    item = str(idx) + '. ' + item
                self.one_msg.append(tk.Message(master, text=item, width=575))
                self.one_msg[idx].grid(row=self._row_count,
                                       column=0,
                                       columnspan=4)
                self._row_count += 1
            self._failure_button.grid(row=self._row_count, column=1)
            self._success_button.grid(row=self._row_count, column=0)
            self._skip_button.grid(row=self._row_count, column=2)
            self._quit_button.grid(row=self._row_count, column=3)

        def remove_question(one_msg):
            while one_msg:
                msg = one_msg.pop()
                msg.grid_forget()

        print_question(self.one_msg)

        def _new_question():
            augment(thisCurrentQuestion)
            remove_question(self.one_msg)
            try:
                print_question(self.one_msg)
            except IndexError:
                master.quit()

        self._failure_button.grid(row=self._row_count, column=1)
        self._success_button.grid(row=self._row_count, column=0)
        self._skip_button.grid(row=self._row_count, column=2)
        self._quit_button.grid(row=self._row_count, column=3)

        def _success_bind(self):
            _success()

        def _failure_bind(self):
            _failure()

        def _skip_bind(self):
            _skip()

        def _quit_bind(self):
            _quit()

        master.protocol("WM_DELETE_WINDOW", _quit)
        master.bind('k', _success_bind)
        master.bind('d', _failure_bind)
        master.bind('s', _skip_bind)
        master.bind('<Escape>', _quit_bind)
コード例 #26
0
            idx = list(map(lambda a: a[2], category)).index(key)
        except ValueError:
            continue
        category[idx][0] = categoryUpdate[key]
    return category


sound.start_sound()
taskVar = 0
zipPasswd = ''
questionFile = ''
categoryUpdate = {}

while True:
    categories = [
        [16, i18n.longNames[i18n.lang()][0], i18n.shortNames[i18n.lang()][0]],
        [6, i18n.longNames[i18n.lang()][1], i18n.shortNames[i18n.lang()][1]],
        [4, i18n.longNames[i18n.lang()][2], i18n.shortNames[i18n.lang()][2]],
        [
            1000, i18n.longNames[i18n.lang()][3],
            i18n.shortNames[i18n.lang()][3]
        ],
        [5, i18n.longNames[i18n.lang()][4], i18n.shortNames[i18n.lang()][4]],
        [0, i18n.longNames[i18n.lang()][5], i18n.shortNames[i18n.lang()][5]],
    ]
    change_catagories(categories, categoryUpdate)
    category_numbers = map(lambda x: x[0], categories)
    mainroot = tk.Tk()
    if sys.platform == 'win32':
        mainroot.iconbitmap(files.FOX_ICO_PATH)
    mainroot.title('F*x!')
コード例 #27
0
 def _toggledown(self):
     old = thisradio.get()
     new = min(old + 1, len(i18n.dictInit[i18n.lang()]) - 1)
     thisradio.set(new)
コード例 #28
0
ファイル: snake.py プロジェクト: Vorathel/Fuxenpruefung
    def __init__(self, master):
        gui.center_window(master)

        master.geometry('%sx%s+%s+%s' % (FULL_WIDTH, FULL_HEIGHT, 100, 100))
        master.resizable(0, 0)

        itemRegister = []

        def reset(self):
            self._xPath = deque([], MAX_QUEUE_LEN)
            self._yPath = deque([], MAX_QUEUE_LEN)
            self._xVel = 0
            self._yVel = 0
            self._xVelTumble = 0
            self._yVelTumble = 0
            self._direction = None
            self._score = 0
            self._nFoxes = 0
            self._nBeers = 0
            self._speed = START_SPEED
            self._job = {}
            self._rotationSpeed = 0
            self._currentRotation = 0
            self._tumbleAngle = START_TUMBLE_ANGLE
            self._foxlastXvec = random.random()
            self._foxlastYvec = random.random()

        def delete_widget(name):
            canv.delete(name)
            try:
                itemRegister.remove(name)
            except ValueError:
                pass

        def _draw_new_fox(newX=None, newY=None, name='fox', size=1):
            if not newX and not newY:
                newX, newY = get_new_random_pos(FOX_SIZE, FOX_SIZE)
                if not newX and not newY:
                    print('Warning: no new free fox position found!')
                    _end_game()
            delete_widget(name)
            thisFoxImgObj = foxImgObj.resize(
                (int(FOX_SIZE * size), int(FOX_SIZE * size)), Image.ANTIALIAS)
            canv.foxImg[name] = ImageTk.PhotoImage(thisFoxImgObj)
            canv.create_image(newX, newY, image=canv.foxImg[name], tags=(name))
            if name not in itemRegister:
                itemRegister.append(name)

        def _draw_new_beer(newX=None, newY=None, name='beer', size=1):
            if not newX and not newY:
                newX, newY = get_new_random_pos(BEER_SIZE, BEER_SIZE)
                if not newX and not newY:
                    print('Warning: no new free beer position found!')
                    _end_game()
            delete_widget(name)
            thisBeerImgObj = beerImgObj.resize(
                (int(BEER_SIZE * size), int(BEER_SIZE * size)),
                Image.ANTIALIAS)
            canv.beerImg[name] = ImageTk.PhotoImage(thisBeerImgObj)
            canv.create_image(newX,
                              newY,
                              image=canv.beerImg[name],
                              tags=(name))
            if name not in itemRegister:
                itemRegister.append(name)

        def _draw_new_bucket(newX=None, newY=None, name='bucket', size=1):
            if not newX and not newY:
                newX, newY = get_new_random_pos(BUCKET_SIZE, BUCKET_SIZE)
                if not newX and not newY:
                    print('Warning: no new free bucket position found!')
                    _end_game()
            delete_widget(name)
            thisBucketImgObj = bucketImgObj.resize(
                (int(BUCKET_SIZE * size), int(BEER_SIZE * size)),
                Image.ANTIALIAS)
            canv.bucketImg[name] = ImageTk.PhotoImage(thisBucketImgObj)
            canv.create_image(newX,
                              newY,
                              image=canv.bucketImg[name],
                              tags=(name))
            if name not in itemRegister:
                itemRegister.append(name)

        def _draw_new_star(newX=None, newY=None, name='star', size=1):
            if not newX and not newY:
                newX, newY = get_new_random_pos(STAR_SIZE, STAR_SIZE)
                if not newX and not newY:
                    print('Warning: no new free star position found!')
                    _end_game()
            delete_widget(name)
            thisStarImgObj = starImgObj.resize(
                (int(FOX_SIZE * size), int(FOX_SIZE * size)), Image.ANTIALIAS)
            canv.starImg[name] = ImageTk.PhotoImage(thisStarImgObj)
            canv.create_image(newX,
                              newY,
                              image=canv.starImg[name],
                              tags=(name))
            if name not in itemRegister:
                itemRegister.append(name)

        canv = tk.Canvas(master, highlightthickness=0)
        canv.pack(fill='both', expand=True)

        majorImgObj = Image.open(majorImgPath)
        majorImgObj = majorImgObj.resize((MAJOR_SIZE, MAJOR_SIZE),
                                         Image.ANTIALIAS)
        canv.majorImg = ImageTk.PhotoImage(majorImgObj)

        foxImgObj = Image.open(foxImgPath)
        foxImgObj = foxImgObj.resize((FOX_SIZE, FOX_SIZE), Image.ANTIALIAS)

        beerImgObj = Image.open(beerImgPath)
        beerImgObj = beerImgObj.resize((BEER_SIZE, BEER_SIZE), Image.ANTIALIAS)

        starImgObj = Image.open(starImgPath)
        starImgObj = starImgObj.resize((STAR_SIZE, STAR_SIZE), Image.ANTIALIAS)

        bucketImgObj = Image.open(bucketImgPath)
        bucketImgObj = bucketImgObj.resize((BUCKET_SIZE, BUCKET_SIZE),
                                           Image.ANTIALIAS)

        floorImgObj = Image.open(floorImgPath)
        floorImgObj = floorImgObj.resize(
            (BOX_X_MAX - BOX_X_MIN, BOX_Y_MAX - BOX_Y_MIN), Image.ANTIALIAS)
        canv.floorImg = ImageTk.PhotoImage(floorImgObj)

        canv.foxImg = {}
        canv.beerImg = {}
        canv.starImg = {}
        canv.bucketImg = {}

        canv.create_image((BOX_X_MAX + BOX_X_MIN) / 2,
                          (BOX_Y_MAX + BOX_Y_MIN) / 2,
                          image=canv.floorImg,
                          tags=('floor'))

        canv.create_line(BOX_X_MIN,
                         BOX_Y_MIN,
                         BOX_X_MAX,
                         BOX_Y_MIN,
                         fill='black',
                         tags=('top'),
                         width=10)
        canv.create_line(BOX_X_MIN,
                         BOX_Y_MIN,
                         BOX_X_MIN,
                         BOX_Y_MAX,
                         fill='black',
                         tags=('left'),
                         width=10)
        canv.create_line(BOX_X_MAX - 1,
                         BOX_Y_MIN,
                         BOX_X_MAX - 1,
                         BOX_Y_MAX,
                         fill='black',
                         tags=('right'),
                         width=10)
        canv.create_line(BOX_X_MIN,
                         BOX_Y_MAX - 2,
                         BOX_X_MAX,
                         BOX_Y_MAX - 2,
                         fill='black',
                         tags=('bottom'),
                         width=10)

        canv.create_text(FULL_WIDTH / 2,
                         BOX_Y_MIN * 0.4,
                         text=i18n.snakeWelcome[i18n.lang()],
                         tags=('welcomeText'),
                         font='b',
                         fill='orange')
        canv.create_text(BOX_X_MAX / 2,
                         BOX_Y_MAX * 2 / 8,
                         text=i18n.snakeInstruction[i18n.lang()][0],
                         tags=('instructionText'))
        canv.create_text(FULL_WIDTH / 2,
                         BOX_Y_MAX * 6 / 8,
                         text=i18n.snakeInstruction[i18n.lang()][1],
                         tags=('instructionText2'))

        _draw_new_star(FULL_WIDTH * 0.30, BOX_Y_MAX * 0.9, "instrStar", 0.5)
        canv.create_text(FULL_WIDTH * 0.40,
                         BOX_Y_MAX * 0.9,
                         text='=',
                         tags=('instructionEquals'))
        _draw_new_beer(FULL_WIDTH * 0.50, BOX_Y_MAX * 0.9, "instrBeer", 0.5)
        canv.create_text(FULL_WIDTH * 0.60,
                         BOX_Y_MAX * 0.9,
                         text='X',
                         tags=('instructionTimes'))
        _draw_new_fox(FULL_WIDTH * 0.70, BOX_Y_MAX * 0.9, "instrFox", 0.5)

        canv.create_image(FULL_WIDTH / 2,
                          BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) / 2,
                          image=canv.majorImg,
                          tags=('major'))
        itemRegister.append('major')

        def move_fox_tail():
            for idx in range(self._nFoxes):
                thisFoxTag = 'tail' + str(idx)
                try:
                    canv.coords(thisFoxTag,
                                self._xPath[(idx + 1) * TAIL_STEP_DISTANCE],
                                self._yPath[(idx + 1) * TAIL_STEP_DISTANCE])
                except IndexError:
                    pass

        def move_free_fox():
            x, y = canv.coords('fox')
            MAX_ALLOWED_ANGLE = 60
            while True:
                yShift = (1 - 2 * random.random()) * MOVEMENT_STEP_SIZE
                xShift = (1 - 2 * random.random()) * MOVEMENT_STEP_SIZE
                angle = get_angle(xShift, yShift, self._foxlastXvec,
                                  self._foxlastYvec)
                if abs(angle) < MAX_ALLOWED_ANGLE:
                    break
            x, y = x + xShift, y + yShift
            if not check_clipping(
                    x, y, xSize=FOX_SIZE, ySize=FOX_SIZE, exclude='fox'):
                self._foxlastXvec = xShift
                self._foxlastYvec = yShift
                canv.move('fox', xShift, yShift)
                keep_in_box('fox')
            else:
                self._foxlastXvec = -self._foxlastXvec
                self._foxlastYvec = -self._foxlastYvec
            self._job['move_free_fox'] = master.after(int(1 / START_SPEED),
                                                      move_free_fox)

        def get_new_tail_pos():
            newX, newY = canv.coords('major')
            try:
                newX = self._xPath[(self._nFoxes) * TAIL_STEP_DISTANCE]
                newY = self._yPath[(self._nFoxes) * TAIL_STEP_DISTANCE]
                return (newX, newY)
            except IndexError:
                try:
                    if self._nFoxes:
                        newX, newY = canv.coords('tail' +
                                                 str(self._nFoxes - 1))
                except ValueError:
                    pass
            return (newX, newY)

        def keep_in_box(item):
            itemX, itemY = canv.coords(item)
            if itemX < BOX_X_MIN:
                canv.coords(item, BOX_X_MAX, itemY)
            if itemX > BOX_X_MAX:
                canv.coords(item, BOX_X_MIN, itemY)
            if itemY < BOX_Y_MIN:
                canv.coords(item, itemX, BOX_Y_MAX)
            if itemY > BOX_Y_MAX:
                canv.coords(item, itemX, BOX_Y_MIN)

        def move():
            if self._direction is not None:
                canv.move('major', self._xVelTumble, self._yVelTumble)
                itemX, itemY = canv.coords('major')
                self._xPath.appendleft(itemX)
                self._yPath.appendleft(itemY)
                keep_in_box('major')
                move_fox_tail()
                # catch foxes
                if check_clipping(itemX, itemY, include='fox'):
                    self._score += self._nBeers
                    self._nFoxes += 1
                    canv.itemconfig('foxText', text=': ' + str(self._nFoxes))
                    canv.itemconfig('starText', text=': ' + str(self._score))
                    newX, newY = get_new_tail_pos()
                    _draw_new_fox(newX=newX,
                                  newY=newY,
                                  name='tail' + str(self._nFoxes - 1))
                    for item in reversed(itemRegister):
                        canv.tag_raise(item)
                    _draw_new_fox()
                    self._foxlastXvec = random.random()
                    self._foxlastYvec = random.random()
                    if 'beer' not in itemRegister:
                        _draw_new_beer()
                # drink beer
                if check_clipping(itemX, itemY, include='beer'):
                    self._nBeers += 1
                    canv.itemconfig('beerText',
                                    text=': ' + str(self._nBeers) + ' / ' +
                                    str(MAX_BEER - 1))
                    canv.itemconfig('starText', text=': ' + str(self._score))
                    step = (MAX_SPEED - START_SPEED) / N_SPEED_STEPS
                    self._speed = min(self._speed + step, MAX_SPEED)
                    if self._nBeers == MAX_BEER - 1:
                        canv.itemconfig(
                            'eventInfoText',
                            text=i18n.snakeEventInfo[i18n.lang()][1])
                    elif self._nBeers == MAX_BEER:
                        self._rotationSpeed = START_ROTATION_SPEED
                        canv.itemconfig(
                            'eventInfoText',
                            text=i18n.snakeEventInfo[i18n.lang()][2])
                    elif self._nBeers > MAX_BEER:
                        step = (MAX_ROTATION_SPEED -
                                START_ROTATION_SPEED) / N_ROTATION_SPEED_STEPS
                        self._rotationSpeed = min(self._rotationSpeed + step,
                                                  MAX_ROTATION_SPEED)
                        step = (MAX_TUMBLE_ANGLE -
                                START_TUMBLE_ANGLE) / N_TUMBLE_STEPS
                        self._tumbleAngle = min(self._tumbleAngle + step,
                                                MAX_TUMBLE_ANGLE)
                    if self._nBeers == MAX_BEER + 5:
                        _draw_new_bucket()
                        canv.itemconfig(
                            'eventInfoText',
                            text=i18n.snakeEventInfo[i18n.lang()][4])
                    if random.random() < BEER_RESPAWN_CHANCE:
                        _draw_new_beer()
                    else:
                        delete_widget('beer')
                # hit bucket
                if check_clipping(itemX, itemY, include='bucket'):
                    self._nBeers = MAX_BEER - 1
                    canv.itemconfig('beerText',
                                    text=': ' + str(self._nBeers) + ' / ' +
                                    str(MAX_BEER - 1))
                    delete_widget('bucket')
                    self._currentRotation = 0
                    self._rotationSpeed = 0
                    self._tumbleAngle = START_TUMBLE_ANGLE
                # rotate major and its direction
                # print('speed', self._speed, 'rotationSpeed', self._rotationSpeed, 'tumbleDegree', self._tumbleAngle)
                self._currentRotation += self._rotationSpeed
                canv.majorImg = ImageTk.PhotoImage(
                    majorImgObj.rotate(self._tumbleAngle * 2 *
                                       math.sin(self._currentRotation)))
                canv.itemconfig('major', image=canv.majorImg)
                angle = get_angle(1, 0, self._xVel, self._yVel)
                angle += self._tumbleAngle * math.sin(-self._currentRotation)
                angle = math.radians(angle)
                self._xVelTumble = MOVEMENT_STEP_SIZE * math.cos(angle)
                self._yVelTumble = MOVEMENT_STEP_SIZE * math.sin(angle)
                # check tail overlap
                noTailFoxes = [
                    item for item in itemRegister if 'tail' not in item
                ]
                noTailFoxes.extend(['tail' + str(idx) for idx in range(2)])
                crashFox = check_clipping(itemX,
                                          itemY,
                                          exclude=noTailFoxes,
                                          xSize=MAJOR_SIZE * 0.1,
                                          ySize=MAJOR_SIZE * 0.1)

                if crashFox:
                    print('Overlapping with tail', crashFox)
                    _end_game()
                    return
            self._job['move'] = master.after(int(1 / self._speed), move)

        def check_box_boundary(x, y, xSize=FOX_SIZE, ySize=FOX_SIZE):
            if x > BOX_X_MAX - xSize / 2 or \
               x < BOX_X_MIN + xSize / 2 or \
               y > BOX_Y_MAX - ySize / 2 or \
               y < BOX_Y_MIN + ySize / 2:
                return True

        def check_clipping(x,
                           y,
                           xSize=MAJOR_SIZE,
                           ySize=MAJOR_SIZE,
                           exclude=[],
                           include=[]):
            for item in itemRegister:
                if item in exclude:
                    continue
                if include and item not in include:
                    continue
                itemX, itemY = canv.coords(item)
                x0, y0, x1, y1 = canv.bbox(item)
                itemSizeX = x1 - x0
                itemSizeY = y1 - y0
                # print('New item x/y', round(x), '/', round(y), item, itemX, '/', itemY)
                PROXIMITY = 3
                isCloseX = abs(itemX -
                               x) < xSize / PROXIMITY + itemSizeX / PROXIMITY
                isCloseY = abs(itemY -
                               y) < xSize / PROXIMITY + itemSizeY / PROXIMITY
                if isCloseX and isCloseY:
                    return item
            return ''

        def get_new_random_pos(xSize, ySize):
            nTries = 0
            while True:
                newX = BOX_X_MAX * random.random()
                newY = BOX_Y_MAX * random.random()
                # print(nTries, 'Trying newX newY', newX, '/', newY)
                if nTries > MAX_POSITION_LOOPS:
                    return (None, None)
                else:
                    nTries += 1
                if check_box_boundary(newX, newY, xSize, ySize):
                    continue
                if check_clipping(newX, newY, xSize, ySize):
                    continue
                return (newX, newY)

        def _init_start(event):
            reset(self)
            _draw_new_fox(BOX_X_MAX * 0.15, BOX_Y_MIN * 0.4, 'scoreFox', 0.5)
            canv.create_text(BOX_X_MAX * 0.25,
                             BOX_Y_MIN * 0.4,
                             text=':' + str(self._nFoxes),
                             font='b',
                             tags=('foxText'))
            _draw_new_beer(BOX_X_MAX * 0.45, BOX_Y_MIN * 0.4, 'scoreBeer', 0.5)
            canv.create_text(BOX_X_MAX * 0.55,
                             BOX_Y_MIN * 0.4,
                             text=':' + str(self._nBeers) + ' / ' +
                             str(MAX_BEER - 1),
                             font='b',
                             tags=('beerText'))
            _draw_new_star(BOX_X_MAX * 0.75, BOX_Y_MIN * 0.4, 'scoreStar', 0.5)
            canv.create_text(BOX_X_MAX * 0.85,
                             BOX_Y_MIN * 0.4,
                             text=':' + str(self._nBeers),
                             font='b',
                             tags=('starText'))
            canv.create_text(BOX_X_MAX / 2,
                             BOX_Y_MIN * 0.73,
                             fill='red',
                             text=i18n.snakeEventInfo[i18n.lang()][0],
                             tags=('eventInfoText'))
            _start(event)

        def _start(event):
            delete_widget('welcomeText')
            delete_widget('instructionText')
            delete_widget('instructionText2')
            delete_widget('instrStar')
            delete_widget('instrBeer')
            delete_widget('instrFox')
            delete_widget('instructionEquals')
            delete_widget('instructionTimes')
            _draw_new_fox()
            _draw_new_beer()
            master.bind('<Up>', _change_direction)
            master.bind('<Down>', _change_direction)
            master.bind('<Right>', _change_direction)
            master.bind('<Left>', _change_direction)
            master.bind('w', _change_direction)
            master.bind('a', _change_direction)
            master.bind('s', _change_direction)
            master.bind('d', _change_direction)
            master.unbind('<Return>')
            move()
            move_free_fox()

        def _quit(self):
            time.sleep(0.1)
            master.quit()

        def _click_quit():
            _quit(self)

        def cancel():
            for job in self._job:
                master.after_cancel(self._job[job])
            self._job = {}

        def remove_items():
            # keepItems = ['scoreFox', 'scoreBeer', 'scoreStar']
            # for item in itemRegister:
            #     if item not in keepItems:
            #         canv.delete(item)
            pass

        def _end_game():
            cancel()
            remove_items()
            canv.itemconfig('eventInfoText', text='R.I.P.')
            canv.create_text(BOX_X_MAX / 2,
                             BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.5,
                             fill='red',
                             font='b',
                             text=i18n.gameOver[i18n.lang()][0],
                             tags=('gameOverText'))
            canv.create_text(BOX_X_MAX / 2,
                             BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.6,
                             fill='red',
                             text=i18n.gameOver[i18n.lang()][1],
                             tags=('gameOverCancelText'))
            canv.create_text(BOX_X_MAX / 2,
                             BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.7,
                             fill='red',
                             text=i18n.gameOver[i18n.lang()][2],
                             tags=('gameOverRestartText'))
            master.bind('<Return>', _restart)

        def _restart(event):
            reset(self)
            delete_widget('gameOverText')
            delete_widget('gameOverCancelText')
            delete_widget('gameOverRestartText')
            delete_widget('bucket')
            tailFoxes = [item for item in itemRegister if 'tail' in item]
            for item in tailFoxes:
                delete_widget(item)
            canv.itemconfig('foxText', text=': ' + str(self._nFoxes))
            canv.itemconfig('beerText',
                            text=': ' + str(self._nBeers) + ' / ' +
                            str(MAX_BEER - 1))
            canv.itemconfig('starText', text=': ' + str(self._score))
            canv.itemconfig('eventInfoText',
                            text=i18n.snakeEventInfo[i18n.lang()][0])
            canv.coords('major', FULL_WIDTH / 2,
                        BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) / 2)
            canv.majorImg = ImageTk.PhotoImage(majorImgObj.rotate(0))
            canv.itemconfig('major', image=canv.majorImg)
            _start(event)

        def _change_direction(event):
            if event.keysym == 'w':
                event.keysym = 'Up'
            if event.keysym == 'a':
                event.keysym = 'Left'
            if event.keysym == 's':
                event.keysym = 'Down'
            if event.keysym == 'd':
                event.keysym = 'Right'
            if not self._direction:
                canv.itemconfig('eventInfoText',
                                text=i18n.snakeEventInfo[i18n.lang()][3])
            if not self._nFoxes:
                self._direction = 'measingless'
            if event.keysym == 'Up' and self._direction != 'Down':
                self._yVel = -MOVEMENT_STEP_SIZE
                self._xVel = 0
                self._direction = event.keysym
            if event.keysym == 'Down' and self._direction != 'Up':
                self._yVel = MOVEMENT_STEP_SIZE
                self._xVel = 0
                self._direction = event.keysym
            if event.keysym == 'Right' and self._direction != 'Left':
                self._yVel = 0
                self._xVel = MOVEMENT_STEP_SIZE
                self._direction = event.keysym
            if event.keysym == 'Left' and self._direction != 'Right':
                self._yVel = 0
                self._xVel = -MOVEMENT_STEP_SIZE
                self._direction = event.keysym

        master.protocol("WM_DELETE_WINDOW", _click_quit)
        master.bind('<Up>', _init_start)
        master.bind('<Down>', _init_start)
        master.bind('<Right>', _init_start)
        master.bind('<Left>', _init_start)
        master.bind('w', _init_start)
        master.bind('a', _init_start)
        master.bind('s', _init_start)
        master.bind('d', _init_start)
        master.bind('<Escape>', _quit)
        master.bind('<Return>', _init_start)
コード例 #29
0
ファイル: snake.py プロジェクト: Vorathel/Fuxenpruefung
        def move():
            if self._direction is not None:
                canv.move('major', self._xVelTumble, self._yVelTumble)
                itemX, itemY = canv.coords('major')
                self._xPath.appendleft(itemX)
                self._yPath.appendleft(itemY)
                keep_in_box('major')
                move_fox_tail()
                # catch foxes
                if check_clipping(itemX, itemY, include='fox'):
                    self._score += self._nBeers
                    self._nFoxes += 1
                    canv.itemconfig('foxText', text=': ' + str(self._nFoxes))
                    canv.itemconfig('starText', text=': ' + str(self._score))
                    newX, newY = get_new_tail_pos()
                    _draw_new_fox(newX=newX,
                                  newY=newY,
                                  name='tail' + str(self._nFoxes - 1))
                    for item in reversed(itemRegister):
                        canv.tag_raise(item)
                    _draw_new_fox()
                    self._foxlastXvec = random.random()
                    self._foxlastYvec = random.random()
                    if 'beer' not in itemRegister:
                        _draw_new_beer()
                # drink beer
                if check_clipping(itemX, itemY, include='beer'):
                    self._nBeers += 1
                    canv.itemconfig('beerText',
                                    text=': ' + str(self._nBeers) + ' / ' +
                                    str(MAX_BEER - 1))
                    canv.itemconfig('starText', text=': ' + str(self._score))
                    step = (MAX_SPEED - START_SPEED) / N_SPEED_STEPS
                    self._speed = min(self._speed + step, MAX_SPEED)
                    if self._nBeers == MAX_BEER - 1:
                        canv.itemconfig(
                            'eventInfoText',
                            text=i18n.snakeEventInfo[i18n.lang()][1])
                    elif self._nBeers == MAX_BEER:
                        self._rotationSpeed = START_ROTATION_SPEED
                        canv.itemconfig(
                            'eventInfoText',
                            text=i18n.snakeEventInfo[i18n.lang()][2])
                    elif self._nBeers > MAX_BEER:
                        step = (MAX_ROTATION_SPEED -
                                START_ROTATION_SPEED) / N_ROTATION_SPEED_STEPS
                        self._rotationSpeed = min(self._rotationSpeed + step,
                                                  MAX_ROTATION_SPEED)
                        step = (MAX_TUMBLE_ANGLE -
                                START_TUMBLE_ANGLE) / N_TUMBLE_STEPS
                        self._tumbleAngle = min(self._tumbleAngle + step,
                                                MAX_TUMBLE_ANGLE)
                    if self._nBeers == MAX_BEER + 5:
                        _draw_new_bucket()
                        canv.itemconfig(
                            'eventInfoText',
                            text=i18n.snakeEventInfo[i18n.lang()][4])
                    if random.random() < BEER_RESPAWN_CHANCE:
                        _draw_new_beer()
                    else:
                        delete_widget('beer')
                # hit bucket
                if check_clipping(itemX, itemY, include='bucket'):
                    self._nBeers = MAX_BEER - 1
                    canv.itemconfig('beerText',
                                    text=': ' + str(self._nBeers) + ' / ' +
                                    str(MAX_BEER - 1))
                    delete_widget('bucket')
                    self._currentRotation = 0
                    self._rotationSpeed = 0
                    self._tumbleAngle = START_TUMBLE_ANGLE
                # rotate major and its direction
                # print('speed', self._speed, 'rotationSpeed', self._rotationSpeed, 'tumbleDegree', self._tumbleAngle)
                self._currentRotation += self._rotationSpeed
                canv.majorImg = ImageTk.PhotoImage(
                    majorImgObj.rotate(self._tumbleAngle * 2 *
                                       math.sin(self._currentRotation)))
                canv.itemconfig('major', image=canv.majorImg)
                angle = get_angle(1, 0, self._xVel, self._yVel)
                angle += self._tumbleAngle * math.sin(-self._currentRotation)
                angle = math.radians(angle)
                self._xVelTumble = MOVEMENT_STEP_SIZE * math.cos(angle)
                self._yVelTumble = MOVEMENT_STEP_SIZE * math.sin(angle)
                # check tail overlap
                noTailFoxes = [
                    item for item in itemRegister if 'tail' not in item
                ]
                noTailFoxes.extend(['tail' + str(idx) for idx in range(2)])
                crashFox = check_clipping(itemX,
                                          itemY,
                                          exclude=noTailFoxes,
                                          xSize=MAJOR_SIZE * 0.1,
                                          ySize=MAJOR_SIZE * 0.1)

                if crashFox:
                    print('Overlapping with tail', crashFox)
                    _end_game()
                    return
            self._job['move'] = master.after(int(1 / self._speed), move)