Курси програмування для дітей безкоштовно

23. Гра на Python Теніс

Гра на Python Теніс (Пінг-понг) — це ваш рецепт створення власної аркадної гри, де гравці керують ракетками, щоб відбивати м’ячик по черзі.
Ви навчитеся програмувати рух об’єктів, рахувати очки й робити гру динамічною та цікавою.
І найкрутіше — ви зможете налаштувати гру під себе: змінювати кольори, швидкість і навіть рівні складності, щоб грати ще веселіше!

Практика. Гра на Python Теніс

Створення ігрового поля

1: Почнемо з бази — налаштуємо ігрове поле. Вам потрібно створити головне вікно, область для відображення анімації та додати основні елементи гри.

Створімо заготовку для гри разом з глобальними змінними. Як бачите, у нас буде блок глобальних змінних, блок функцій і блок основної логіки. Розташовуйте код відповідно до цієї схеми — це допоможе створити правильну структуру й уникнути помилок в майбутньому. Створіть вказані змінні.

from tkinter import *
### глобальні змінні
# налаштування вікна
Створіть змінні ширини WIDTH у  900 пікселів та висоти HEIGHT у 300 пікселів.

# налаштування ракеток
Створіть змінні PAD_W та PAD_H для ширини та висоти ракетки відповідно. Встановіть ширину ракетки у 10 пікселів, а висоту у 100 пікселів.

# налаштування мʼячика
Додайте змінну BALL_RADIUS для радіуса м’яча та встановіть її значення у 30 пікселів.

### Функції для роботи з ігровими об'єктами


### Основна програма

Зверніть увагу на глобальні змінні на початку коду. Вони значно спрощують роботу. Наприклад, якщо ширина вікна 900 пікселів, набагато зручніше створити змінну WIDTH, присвоїти їй значення 900 і використовувати її в коді, ніж щоразу вручну писати 900.
Ви особливо оціните цей підхід, коли захочете щось змінити — наприклад, ширину вікна. Достатньо буде змінити лише одне значення, і вся гра автоматично підлаштується 🙂

2: Створімо базове вікно гри та додамо всі основні елементи.

Гра на Python Теніс | Python для дітей | ITisFuture
Гра на Python Теніс | Python для дітей | ITisFuture

Пояснення коду :

🔹 Створюємо вікно
root = Tk()
root.title(“Pythonic Pong”) – назва вікна зверху
🔹 Поле для гри
c = Canvas(root, width=WIDTH, height=HEIGHT, background=”#003300″) — створюємо “полотно” (Canvas), де буде гра. Вказуємо розмір і колір фону (темно-зелений)
c.pack() – Показуємо це полотно у вікні
🔹 Малюємо лінії поля.
c.create_line(PAD_W, 0, PAD_W, HEIGHT, fill=”white”) малюємо ліву вертикальну лінію (відступаємо від краю поля на ширину ракетки, щоб вона помістилася)
c.create_line(WIDTH-PAD_W, 0, WIDTH-PAD_W, HEIGHT, fill=”white”) малюємо праву лінію (відступаємо від краю поля на ширину ракетки)
c.create_line(WIDTH/2, 0, WIDTH/2, HEIGHT, fill=”white”) малюємо центральну лінію (як у тенісі)

🟨 Створення ліній :

create_line(x1, y1, x2, y2, width=…, fill=…)

  • (x1, y1) — точка початку лінії
  • (x2, y2) — точка кінця лінії
  • width — товщина
  • fill — колір

🔹 Створення м’яча : овал, який вписаний в прямокутник. Координати прямокутника вказані за допомогою двох точок : лівого верхнього і правого нижнього кута.
BALL = c.create_oval(…)

create_oval(x1, y1, x2, y2, fill=…)

  • (x1, y1) — верхній лівий кут уявного прямокутника
  • (x2, y2) — нижній правий кут
  • fill — колір фігури

BALL = c.create_oval(WIDTH/2-BALL_RADIUS/2,
HEIGHT/2-BALL_RADIUS/2,
WIDTH/2+BALL_RADIUS/2,
HEIGHT/2+BALL_RADIUS/2, fill=”white”)

🔹 Ракетки.
LEFT_PAD = c.create_line(PAD_W/2, 0, PAD_W/2, PAD_H, width=PAD_W, fill=”yellow”) малюємо ліву вертикальну лінію (ліву ракетку)
RIGHT_PAD = c.create_line(WIDTH-PAD_W/2, 0, WIDTH-PAD_W/2, PAD_H, width=PAD_W, fill=”yellow”) малюємо праву лінію (праву ракетку)

🟨 Створення ракеток : Ракетка — це товста лінія шириною width=PAD_W, як дуже витягнутий прямокутник.

LEFT_PAD = c.create_line(PAD_W/2, 0, PAD_W/2, PAD_H, width=PAD_W, fill=”yellow”)

Перша точка: PAD_W/2 → це X (по горизонталі, половинка ширини ракетки = центр лінії), а 0 → це Y (верх екрана)
Друга точка: PAD_W/2 (той самий X!) y = PAD_H (вниз на висоту ракетки)

Аналогічно, друга ракетка. Тільки в кінці поля, тому розраховуємо від ширини поля WIDTH-PAD_W.

🔹 Запуск гри: root.mainloop() йде за допомогою циклу. Функція mainloop() для динамічної гри, вона створить нескінченний цикл і слухатиме дії клавіатури чи мишки.

Перший запуск

У результаті у вас має вийти приблизно таке ігрове поле:

Гра на Python Теніс | Python для дітей | ITisFuture

Це наш “скелет” гри. Далі додамо рух і зробимо її по-справжньому інтерактивною 😉

Змушуємо м’яч рухатися

Додаймо цій грі трохи драйву! Створимо рух мʼячика. Для цього нам знадобиться нова функція move_ball, у якій ми опишемо логіку руху м’яча. Саме тут м’яч буде “оживати” і переміщатися по полю.
Також створімо функцію main. Вона буде:
🥎 викликати move_ball
🥎 запускати саму себе знову через root.after|
Таким чином, утворюється цикл, який постійно оновлює стан гри. Це і є основа будь-якої простої анімації в tkinter.

3: Додайте глобальні змінні швидкості м’яча:
рух по горизонталі: BALL_X_CHANGE зі значенням 20
рух по вертикалі BALL_Y_CHANGE зі значенням 0

4: Створіть функцію def move_ball() без параметрів. Функція має викликати команду :
c.move() — рух об’єкта з області анімації Canvas (ігрового поля). Ця функція потребує параметрів, тому передайте в неї :
BALL — це саме той об’єкт, який рухаємо (м’яч)
BALL_X_CHANGE — на скільки пікселів рухаємо по горизонталі
BALL_Y_CHANGE — на скільки пікселів рухаємо по вертикалі

5: Також створіть функцію main, яка буде робити дві команди:
🥎 викликати функцію move_ball() без параметрів
🥎 викликати функцію main кожні 30 мілісекунд : root.after(30, main). Це явище в програмування називається рекурсія

6: Додайте виклик функції main() в основну програму. (Перед рядком root.mainloop()). Це запустить рух м’яча із запуском гри


Якщо ви все зробили правильно, після запуску м’яч буде рухатися вправо. Запустіть програму

Ви можете змінювати швидкість і напрямок руху по горизонталі, змінюючи значення змінної BALL_X_CHANGE.

Рекурсія в Python

Рекурсія в Python — це коли функція викликає сама себе, щоб розв’язати задачу по частинах. Уявіть це як “розбирати задачу на менші копії самої себе” 🧩. У рекурсії завжди є 2 частини:
Рекурсивний крок — коли вона викликає сама себе
Базовий випадок — коли функція зупиняється

Рекурсія у Python | Python для дітей | ITisFuture

Як це виглядає в Python на практиці:

Приклад: порахувати факторіал числа (наприклад, 5! = 5×4×3×2×1)


def factorial(n):
# базовий випадок (коли зупинка)
    if n == 1: 
        return 1
    # виклик самої себе
    return n * factorial(n - 1)   

🔹 Як це працює
factorial(5)
→ 5 * factorial(4)
→ 5 * 4 * factorial(3)
→ 5 * 4 * 3 * factorial(2)
→ 5 * 4 * 3 * 2 * factorial(1)
→ 5 * 4 * 3 * 2 * 1 = 120

Не хвилюйтеся, якщо слово “рекурсія” звучить складно — на початку вона може трохи дивувати, але її розуміння дає ключ до розв’язання складніших задач у програмуванні 🙂

Керуємо ракетками

Тепер додамо керування ракетками, щоб гра стала інтерактивною.

Логіка тут дуже проста:
🏓у кожної ракетки є швидкість
🏓 спочатку вона дорівнює 0 — ракетка стоїть на місці
🏓коли користувач натискає клавішу — швидкість змінюється
🏓 ракетка починає рухатися вгору або вниз
🏓коли клавішу відпускають — швидкість знову стає 0

Тобто, фактично ви керуєте не позицією ракетки напряму, а її швидкістю. Цей підхід, використовується в багатьох іграх 🙂

Далі ми реалізуємо це в коді та прив’яжемо рух до клавіш клавіатури

7: Задайте глобальні змінні швидкості ракеток:
🏓PAD_SPEED – швидкість руху ракеток, значення 20
🏓LEFT_PAD_SPEED – швидкість лівої ракетки, значення 0
🏓RIGHT_PAD_SPEED – швидкість правої ракетки, значення 0

8: Створіть функцію руху ракеток:

Гра на Python Теніс | Python для дітей | ITisFuture

🏓 c.move(pad, 0, PADS[pad]) – рух об’єкта
pad – об’єкт, який рухаємо (одна з ракеток)
по X = 0 (вліво/вправо не рухається)
по Y = швидкість (вгору/вниз)
Тобто: ракетка рухається вверх або вниз

🏓 Перевірка: чи ракетка не вилізла вгору? if c.coords(pad)[1] < 0:
[1] — це верхня точка ракетки. Якщо вона < 0 → ракетка вилізла за верх
c.move(pad, 0, -c.coords(pad)[1]) – повертаємо її назад на поле

🏓 Перевірка: не вилізла вниз? elif c.coords(pad)[3] > HEIGHT:
[3] — це нижня точка. Якщо > HEIGHT → вилізла вниз
Тоді виправляємо: c.move(pad, 0, HEIGHT – c.coords(pad)[3]) – підтягуємо її назад в поле

9: Оновлюємо функцію main, додамо туди ще постійний виклик руху ракеток:

def main():
    move_ball()
    move_pads()
    root.after(30, main)

10: Створімо функцію обробки натискання клавіш. Допишіть код нижче, керуючись поясненнями:

movement_handler(event) – це функція, яка спрацьовує, коли гравець натискає кнопку на клавіатурі
event — це “повідомлення” від клавіатури. В ньому є: event.keysym – назва клавіші, наприклад “w” чи “Up” (стрілка вгору)

🏓 Клавіші керування лівою ракеткою : “w” – рух вгору і “s” – рух вниз
🏓 Клавіші керування правою ракеткою : “Up” (стрілка вгору) – рух вгору і “Down”(стрілка вгору) – рух вниз

🔹 Логіка кнопок
if event.keysym == “w”: – якщо натиснули w
LEFT_PAD_SPEED = -PAD_SPEED → Ліва ракетка їде вгору
elif event.keysym == “s”: – якщо натиснули s
LEFT_PAD_SPEED = PAD_SPEED → Ліва ракетка їде вниз

# обробка натискання клавіш
def movement_handler(event):
    global LEFT_PAD_SPEED, RIGHT_PAD_SPEED
    
    if event.keysym == "w":
        LEFT_PAD_SPEED = -PAD_SPEED
    elif event.keysym == "s":
        LEFT_PAD_SPEED = PAD_SPEED
    elif натуснули_стрілку_вгору:
        🏓🏓🏓🏓🏓= 🏓🏓🏓🏓
    elif натуснули_стрілку_вниз:
        🏓🏓🏓🏓🏓= 🏓🏓🏓🏓

Зупинка ракеток

11: Створімо функцію stop_pad з параметром event, яка буде зупиняти рух ракеток, якщо клавішу відпустили:
🏓Вкажіть глобальні змінні LEFT_PAD_SPEED, RIGHT_PAD_SPEED у функції
🏓Якщо event.keysym in (“w”, “s”), то LEFT_PAD_SPEED = 0. Тобто, якщо відпустили одну з клавіш w чи s, то швидкість лівої ракетки стає 0
🏓Аналогічно, якщо відпустили одну зі стрілочок “Up” чи “Down”, то швидкість правої ракетки стає 0.

12: Тепер час змінити основну програму і слухати події натискання клавіш. Додайте цей код перед викликом main():

# встановлюємо фокус на Canvas (щоб ловити натискання клавіш)
c.focus_set()

# прив’язуємо натискання клавіш
c.bind("<KeyPress>", movement_handler)

# прив’язуємо відпускання клавіш
c.bind("<KeyRelease>", stop_pad)

13: Запустіть і перевірте, що ви можете керувати обома ракетками 🎮. М’ячик поки не має відбиватися, це ми додамо згодом

Відскок м’яча від стінок і ракеток

Тепер прокачаємо м’ячик, щоб він вмів відбиватися від перешкод:
🥎 при зіткненні зі стінкою або ракеткою змінюємо напрямок руху м’яча
🥎 при ударі об ракетку:
🥎🥎 трохи збільшується швидкість
🥎🥎 вертикальний рух змінюється випадковим чином

14: Додайте бібліотеку import random для обробки випадкових подій. Також додайте кілька нових глобальних змінних:
BALL_SPEED_UP – наскільки збільшується швидкість після удару, значення 1.05
BALL_MAX_SPEED – максимальна швидкість м’яча, значення 40
BALL_X_SPEED – початкова швидкість по горизонталі, значення 20
BALL_Y_SPEED – початкова швидкість по вертикалі, значення 20
right_line_distance – відстань до правої межі поля, значення WIDTH – PAD_W

14: Створімо функцію відскоку м’яча bounce.

Гра на Python Теніс | Python для дітей | ITisFuture

Є 2 ситуації
🥎 if action == “strike”: 1: М’яч вдарився об ракетку
🥎 else: 2. М’яч вдарився об стінку

🥎 1. Удар об ракетку
BALL_Y_SPEED = random.randrange(-10, 10) м’яч отримує випадковий рух вверх/вниз
Тобто: кожен удар – це трохи змінює напрямок його руху

Зміна напрямку по X: if abs(BALL_X_SPEED) < BALL_MAX_SPEED:
BALL_X_SPEED *= -BALL_SPEED_UP

Що тут відбувається:
* -1 – змінює напрямок (вліво ↔ вправо)
BALL_SPEED_UP → трохи прискорює
Тобто, м’яч відскакує і стає швидшим

Якщо м’ячик вже дуже швидкий: else:
BALL_X_SPEED = -BALL_X_SPEED
то просто змінює напрямок (без прискорення)

🥎 2. Удар об стінку
BALL_Y_SPEED = -BALL_Y_SPEED міняємо напрямок по вертикалі
летів вниз → полетить вверх
летів вверх → полетить вниз

Програмуємо основну логіку м’ячика

15: Знайдіть функцію move_ball і розширте її логіку (поточний рядок можна буде замінити на новий код):

# функція руху м’яча
def move_ball():
    # координати м’яча
    ball_left, ball_top, ball_right, ball_bot = c.coords(BALL)
    ball_center = (ball_top + ball_bot) / 2

    # перевірка руху по горизонталі
    if ball_right + BALL_X_SPEED < right_line_distance and \
       ball_left + BALL_X_SPEED > PAD_W:
        c.move(BALL, BALL_X_SPEED, BALL_Y_SPEED)

    # торкання межі
    elif ball_right == right_line_distance or ball_left == PAD_W:
        
        if ball_right > WIDTH / 2:
            # права ракетка
            if c.coords(RIGHT_PAD)[1] < ball_center < c.coords(RIGHT_PAD)[3]:
                bounce("strike")
            else:
                # промах (додамо пізніше)
                pass
        else:
            # ліва ракетка
            if c.coords(LEFT_PAD)[1] < ball_center < c.coords(LEFT_PAD)[3]:
                bounce("strike")
            else:
                pass
    else:
        # якщо м’яч вилітає за межі — повертаємо його
        if ball_right > WIDTH / 2:
            c.move(BALL, right_line_distance - ball_right, BALL_Y_SPEED)
        else:
            c.move(BALL, -ball_left + PAD_W, BALL_Y_SPEED)

    # відскок від верхньої/нижньої межі
    if ball_top + BALL_Y_SPEED < 0 or ball_bot + BALL_Y_SPEED > HEIGHT:
        bounce("ricochet")

🧠 Загальна логіка м’яча:
🥎 летить
🥎 перевіряє — не вдарився?
🥎 якщо вдарився → змінює напрямок

🥎 1. Беремо координати ball_left, ball_top, ball_right, ball_bot = c.coords(BALL)
Це межі м’яча: ліва, верхня, права, нижня

ball_center = (ball_top + ball_bot) / 2 центр по вертикалі (щоб перевірити попадання в ракетку)

🥎 2. Якщо нічого не заважає — просто летимо
if ball_right + BALL_X_SPEED < right_line_distance and \ ball_left + BALL_X_SPEED > PAD_W: (якщо не вийшов справа чи зліва), тоді:
c.move(BALL, BALL_X_SPEED, BALL_Y_SPEED) просто рухаємо м’яч (летимо)

🥎 3. Торкання ракетки
elif ball_right == right_line_distance or ball_left == PAD_W: якщо м’яч дійшов до краю (де ракетки)

Якщо справа if ball_right > WIDTH / 2: значить це права сторона
Перевірка попадання
if c.coords(RIGHT_PAD)[1] < ball_center < c.coords(RIGHT_PAD)[3]: центр м’яча в межах ракетки?

✔ так → bounce(“strike”)
❌ ні → pass (пізніше тут буде “гол”)

Якщо зліва — те саме тільки для лівої ракетки

🥎 4. Якщо м’яч виліз за межі else:, то трохи “поправляємо” його назад у поле:

Якщо справа ball_right > WIDTH / 2, то c.move(BALL, right_line_distance – ball_right, BALL_Y_SPEED)
повертаємо назад

Якщо зліва, то теж повертаємо c.move(BALL, -ball_left + PAD_W, BALL_Y_SPEED)

🥎 5. Відскок від верху/низу
if ball_top + BALL_Y_SPEED < 0 or ball_bot + BALL_Y_SPEED > HEIGHT: м’яч торкнувся верху або низу
то bounce(“ricochet”) відскакує

Тепер м’яч відбивається від стінок і ракеток. Якщо гравець не встиг відбити — м’яч “зависає” біля краю. Далі це виправимо, додавши рахунок і перезапуск м’яча.

Підрахунок очок і респаун м’яча

16: Додамо рахунок для обох гравців. Створіть глобальні змінні:
PLAYER_1_SCORE = 0
PLAYER_2_SCORE = 0

17: Тепер відобразимо рахунок на екрані (можна додати в місце, де малюються лінії):

p_1_text = c.create_text(WIDTH - WIDTH/6, PAD_H/4,
                         text=PLAYER_1_SCORE,
                         font="Arial 20",
                         fill="white")

Аналогічно p_2_text, тільки координати : WIDTH/6, PAD_H/4 і текст PLAYER_2_SCORE.

Запустіть гру, має відображатися початковий рахунок:

Гра на Python Теніс | Python для дітей | ITisFuture

Залишилося додати оновлення рахунку й у вас буде повноцінний Pong 🏓

18: Створимо функції для оновлення рахунку та респауну. Для цього створіть ще одну глобальну змінну: INITIAL_SPEED — початкова швидкість м’яча, значення 20.

19: Створіть функцію оновлення рахунку update_score з параметром player – це гравець, якому оновлюємо рахунок (правий чи лівий):
🤾‍♀️ Визначаємо глобальні змінні PLAYER_1_SCORE, PLAYER_2_SCORE
🤾‍♀️Якщо передали правого гравця (player == “right”), то збільшуємо рахунок першого PLAYER_1_SCORE на 1. І відображаємо рахунок c.itemconfig(p_1_text, text=PLAYER_1_SCORE)
🤾‍♀️Інакше, збільшуємо рахунок лівого (другого) грався і відображаємо новий рахунок для нього

20: Створимо функцію респауну (оновлення м’яча). Вона буде ставити м’яч у центр і почне його рухати у бік гравця, який тільки-но пропустив з початковою швидкістю.

def spawn_ball():
    global BALL_X_SPEED
    
    # ставимо м’яч у центр
    c.coords(BALL,
             WIDTH/2 - BALL_RADIUS/2,
             HEIGHT/2 - BALL_RADIUS/2,
             WIDTH/2 + BALL_RADIUS/2,
             HEIGHT/2 + BALL_RADIUS/2)
    
    # задаємо напрямок у сторону гравця, який пропустив
    # і повертаємо початкову швидкість
    BALL_X_SPEED = -(BALL_X_SPEED * -INITIAL_SPEED) / abs(BALL_X_SPEED)

21: Тепер потрібно замінити pass у функції move_ball на виклик функцій оновлення рахунку і респану.
Замініть ТІЛЬКИ виділений жовтим код. Було:

if c.coords(RIGHT_PAD)[1] < ball_center < c.coords(RIGHT_PAD)[3]:
    bounce("strike")
else:
    pass
else:
    if c.coords(LEFT_PAD)[1] < ball_center < c.coords(LEFT_PAD)[3]:
        bounce("strike")
    else:
        pass

Має стати 👇

if c.coords(RIGHT_PAD)[1] < ball_center < c.coords(RIGHT_PAD)[3]:
   bounce("strike")
else:
   update_score("left")
   spawn_ball()
else:
   if c.coords(LEFT_PAD)[1] < ball_center < c.coords(LEFT_PAD)[3]:
       bounce("strike")
   else:
       update_score("right")
       spawn_ball()

 Що тепер відбувається:
🤾‍♂️якщо гравець не відбив м’яч — суперник отримує очко
🤾‍♂️рахунок оновлюється прямо на екрані
🤾‍♂️м’яч повертається в центр і летить у сторону того, хто програв розіграш

Готово 🎉

Тепер ваш «Пінг-понг» — повноцінна гра, у яку вже можна грати з другом.

Гра на Python Теніс | Python для дітей | ITisFuture

Приємної гри! 🏓

Уроки програмування для дітей. Домашня робота

Домашня робота

1: Звершіть гру та протестуйте, щоб усе працювало правильно. Перефарбуйте ігрове поле та ракетки у кольори на свій смак.
2: Зробіть так, щоб при відбитті м’ячика ракеткою додавалися не одне, а два очки.
3: Домалюйте горизонтальну лінію до поля, як на фото.
4: (Завдання виконується окремо від гри). Роздивіться приклад рекурсії. Зробіть одне з завдань на вибір за допомогою рекурсії:

Гра на Python Теніс | Python для дітей | ITisFuture

🪐Знайдіть суму чисел від 1 до n. Приклад: sum(5) = 1 + 2 + 3 + 4 + 5 = 15
🪐Піднесіть число до степеня без використання **. Приклад : pow(2, 3) = 8

Мем про ІТ  | Python для дітей | ITisFuture
Уроки програмування для дітей ускладнені завдання level up

Level Up!
Гра на Python Теніс

1: Додайте можливість грати одному гравцю (користувач обирає в консолі).
Підказка: простіше реалізувати, якщо збільшити одну з ракеток до максимальної висоти.

2: Додайте 3 рівні складності. Нехай користувач обирає рівень:
Новачок
Середній
Геймер

І залежно від рівня змінюйте швидкість м’яча і розмір ракеток.

3: Розв’яжіть одне з завдань на ваш вибір за допомогою рекурсії:

🪐Послідовність Фібоначчі — це такі числа, де кожне наступне число є сумою попередніх (крім перших): 0, 1, 1, 2, 3, 5, 8, 13, 21…
Поверніть n-те число Фібоначчі.
🪐Переверніть рядок за допомогою рекурсії. Приклад:
"hello" → "olleh"
🪐 Знайдіть суму цифр числа. Приклад: 123 → 1 + 2 + 3 = 6

Рекурсія у Python | Python для дітей | ITisFuture

Не зупиняйтеся у вивченні Python! До зустрічі на наступних уроках!

Залишити коментар

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *

holiganbet   holiganbet   holiganbet   holiganbet   holiganbet   holiganbet   starzbet   starzbet   starzbet   starzbet   starzbet   zlot   zlot   zlot   meritking   betgaranti   meritking   meritking   starzbet   betsmove   betcio   egebet   phishing   child porn   hack   shell   bets10   pishing   meritking   meritking   meritking   meritking   meritking   meritking   meritking   childiren porn   hack   shell   child porn   meritking   starzbet   jojobet   jojobet   meritking   starzbet   starzbet   mariobet   mariobet   mariobet   meritking   meritking   meritking   grandpashabet   meritking   meritkin   meritking   grandpashabet   meritking   grandpashabet   grandpashabet   grandpashabet   grandpashabet   grandpashabet   grandpashabet   grandpashabet   grandpashabet   grandpashabet   grandpashabet   grandpashabet   grandpashabet   grandpashabet   grandpashabet   grandpashabet