diff --git a/.github/workflows/docker-deploy.yml b/.github/workflows/docker-deploy.yml new file mode 100644 index 0000000..8237496 --- /dev/null +++ b/.github/workflows/docker-deploy.yml @@ -0,0 +1,57 @@ +name: Build and Deploy Python App + +on: + push: + branches: + - main # Adjust if using a different branch + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Debug Secrets (Check if they are available) + run: echo "Secrets are set" + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push Docker image + run: | + docker build -t ${{ secrets.DOCKER_USERNAME }}/python-snake-game:test . + docker push ${{ secrets.DOCKER_USERNAME }}/python-snake-game:test + + deploy: + needs: build + runs-on: ubuntu-latest + steps: + - name: Set up SSH Key + run: | + echo "${{ secrets.SSH_PRIVATE_KEY }}" > private_key + chmod 600 private_key + + - name: Install Docker & Docker Compose on Remote Server + run: | + ssh -o StrictHostKeyChecking=no -i private_key ubuntu@${{ secrets.SERVER_IP }} << 'EOF' + sudo apt update + sudo apt install -y docker.io docker-compose + sudo systemctl enable --now docker + EOF + + - name: Deploy using Docker Compose + run: | + ssh -o StrictHostKeyChecking=no -i private_key ubuntu@${{ secrets.SERVER_IP }} << 'EOF' + cd /home/ubuntu/python_projects # Navigate to the correct directory + docker login -u "${{ secrets.DOCKER_USERNAME }}" -p "${{ secrets.DOCKER_PASSWORD }}" + docker pull ${{ secrets.DOCKER_USERNAME }}/python-snake-game:test + docker-compose down # Stop any running containers + docker-compose up -d --force-recreate # Start fresh + EOF diff --git a/1_snake_game/7_final_code_background_music_image.py b/1_snake_game/7_final_code_background_music_image.py index cb4e329..428a179 100644 --- a/1_snake_game/7_final_code_background_music_image.py +++ b/1_snake_game/7_final_code_background_music_image.py @@ -1,12 +1,14 @@ -# Add background image and music - import pygame from pygame.locals import * import time import random +from flask import Flask, render_template + +app = Flask(__name__) SIZE = 40 BACKGROUND_COLOR = (110, 110, 5) +ENABLE_SOUND = False class Apple: def __init__(self, parent_screen): @@ -20,15 +22,14 @@ def draw(self): pygame.display.flip() def move(self): - self.x = random.randint(1,24)*SIZE - self.y = random.randint(1,19)*SIZE + self.x = random.randint(1, 24) * SIZE + self.y = random.randint(1, 19) * SIZE class Snake: def __init__(self, parent_screen): self.parent_screen = parent_screen self.image = pygame.image.load("resources/block.jpg").convert() self.direction = 'down' - self.length = 1 self.x = [40] self.y = [40] @@ -46,12 +47,10 @@ def move_down(self): self.direction = 'down' def walk(self): - # update body - for i in range(self.length-1,0,-1): - self.x[i] = self.x[i-1] - self.y[i] = self.y[i-1] + for i in range(self.length - 1, 0, -1): + self.x[i] = self.x[i - 1] + self.y[i] = self.y[i - 1] - # update head if self.direction == 'left': self.x[0] -= SIZE if self.direction == 'right': @@ -77,10 +76,10 @@ def increase_length(self): class Game: def __init__(self): pygame.init() - pygame.display.set_caption("Codebasics Snake And Apple Game") - - pygame.mixer.init() - self.play_background_music() + pygame.display.set_caption("Snake Game") + if ENABLE_SOUND: + pygame.mixer.init() + self.play_background_music() self.surface = pygame.display.set_mode((1000, 800)) self.snake = Snake(self.surface) @@ -88,107 +87,40 @@ def __init__(self): self.apple = Apple(self.surface) self.apple.draw() - def play_background_music(self): - pygame.mixer.music.load('resources/bg_music_1.mp3') - pygame.mixer.music.play(-1, 0) - - def play_sound(self, sound_name): - if sound_name == "crash": - sound = pygame.mixer.Sound("resources/crash.mp3") - elif sound_name == 'ding': - sound = pygame.mixer.Sound("resources/ding.mp3") - - pygame.mixer.Sound.play(sound) - - def reset(self): - self.snake = Snake(self.surface) - self.apple = Apple(self.surface) - - def is_collision(self, x1, y1, x2, y2): - if x1 >= x2 and x1 < x2 + SIZE: - if y1 >= y2 and y1 < y2 + SIZE: - return True - return False - - def render_background(self): - bg = pygame.image.load("resources/background.jpg") - self.surface.blit(bg, (0,0)) - def play(self): - self.render_background() self.snake.walk() self.apple.draw() - self.display_score() - pygame.display.flip() - - # snake eating apple scenario - if self.is_collision(self.snake.x[0], self.snake.y[0], self.apple.x, self.apple.y): - self.play_sound("ding") - self.snake.increase_length() - self.apple.move() - - # snake colliding with itself - for i in range(3, self.snake.length): - if self.is_collision(self.snake.x[0], self.snake.y[0], self.snake.x[i], self.snake.y[i]): - self.play_sound('crash') - raise "Collision Occurred" - - def display_score(self): - font = pygame.font.SysFont('arial',30) - score = font.render(f"Score: {self.snake.length}",True,(200,200,200)) - self.surface.blit(score,(850,10)) - - def show_game_over(self): - self.render_background() - font = pygame.font.SysFont('arial', 30) - line1 = font.render(f"Game is over! Your score is {self.snake.length}", True, (255, 255, 255)) - self.surface.blit(line1, (200, 300)) - line2 = font.render("To play again press Enter. To exit press Escape!", True, (255, 255, 255)) - self.surface.blit(line2, (200, 350)) - pygame.mixer.music.pause() pygame.display.flip() def run(self): running = True - pause = False - while running: for event in pygame.event.get(): if event.type == KEYDOWN: if event.key == K_ESCAPE: running = False - - if event.key == K_RETURN: - pygame.mixer.music.unpause() - pause = False - - if not pause: - if event.key == K_LEFT: - self.snake.move_left() - - if event.key == K_RIGHT: - self.snake.move_right() - - if event.key == K_UP: - self.snake.move_up() - - if event.key == K_DOWN: - self.snake.move_down() - + if event.key == K_LEFT: + self.snake.move_left() + if event.key == K_RIGHT: + self.snake.move_right() + if event.key == K_UP: + self.snake.move_up() + if event.key == K_DOWN: + self.snake.move_down() elif event.type == QUIT: running = False - try: - - if not pause: - self.play() + self.play() + time.sleep(.25) - except Exception as e: - self.show_game_over() - pause = True - self.reset() +game = None - time.sleep(.25) +@app.route('/') +def index(): + global game + if game is None: + game = Game() + game.run() + return "Snake Game is Running!" if __name__ == '__main__': - game = Game() - game.run() \ No newline at end of file + app.run(host='0.0.0.0', port=5000) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..13a6149 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,7 @@ +version: '3' +services: + python-game: + image: jobinaj/python-snake-game:test + restart: always + ports: + - "5000:5000" diff --git a/dockerfile b/dockerfile new file mode 100644 index 0000000..8b20a22 --- /dev/null +++ b/dockerfile @@ -0,0 +1,33 @@ +# Use a slim Python image +FROM python:3.9-slim + +# Set working directory +WORKDIR /app + +# Install necessary system libraries for audio and GUI support +RUN apt-get update && apt-get install -y \ + libglib2.0-0 \ + libglib2.0-dev \ + libsdl2-mixer-2.0-0 \ + alsa-utils \ + pulseaudio \ + xvfb && \ + rm -rf /var/lib/apt/lists/* + +# Copy only necessary files +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +# Set the correct working directory +WORKDIR /app/1_snake_game + +# Copy the `1_snake_game` folder properly +COPY 1_snake_game /app/1_snake_game + +# Set environment variables +ENV SDL_AUDIODRIVER=pulseaudio +ENV XDG_RUNTIME_DIR=/tmp +ENV DISPLAY=:99 + +# Start the virtual display and run the game +CMD ["bash", "-c", "Xvfb :99 -screen 0 1024x768x16 & python 7_final_code_background_music_image.py"] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..3785397 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +flask +pygame