Как починить Часы? Для шахмат. питон

Я создаю шахматные часы для своего шахматного проекта. В шахматах есть форматы времени 5 | 5, когда каждому игроку (белому и черному) дается общее 5 минут, поэтому, когда любой из игроков делает ход, к часам добавляется 5 секунд. Таким образом, 15|10 — это 15 минут в целом и 10 секунд на ход.

Мой код:

import pygame
import time

pygame.init()

size = width, height = 300, 300
screen = pygame.display.set_mode(size)

# Fonts
Font = pygame.font.SysFont("Trebuchet MS", 25)

class Button:
    def __init__(self, color, x, y, width, height, text=''):
        self.color = color
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.text = text

    def draw(self, screen, outline=None):
        # Call this method to draw the button on the screen
        if outline:
            pygame.draw.rect(screen, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)

        pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height), 0)

        if self.text != '':
            font = pygame.font.SysFont('freesansbold.ttf', 16)
            text = font.render(self.text, 1, (0, 0, 0))
            screen.blit(text, (
                self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))

    def setColor(self, new_color):
        self.color = new_color

    def isOver(self, pos):
        # Pos is the mouse position or a tuple of (x,y) coordinates
        if self.x < pos[0] < self.x + self.width:
            if self.y < pos[1] < self.y + self.height:
                return True

        return False

def main():
    global Second, Minute
    running = True

    Black = 0, 0, 0
    White = 255, 255, 255

    Second = 0
    Minute = 0
    five_five = False
    Clock = pygame.time.Clock()

    while running:
        five_five_button = Button(White, 150, 150, 40, 20, '5|5')
        five_plus_five = Button(White, 150, 180, 40, 20, "+5 secs")
        five_five_button.draw(screen, None)
        five_plus_five.draw(screen, None)
        pygame.display.update()
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                running = False
            if e.type == pygame.MOUSEBUTTONDOWN:
                if five_five_button.isOver(e.pos):
                    five_five = True
                if five_plus_five.isOver(e.pos):
                    Second = +5
            if e.type == pygame.KEYDOWN:
                pass  # if you want to add keys to test things easier

         if five_five:
            Minute = 5
            Second = 0
            five_five = False
        if not five_five:
            if Second == 0:
                Second = 58
                Minute = Minute - 1
                Second += 2

        time.sleep(1)
        Second -= 1
        # Minute
        MinuteFont = Font.render(str(Minute).zfill(2), True, Black)
        MinuteFontR = MinuteFont.get_rect()
        MinuteFontR.center = (50, 60)
        # Second
        SecondFont = Font.render(":" + str(Second).zfill(2), True, Black)
        SecondFontR = SecondFont.get_rect()
        SecondFontR.center = (80, 60)

        screen.fill(White)

        # Timer
        #    while Time==0: this will cause a crash !
        screen.blit(SecondFont, SecondFontR)
        screen.blit(MinuteFont, MinuteFontR)
        pygame.display.flip()
        Clock.tick(60)


if __name__ == '__main__':
    main()

Проблемы, с которыми я сталкиваюсь:

Допустим, игрок делает ход, и время 4:59. Мы хотим добавить 5 секунд. Так что это добавляет 5 секунд, то есть 4:64, то есть минус минута, то есть 3:04. Я не знаю, как это исправить.

Другой заключается в том, что всякий раз, когда вы хотите добавить 5 секунд или что-то еще, оно никогда не превысит 59, и добавьте эти секунды к общему количеству и добавьте минуту.

Я часами работал над этим, верьте этому или нет, выясняя простые вещи. Я искал, как сделать часы и другие вещи в python (или pygame), и я всегда добавляю часы. Я никогда не встречал часы, которые прибавляют время, но при этом еще и отсчитывают время.

Всякий раз, когда я даже пытаюсь загрузить или нажать одну из кнопок. Регистрация занимает несколько секунд. Поэтому, если вы можете помочь мне разобраться во всем этом или найти лучший способ сделать это, я очень ценю это.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
539
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Итак, давайте просто перестроим блок, в котором вы обрабатываете мелкие изменения.

Вещи, которые нам нужно реализовать:

  1. Каждый тик должен проверять, прошло ли секунд больше 59 или меньше 0
  2. Если закончилось, то надо добавить минуту
  3. Если под, то надо вычесть минуту
  4. В обоих случаях нам нужно сбросить секунды

Мы можем сделать все это с помощью простых операторов if. Взгляните на следующее.

Я также собираюсь переместить секундную галочку перед проверкой, чтобы сделать нашу математику немного более понятной (измените время, а затем исправьте это).

Second -= 1
if not five_five:
    if Second < 0:
        Minute -= 1
        Second += 60    # Since Seconds will probably be -1
    elif Second > 59:
        Minute += 1
        Second -= 60

Это помогает, это делает игру лучше, но что произойдет, если игрок сделает ход на 4:59, добавив 5 секунд. Что получается должно быть 5:04, а получается 4:04. Поэтому я не знаю, как это исправить.

Axhul 15.12.2020 09:41

Это все еще происходит? В моем коде минуты должны увеличиваться, если добавляется время, а не уменьшаться.

Keldan Chapman 15.12.2020 09:53
Ответ принят как подходящий

Изменения имени

Прежде всего, я бы переименовал некоторые переменные, чтобы лучше передать их значение (учитывая, что некоторые из них не были сразу очевидны), поэтому я изменил эти:

five_five_button -> reset_button
five_plus_five -> add_button
Second -> seconds
Minute -> minutes
Black -> BLACK
White -> WHITE

Создание кнопки

Далее, я не думаю, что вам нужно заново создавать две кнопки в каждом кадре. Одного раза должно быть достаточно, чтобы их можно было нарисовать, поэтому я переместил их, как показано на рисунке:

# moved to here
reset_button = Button(White, 150, 150, 40, 20, '5|5')
add_button = Button(White, 150, 180, 40, 20, "+5 secs")
while running:
    # removed from here
    # reset_button = Button(White, 150, 150, 40, 20, '5|5')
    # add_button = Button(White, 150, 180, 40, 20, "+5 secs")

    # ... rest of loop code ...

Таймер минут и секунд

Далее, мне нравится то, что вы хотели сделать со сбросом и добавлением временного кода, но думаю, что в таком сценарии это на самом деле только усложняет ситуацию. Поэтому я удалил эти утверждения if:

if five_five:
    minutes = 5
    seconds = 0
    five_five = False
if not five_five:
    if seconds == 0:
        seconds = 58
        minutes = minutes - 1
        seconds += 2

и перенесли свою логику прямо в код цикла обработки событий pygame:

if e.type == pygame.MOUSEBUTTONDOWN:
    if reset_button.isOver(e.pos):
        minutes = 5
        seconds = 0
    if add_button.isOver(e.pos):
        seconds += 5

но это также означает, что у нас нет никакой логики, чтобы справиться с тем, что произойдет, если секунды выйдут за пределы допустимого, поэтому я написал следующее, чтобы это произошло сразу после нашего цикла событий pygame:

while seconds >= 60:
    seconds -= 60
    minutes += 1
while seconds < 0:
    seconds += 60
    minutes -= 1

Разделение на функции

Рефакторинг кода почти завершен, но перед этим я хочу разделить наш код на функции, чтобы упростить сопровождение и модульность. Мне также очень нравится использование классов для кнопок.

Сначала мне нужна функция «нарисовать все на экране»:

def draw_screen():
    global WHITE, BLACK

    screen.fill(WHITE)

    # buttons
    reset_button.draw(screen, None)
    add_button.draw(screen, None)

    # minutes tezt
    minutesFont = Font.render(str(minutes).zfill(2), True, BLACK)
    minutesFontR = minutesFont.get_rect()
    minutesFontR.center = (50, 60)
    screen.blit(minutesFont, minutesFontR)

    # seconds text
    secondsFont = Font.render(":" + str(seconds).zfill(2), True, BLACK)
    secondsFontR = secondsFont.get_rect()
    secondsFontR.center = (80, 60)
    screen.blit(secondsFont, secondsFontR)

    pygame.display.flip()

Таймер

Причина, по которой вы чувствуете, что кнопки реагируют вечно, заключается в том, что pygame может реагировать на нажатия кнопок только один раз в секунду. Это из-за вашего time.sleep(1), что означает, что ваш цикл событий запускается только один раз в секунду. Нам понадобится неблокирующий способ уменьшения таймера секунд на 1 один раз в секунду:

previousTime = time.time()
# ...
while running:
    # ...
    if time.time() - previousTime > 1:
        previousTime = time.time()
        seconds -= 1

Окончательный код

import pygame
import time

pygame.init()

size = width, height = 300, 300
screen = pygame.display.set_mode(size)

# Fonts
Font = pygame.font.SysFont("Trebuchet MS", 25)

class Button:
    def __init__(self, color, x, y, width, height, text=''):
        self.color = color
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.text = text

    def draw(self, screen, outline=None):
        # Call this method to draw the button on the screen
        if outline:
            pygame.draw.rect(screen, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)

        pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height), 0)

        if self.text != '':
            font = pygame.font.SysFont('freesansbold.ttf', 16)
            text = font.render(self.text, 1, (0, 0, 0))
            screen.blit(text, (
                self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))

    def setColor(self, new_color):
        self.color = new_color

    def isOver(self, pos):
        # Pos is the mouse position or a tuple of (x,y) coordinates
        if self.x < pos[0] < self.x + self.width:
            if self.y < pos[1] < self.y + self.height:
                return True

        return False

def draw_screen(minutes, seconds):
    global WHITE, BLACK

    screen.fill(WHITE)

    # buttons
    reset_button.draw(screen, None)
    add_button.draw(screen, None)

    # minutes tezt
    minutesFont = Font.render(str(minutes).zfill(2), True, BLACK)
    minutesFontR = minutesFont.get_rect()
    minutesFontR.center = (50, 60)
    screen.blit(minutesFont, minutesFontR)

    # seconds text
    secondsFont = Font.render(":" + str(seconds).zfill(2), True, BLACK)
    secondsFontR = secondsFont.get_rect()
    secondsFontR.center = (80, 60)
    screen.blit(secondsFont, secondsFontR)

    pygame.display.flip()


def fix_time(minutes, seconds):
    while seconds >= 60:
        seconds -= 60
        minutes += 1
    while seconds < 0:
        seconds += 60
        minutes -= 1
    return minutes, seconds


def handle_events(minutes, seconds, reset_button, add_button):
    for e in pygame.event.get():
            if e.type == pygame.QUIT:
                running = False
            if e.type == pygame.MOUSEBUTTONDOWN:
                if reset_button.isOver(e.pos):
                    minutes = 5
                    seconds = 0
                if add_button.isOver(e.pos):
                    seconds += 5
    return minutes, seconds

def main():
    global seconds, minutes
    running = True

    BLACK = 0, 0, 0
    WHITE = 255, 255, 255

    seconds = 0
    minutes = 0
    previousTime = time.time()
    Clock = pygame.time.Clock()

    reset_button = Button(WHITE, 150, 150, 40, 20, '5|5')
    add_button = Button(WHITE, 150, 180, 40, 20, "+5 secs")
    while running:
        
        minutes, seconds = handle_events(minutes, seconds, reset_button, add_button)

        if time.time() - previousTime > 1:
            previousTime = time.time()
            seconds -= 1

        minutes, seconds = fix_time(minutes, seconds)

        draw_screen(minutes, seconds):

        Clock.tick(60)


if __name__ == '__main__':
    main()

Мысли

Я не запускал код, но мысль, намерение и улучшение по-прежнему актуальны. Есть еще улучшения, которые можно внести в код (необходимость возвращать minutes и seconds и передавать reset_button и add_button в качестве параметров — это «нехорошо»), поэтому не стесняйтесь использовать мой пример в качестве вдохновения.

Вы действительно устранили проблемы. Я исправлю параметры. Большое спасибо.

Axhul 15.12.2020 10:16

Другие вопросы по теме