Skip to main content

Command Palette

Search for a command to run...

Dual Snake Battle: Implementasi Game Snake Dua Pemain dengan AI Pathfinding

Using Python to Create a Two-Player Snake Game with AI Pathfinding

Published
7 min read
Dual Snake Battle: Implementasi Game Snake Dua Pemain dengan AI Pathfinding
R

Tech enthusiast | MATLAB & Python lover | Exploring AI, ML, and deep learning. Sharing free code & tutorials to help others learn faster

Gambaran Umum

Dual Snake Battle adalah game Snake modern yang menampilkan dua ular yang dikendalikan oleh AI yang bersaing untuk mengumpulkan makanan di arena pertempuran. Game ini mengimplementasikan algoritma pathfinding canggih untuk menciptakan pengalaman bermain yang menantang dan dinamis.

import pygame
import random
import heapq

Fitur Utama

1. Dual AI System

  • Dua ular dengan AI independen

  • Kompetisi real-time untuk makanan

  • Sistem skor terpisah

2. Advanced Pathfinding

  • Menggunakan algoritma A* untuk pencarian jalur optimal

  • Heuristic Manhattan Distance untuk efisiensi

  • Penghindaran rintangan dinamis

3. Visual Modern

  • Grid system yang jelas

  • Warna berbeda untuk setiap ular

  • Tampilan skor real-time

Arsitektur Program

Struktur Data Utama

# Posisi snake dan makanan
snake_a = [(5, 5), (4, 5), (3, 5)]  # Ular A (biru)
snake_b = [(45, 25), (46, 25), (47, 25)]  # Ular B (hijau)
food_pos = (random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1))

Konfigurasi Game

GRID_SIZE = 20
GRID_WIDTH = 50
GRID_HEIGHT = 30
SCREEN_WIDTH = GRID_WIDTH * GRID_SIZE
SCREEN_HEIGHT = GRID_HEIGHT * GRID_SIZE

Algoritma A* Pathfinding

Implementasi Heuristic

def heuristic(a, b):
    return abs(a[0] - b[0]) + abs(a[1] - b[1])
def a_star_search(start, goal, obstacles, grid_width, grid_height):
    frontier = []
    heapq.heappush(frontier, (0, start))
    came_from = {start: None}
    cost_so_far = {start: 0}

    while frontier:
        _, current = heapq.heappop(frontier)

        if current == goal:
            break

        # Explore neighbors
        neighbors = [
            (current[0] + 1, current[1]),  # Kanan
            (current[0] - 1, current[1]),  # Kiri
            (current[0], current[1] + 1),  # Bawah
            (current[0], current[1] - 1)   # Atas
        ]

        for next_node in neighbors:
            if (0 <= next_node[0] < grid_width and 
                0 <= next_node[1] < grid_height and 
                next_node not in obstacles):

                new_cost = cost_so_far[current] + 1
                if next_node not in cost_so_far or new_cost < cost_so_far[next_node]:
                    cost_so_far[next_node] = new_cost
                    priority = new_cost + heuristic(goal, next_node)
                    heapq.heappush(frontier, (priority, next_node))
                    came_from[next_node] = current

    # Reconstruct path
    path = []
    current = goal
    while current is not None:
        path.append(current)
        current = came_from[current]
    path.reverse()
    return path if len(path) > 1 else []

Mekanisme Game

1. Perhitungan Pergerakan

# Hitung path untuk setiap snake
path_a = a_star_search(snake_a[0], food_pos, obstacles, GRID_WIDTH, GRID_HEIGHT)
path_b = a_star_search(snake_b[0], food_pos, obstacles, GRID_WIDTH, GRID_HEIGHT)

# Update posisi snake
if len(path_a) > 1:
    snake_a = [path_a[1]] + snake_a[:-1]
if len(path_b) > 1:
    snake_b = [path_b[1]] + snake_b[:-1]

2. Sistem Makanan dan Skor

if snake_a[0] == food_pos:
    food_pos = (random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1))
    snake_a.append(snake_a[-1])  # Tambah panjang
    score_a += 10
elif snake_b[0] == food_pos:
    food_pos = (random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1))
    snake_b.append(snake_b[-1])  # Tambah panjang
    score_b += 10

3. Game Over Conditions

# Tabrak tubuh sendiri atau lawan
if snake_a[0] in snake_b or snake_a[0] in snake_a[1:]:
    running = False
    print("Snake A kalah!")
if snake_b[0] in snake_a or snake_b[0] in snake_b[1:]:
    running = False
    print("Snake B kalah!")

Cara Menjalankan Program

Prasyarat Sistem

# Pastikan Python 3.x terinstall
python --version

# Install Pygame
pip install pygame

Langkah-langkah Menjalankan

  1. Simpan kode sebagai dual_snake_battle.py

  2. Jalankan melalui terminal/command prompt:

     python dual_snake_battle.py
    
  3. Game akan terbuka di window baru

Kontrol (jika ingin ditambahkan input manual)

# Contoh tambahan kontrol keyboard (bisa ditambahkan)
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:  # Snake A atas
    # Implementasi kontrol manual
    pass

🎨 Customization Options

Mengubah Warna

SNAKE_A_COLOR = (0, 128, 255)    # Biru
SNAKE_B_COLOR = (0, 255, 128)    # Hijau
FOOD_COLOR = (255, 0, 0)         # Merah
BACKGROUND_COLOR = (30, 30, 30)  # Dark gray

Mengubah Ukuran Grid

# Untuk arena lebih kecil
GRID_WIDTH = 30
GRID_HEIGHT = 20
GRID_SIZE = 25  # Pixel per grid

Mengubah Kecepatan Game

# Di dalam game loop
clock.tick(10)  # Ubah angka untuk kecepatan (5 = lambat, 20 = cepat)

Troubleshooting

Masalah Umum dan Solusi

  1. ModuleNotFoundError: No module named 'pygame'

     pip install pygame
    
  2. Game terlalu cepat/lambat

    • Ubah nilai clock.tick(10) di akhir game loop
  3. Window tidak muncul

    • Pastikan tidak ada error di console

    • Check kompatibilitas Pygame dengan Python version

  4. Performance issues

    • Kurangi ukuran grid (GRID_WIDTH dan GRID_HEIGHT)

    • Tutup aplikasi lain yang menggunakan resource tinggi

Potensi Pengembangan

Fitur yang Bisa Ditambahkan

  1. Multi-level System

     levels = {
         1: {"speed": 10, "grid_size": 20},
         2: {"speed": 15, "grid_size": 15},
         3: {"speed": 20, "grid_size": 10}
     }
    
  2. Power-ups dan Obstacles

     power_ups = [
         {"type": "speed_boost", "pos": (x, y), "duration": 5},
         {"type": "double_points", "pos": (x, y), "duration": 10}
     ]
    
  3. Mode Permainan Lain

    • Time attack

    • Survival mode

    • Team battle

Keunggulan Teknis

1. Efisiensi Algoritma

  • Menggunakan heap untuk priority queue

  • Manhattan distance untuk heuristic yang cepat

  • Optimasi memory dengan set untuk obstacles

2. Struktur Kode yang Bersih

  • Fungsi-fungsi terpisah dengan tanggung jawab jelas

  • Konstanta untuk mudah konfigurasi

  • Komentar yang informatif

3. Extensibility

  • Mudah ditambah fitur baru

  • Fleksibel untuk berbagai ukuran grid

  • Dapat diintegrasikan dengan AI yang lebih kompleks


Full Default Program

import pygame
import random
import heapq

# Inisialisasi Pygame
pygame.init()

# Ukuran layar dan grid (Lebih luas!)
GRID_SIZE = 20
GRID_WIDTH = 50
GRID_HEIGHT = 30
SCREEN_WIDTH = GRID_WIDTH * GRID_SIZE
SCREEN_HEIGHT = GRID_HEIGHT * GRID_SIZE

# Warna
SNAKE_A_COLOR = (0, 128, 255)
SNAKE_B_COLOR = (0, 255, 128)
FOOD_COLOR = (255, 0, 0)
BACKGROUND_COLOR = (30, 30, 30)
TEXT_COLOR = (255, 255, 255)

# Setup layar dan font
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT + 40))
pygame.display.set_caption("Dual Snake Battle with Scoring")
font = pygame.font.SysFont("Arial", 24)

# Fungsi untuk menggambar grid
def draw_grid():
    for x in range(0, SCREEN_WIDTH, GRID_SIZE):
        pygame.draw.line(screen, (40, 40, 40), (x, 0), (x, SCREEN_HEIGHT))
    for y in range(0, SCREEN_HEIGHT, GRID_SIZE):
        pygame.draw.line(screen, (40, 40, 40), (0, y), (SCREEN_WIDTH, y))

# Fungsi Heuristic (Manhattan Distance)
def heuristic(a, b):
    return abs(a[0] - b[0]) + abs(a[1] - b[1])

# Algoritma A* Pathfinding
def a_star_search(start, goal, obstacles, grid_width, grid_height):
    frontier = []
    heapq.heappush(frontier, (0, start))
    came_from = {start: None}
    cost_so_far = {start: 0}

    while frontier:
        _, current = heapq.heappop(frontier)

        if current == goal:
            break

        neighbors = [
            (current[0] + 1, current[1]),
            (current[0] - 1, current[1]),
            (current[0], current[1] + 1),
            (current[0], current[1] - 1)
        ]

        for next_node in neighbors:
            if (0 <= next_node[0] < grid_width and 
                0 <= next_node[1] < grid_height and 
                next_node not in obstacles):

                new_cost = cost_so_far[current] + 1
                if next_node not in cost_so_far or new_cost < cost_so_far[next_node]:
                    cost_so_far[next_node] = new_cost
                    priority = new_cost + heuristic(goal, next_node)
                    heapq.heappush(frontier, (priority, next_node))
                    came_from[next_node] = current

    path = []
    current = goal
    while current is not None:
        path.append(current)
        current = came_from[current]
    path.reverse()
    return path if len(path) > 1 else []

# Inisialisasi posisi snake, makanan, dan skor
snake_a = [(5, 5), (4, 5), (3, 5)]
snake_b = [(45, 25), (46, 25), (47, 25)]
food_pos = (random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1))
score_a = 0
score_b = 0

# Loop utama game
running = True
clock = pygame.time.Clock()

while running:
    screen.fill(BACKGROUND_COLOR)
    draw_grid()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    obstacles = set(snake_a + snake_b)

    path_a = a_star_search(snake_a[0], food_pos, obstacles, GRID_WIDTH, GRID_HEIGHT)
    path_b = a_star_search(snake_b[0], food_pos, obstacles, GRID_WIDTH, GRID_HEIGHT)

    if len(path_a) > 1:
        snake_a = [path_a[1]] + snake_a[:-1]
    if len(path_b) > 1:
        snake_b = [path_b[1]] + snake_b[:-1]

    if snake_a[0] == food_pos:
        food_pos = (random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1))
        snake_a.append(snake_a[-1])
        score_a += 10
    elif snake_b[0] == food_pos:
        food_pos = (random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1))
        snake_b.append(snake_b[-1])
        score_b += 10

    # Game Over Logic
    if snake_a[0] in snake_b or snake_a[0] in snake_a[1:]:
        running = False
        print("Snake A kalah!")
    if snake_b[0] in snake_a or snake_b[0] in snake_b[1:]:
        running = False
        print("Snake B kalah!")

    # Gambar snake dan makanan
    for segment in snake_a:
        pygame.draw.rect(screen, SNAKE_A_COLOR, (segment[0] * GRID_SIZE, segment[1] * GRID_SIZE, GRID_SIZE, GRID_SIZE))
    for segment in snake_b:
        pygame.draw.rect(screen, SNAKE_B_COLOR, (segment[0] * GRID_SIZE, segment[1] * GRID_SIZE, GRID_SIZE, GRID_SIZE))
    pygame.draw.rect(screen, FOOD_COLOR, (food_pos[0] * GRID_SIZE, food_pos[1] * GRID_SIZE, GRID_SIZE, GRID_SIZE))

    # Tampilkan skor
    score_text = font.render(f"Score A: {score_a}   Score B: {score_b}", True, TEXT_COLOR)
    screen.blit(score_text, (10, SCREEN_HEIGHT + 5))

    # Update layar
    pygame.display.flip()
    clock.tick(10)

pygame.quit()

Kesimpulan

Dual Snake Battle menunjukkan bagaimana konsep klasik game Snake dapat dikembangkan menjadi pengalaman yang lebih kompleks dan menarik dengan menerapkan algoritma AI modern. Program ini tidak hanya menghibur tetapi juga menjadi platform yang excellent untuk mempelajari:

  • Algoritma Pathfinding (A* dengan berbagai heuristic)

  • Game Development dengan Pygame

  • Artificial Intelligence dalam game

  • Optimasi Performance untuk real-time applications

Dengan struktur kode yang terorganisir dengan baik dan algoritma yang efisien, game ini dapat dengan mudah dikembangkan lebih lanjut menjadi produk game yang lebih kompleks dan menarik.