Added battleship files
BIN
Battleships/.DS_Store
vendored
Normal file
121
Battleships/Lesson1.html
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<title>Lesson 1: Battleships in Python!</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
background: #f0f8ff;
|
||||||
|
color: #2c3e50;
|
||||||
|
padding: 20px;
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color: #2980b9;
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 3px solid #3498db;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
color: #2c3e50;
|
||||||
|
margin-top: 25px;
|
||||||
|
}
|
||||||
|
.outcome {
|
||||||
|
background: #e3f2fd;
|
||||||
|
padding: 15px;
|
||||||
|
border-left: 4px solid #3498db;
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
.why {
|
||||||
|
background: #e8f5e9;
|
||||||
|
padding: 15px;
|
||||||
|
border-left: 4px solid #2ecc71;
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
.step {
|
||||||
|
background: #fff8e1;
|
||||||
|
padding: 12px;
|
||||||
|
margin: 10px 0;
|
||||||
|
border-radius: 6px;
|
||||||
|
border-left: 4px solid #f39c12;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
background: #f1f1f1;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
.time {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #e74c3c;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>🎮 Lesson 1: Find the Hidden Ship!</h1>
|
||||||
|
|
||||||
|
<div class="outcome">
|
||||||
|
<h2>✅ Learning Outcomes</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Use <code>random</code> to create hidden game elements</li>
|
||||||
|
<li>Get input from the player using <code>input()</code></li>
|
||||||
|
<li>Use <code>if</code> / <code>else</code> to give feedback</li>
|
||||||
|
<li>Run and debug a simple Python program</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="why">
|
||||||
|
<h2>💡 Why It Matters</h2>
|
||||||
|
<p>Every video game has <strong>hidden logic</strong> — secret levels, random enemies, or treasure locations. Learning to hide and reveal things with code is the first step to making your own games!</p>
|
||||||
|
<p>These same skills are used in apps, quizzes, and even smart home devices!</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>⏱️ Lesson Plan (40 minutes)</h2>
|
||||||
|
|
||||||
|
<div class="step">
|
||||||
|
<span class="time">0–5 min</span> → <strong>Demo & Explain</strong><br>
|
||||||
|
Show the game: “There’s a secret ship! Can you find it?”<br>
|
||||||
|
Explain: We’ll write code that hides a ship and checks your guess.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="step">
|
||||||
|
<span class="time">5–20 min</span> → <strong>Code Together</strong><br>
|
||||||
|
Type this starter code (or use your template):
|
||||||
|
<pre style="background:#2d2d2d;color:#f8f8f2;padding:10px;border-radius:6px;font-size:14px;">
|
||||||
|
import random
|
||||||
|
|
||||||
|
ship_row = random.randint(0, 4)
|
||||||
|
ship_col = random.randint(0, 4)
|
||||||
|
|
||||||
|
print("Guess the ship!")
|
||||||
|
guess_row = int(input("Row (0-4): "))
|
||||||
|
guess_col = int(input("Col (0-4): "))
|
||||||
|
|
||||||
|
if guess_row == ship_row and guess_col == ship_col:
|
||||||
|
print("🎯 HIT! You sank the ship!")
|
||||||
|
else:
|
||||||
|
print("💦 MISS!")
|
||||||
|
|
||||||
|
print("The ship was at", ship_row, ship_col)
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="step">
|
||||||
|
<span class="time">20–35 min</span> → <strong>Test & Improve</strong><br>
|
||||||
|
• Run the program 3 times<br>
|
||||||
|
• Try to break it (type a letter instead of number — what happens?)<br>
|
||||||
|
• 🌟 <em>Challenge</em>: Add a 2nd ship or limit to 3 guesses!
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="step">
|
||||||
|
<span class="time">35–40 min</span> → <strong>Share & Celebrate</strong><br>
|
||||||
|
Pair up! Can your partner guess the ship in 2 tries?
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>🚀 You Just Learned:</h2>
|
||||||
|
<p>How to create <strong>interactive programs</strong> that respond to user choices — the heart of all games!</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
138
Battleships/Lesson2.html
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<title>Lesson 2: Hunt All the Ships!</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
background: #fff3e0;
|
||||||
|
color: #2c3e50;
|
||||||
|
padding: 20px;
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color: #e67e22;
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 3px solid #f39c12;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
color: #2c3e50;
|
||||||
|
margin-top: 25px;
|
||||||
|
}
|
||||||
|
.outcome {
|
||||||
|
background: #ffecb3;
|
||||||
|
padding: 15px;
|
||||||
|
border-left: 4px solid #f39c12;
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
.why {
|
||||||
|
background: #dcedc8;
|
||||||
|
padding: 15px;
|
||||||
|
border-left: 4px solid #8bc34a;
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
.step {
|
||||||
|
background: #e1f5fe;
|
||||||
|
padding: 12px;
|
||||||
|
margin: 10px 0;
|
||||||
|
border-radius: 6px;
|
||||||
|
border-left: 4px solid #039be5;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
background: #f1f1f1;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
.time {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #d32f2f;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>🚢 Lesson 2: Hunt All the Ships!</h1>
|
||||||
|
|
||||||
|
<div class="outcome">
|
||||||
|
<h2>✅ Learning Outcomes</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Use <strong>lists</strong> to store multiple ships</li>
|
||||||
|
<li>Create a <strong>game loop</strong> with turns</li>
|
||||||
|
<li>Track game state (<code>hits</code>, <code>turns</code>)</li>
|
||||||
|
<li>Make decisions with <code>for</code> loops and <code>if</code> inside lists</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="why">
|
||||||
|
<h2>💡 Why It Matters</h2>
|
||||||
|
<p>Real games don’t end after one guess! They track <strong>score</strong>, <strong>lives</strong>, and <strong>progress</strong>. Learning to manage game state is how you build Pac-Man, Minecraft, or Roblox games!</p>
|
||||||
|
<p>Lists and loops are used in <em>every</em> programming language — from apps to robots.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>⏱️ Lesson Plan (40 minutes)</h2>
|
||||||
|
|
||||||
|
<div class="step">
|
||||||
|
<span class="time">0–5 min</span> → <strong>Review & Goal</strong><br>
|
||||||
|
“Last time: 1 ship. Today: <strong>3 ships</strong> and <strong>10 turns</strong>!”<br>
|
||||||
|
Show the enhanced game in action.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="step">
|
||||||
|
<span class="time">5–20 min</span> → <strong>Upgrade Your Code</strong><br>
|
||||||
|
Edit your Lesson 1 file to this:
|
||||||
|
<pre style="background:#2d2d2d;color:#f8f8f2;padding:10px;border-radius:6px;font-size:14px;">
|
||||||
|
import random
|
||||||
|
|
||||||
|
ships = []
|
||||||
|
while len(ships) < 3:
|
||||||
|
r = random.randint(0, 4)
|
||||||
|
c = random.randint(0, 4)
|
||||||
|
if [r, c] not in ships:
|
||||||
|
ships.append([r, c])
|
||||||
|
|
||||||
|
print("3 ships hidden! 10 turns to find them all.")
|
||||||
|
hits = 0
|
||||||
|
|
||||||
|
for turn in range(10):
|
||||||
|
print("\nTurn", turn + 1)
|
||||||
|
guess_row = int(input("Row (0-4): "))
|
||||||
|
guess_col = int(input("Col (0-4): "))
|
||||||
|
|
||||||
|
if [guess_row, guess_col] in ships:
|
||||||
|
print("🎯 HIT!")
|
||||||
|
ships.remove([guess_row, guess_col])
|
||||||
|
hits += 1
|
||||||
|
if hits == 3:
|
||||||
|
print("🏆 You win!")
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print("💦 MISS!")
|
||||||
|
|
||||||
|
if hits < 3:
|
||||||
|
print("Game over! You found", hits, "ships.")
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="step">
|
||||||
|
<span class="time">20–35 min</span> → <strong>Level Up!</strong><br>
|
||||||
|
• Test the game (try to win!)<br>
|
||||||
|
• 🌟 <em>Challenge 1</em>: Let players use <strong>A, B, C</strong> for rows!<br>
|
||||||
|
<code>row_letter = input("Row (A-E): ").upper()</code><br>
|
||||||
|
<code>guess_row = ord(row_letter) - ord('A')</code><br>
|
||||||
|
• 🌟 <em>Challenge 2</em>: Show how many turns are left!
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="step">
|
||||||
|
<span class="time">35–40 min</span> → <strong>Play & Reflect</strong><br>
|
||||||
|
Play your friend’s game! What makes it fun?<br>
|
||||||
|
“Now YOU can make games — not just play them!”
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>🌟 You’re Now a Game Coder!</h2>
|
||||||
|
<p>You’ve learned the core ideas behind almost every game: <strong>hidden objects</strong>, <strong>player input</strong>, <strong>feedback</strong>, and <strong>win/lose conditions</strong>.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
Battleships/battleships-137-main/.DS_Store
vendored
Normal file
9
Battleships/battleships-137-main/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
core.Microsoft*
|
||||||
|
core.mongo*
|
||||||
|
core.python*
|
||||||
|
env.py
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
node_modules/
|
||||||
|
.github/
|
||||||
|
creds.json
|
||||||
84
Battleships/battleships-137-main/.gitpod.dockerfile
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
FROM gitpod/workspace-base
|
||||||
|
|
||||||
|
RUN echo "CI version from base"
|
||||||
|
|
||||||
|
### NodeJS ###
|
||||||
|
USER gitpod
|
||||||
|
ENV NODE_VERSION=16.13.0
|
||||||
|
ENV TRIGGER_REBUILD=1
|
||||||
|
RUN curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | PROFILE=/dev/null bash \
|
||||||
|
&& bash -c ". .nvm/nvm.sh \
|
||||||
|
&& nvm install $NODE_VERSION \
|
||||||
|
&& nvm use $NODE_VERSION \
|
||||||
|
&& nvm alias default $NODE_VERSION \
|
||||||
|
&& npm install -g typescript yarn node-gyp" \
|
||||||
|
&& echo ". ~/.nvm/nvm.sh" >> /home/gitpod/.bashrc.d/50-node
|
||||||
|
ENV PATH=$PATH:/home/gitpod/.nvm/versions/node/v${NODE_VERSION}/bin
|
||||||
|
|
||||||
|
### Python ###
|
||||||
|
USER gitpod
|
||||||
|
RUN sudo install-packages python3-pip
|
||||||
|
ENV PYTHON_VERSION 3.12.2
|
||||||
|
|
||||||
|
ENV PATH=$HOME/.pyenv/bin:$HOME/.pyenv/shims:$PATH
|
||||||
|
RUN curl -fsSL https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash \
|
||||||
|
&& { echo; \
|
||||||
|
echo 'eval "$(pyenv init -)"'; \
|
||||||
|
echo 'eval "$(pyenv virtualenv-init -)"'; } >> /home/gitpod/.bashrc.d/60-python \
|
||||||
|
&& pyenv update \
|
||||||
|
&& pyenv install $PYTHON_VERSION \
|
||||||
|
&& pyenv global $PYTHON_VERSION \
|
||||||
|
&& python3 -m pip install --no-cache-dir --upgrade pip \
|
||||||
|
&& python3 -m pip install --no-cache-dir --upgrade \
|
||||||
|
setuptools wheel virtualenv pipenv pylint rope flake8 \
|
||||||
|
mypy autopep8 pep8 pylama pydocstyle bandit notebook \
|
||||||
|
twine \
|
||||||
|
&& sudo rm -rf /tmp/*USER gitpod
|
||||||
|
ENV PYTHONUSERBASE=/workspace/.pip-modules \
|
||||||
|
PIP_USER=yes
|
||||||
|
ENV PATH=$PYTHONUSERBASE/bin:$PATH
|
||||||
|
|
||||||
|
# Setup Heroku CLI
|
||||||
|
RUN curl https://cli-assets.heroku.com/install.sh | sh
|
||||||
|
|
||||||
|
RUN wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb && sudo dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb && \
|
||||||
|
sudo rm -rf /var/cache/apt/* /var/lib/apt/lists/* /tmp/* /home/gitpod/*.deb && \
|
||||||
|
sudo chown -R gitpod:gitpod /home/gitpod/.cache/heroku/
|
||||||
|
|
||||||
|
# Setup PostgreSQL
|
||||||
|
|
||||||
|
RUN sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list' && \
|
||||||
|
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8 && \
|
||||||
|
sudo apt-get update -y && \
|
||||||
|
sudo apt-get install -y postgresql-12
|
||||||
|
|
||||||
|
ENV PGDATA="/workspace/.pgsql/data"
|
||||||
|
|
||||||
|
RUN mkdir -p ~/.pg_ctl/bin ~/.pg_ctl/sockets \
|
||||||
|
&& echo '#!/bin/bash\n[ ! -d $PGDATA ] && mkdir -p $PGDATA && initdb --auth=trust -D $PGDATA\npg_ctl -D $PGDATA -l ~/.pg_ctl/log -o "-k ~/.pg_ctl/sockets" start\n' > ~/.pg_ctl/bin/pg_start \
|
||||||
|
&& echo '#!/bin/bash\npg_ctl -D $PGDATA -l ~/.pg_ctl/log -o "-k ~/.pg_ctl/sockets" stop\n' > ~/.pg_ctl/bin/pg_stop \
|
||||||
|
&& chmod +x ~/.pg_ctl/bin/*
|
||||||
|
|
||||||
|
# ENV DATABASE_URL="postgresql://gitpod@localhost"
|
||||||
|
# ENV PGHOSTADDR="127.0.0.1"
|
||||||
|
ENV PGDATABASE="postgres"
|
||||||
|
|
||||||
|
ENV PATH="/usr/lib/postgresql/12/bin:/home/gitpod/.nvm/versions/node/v${NODE_VERSION}/bin:$HOME/.pg_ctl/bin:$PATH"
|
||||||
|
|
||||||
|
|
||||||
|
# Add aliases
|
||||||
|
|
||||||
|
RUN echo 'alias run="python3 $GITPOD_REPO_ROOT/manage.py runserver 0.0.0.0:8000"' >> ~/.bashrc && \
|
||||||
|
echo 'alias heroku_config=". $GITPOD_REPO_ROOT/.vscode/heroku_config.sh"' >> ~/.bashrc && \
|
||||||
|
echo 'alias python=python3' >> ~/.bashrc && \
|
||||||
|
echo 'alias pip=pip3' >> ~/.bashrc && \
|
||||||
|
echo 'alias arctictern="python3 $GITPOD_REPO_ROOT/.vscode/arctictern.py"' >> ~/.bashrc && \
|
||||||
|
echo 'alias font_fix="python3 $GITPOD_REPO_ROOT/.vscode/font_fix.py"' >> ~/.bashrc && \
|
||||||
|
echo 'alias set_pg="export PGHOSTADDR=127.0.0.1"' >> ~/.bashrc && \
|
||||||
|
echo 'alias make_url="python3 $GITPOD_REPO_ROOT/.vscode/make_url.py "' >> ~/.bashrc
|
||||||
|
|
||||||
|
# Local environment variables
|
||||||
|
ENV PORT="8080"
|
||||||
|
ENV IP="0.0.0.0"
|
||||||
|
|
||||||
|
|
||||||
14
Battleships/battleships-137-main/.gitpod.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
image:
|
||||||
|
file: .gitpod.dockerfile
|
||||||
|
tasks:
|
||||||
|
- init: . ${GITPOD_REPO_ROOT}/.vscode/init_tasks.sh
|
||||||
|
command: /home/gitpod/.pg_ctl/bin/pg_start > /dev/null
|
||||||
|
- command: . ${GITPOD_REPO_ROOT}/.vscode/uptime.sh &
|
||||||
|
vscode:
|
||||||
|
extensions:
|
||||||
|
- ms-python.python
|
||||||
|
- formulahendry.auto-close-tag
|
||||||
|
- eventyret.bootstrap-4-cdn-snippet
|
||||||
|
- hookyqr.beautify
|
||||||
|
- matt-rudge.auto-open-preview-panel
|
||||||
|
|
||||||
8
Battleships/battleships-137-main/.replit
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
modules = ["web", "nodejs-20", "python-3.12"]
|
||||||
|
run = "python3 run.py"
|
||||||
|
|
||||||
|
[nix]
|
||||||
|
channel = "stable-24_05"
|
||||||
|
|
||||||
|
[deployment]
|
||||||
|
run = ["sh", "-c", "python3 run.py"]
|
||||||
186
Battleships/battleships-137-main/.vscode/arctictern.py
vendored
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
"""
|
||||||
|
arctictern.py
|
||||||
|
A little script that does a big migration
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from os.path import exists
|
||||||
|
|
||||||
|
COLOURS = {"red": "\033[31m",
|
||||||
|
"blue": "\033[34m",
|
||||||
|
"green": "\033[32m",
|
||||||
|
"reset": "\033[0m",
|
||||||
|
"bold": "\033[1m"}
|
||||||
|
|
||||||
|
BASE_URL = "https://raw.githubusercontent.com/Code-Institute-Org/gitpod-full-template/main/"
|
||||||
|
CURRENT_VERSION = 1.0
|
||||||
|
THIS_VERSION = 1.0
|
||||||
|
|
||||||
|
|
||||||
|
UPGRADE_FILE_LIST = [{"filename": ".vscode/settings.json",
|
||||||
|
"url": ".vscode/settings.json"
|
||||||
|
},
|
||||||
|
{"filename": ".vscode/launch.json",
|
||||||
|
"url": ".vscode/launch.json"
|
||||||
|
},
|
||||||
|
{"filename": ".gitpod.yml",
|
||||||
|
"url": ".gitpod.yml"
|
||||||
|
},
|
||||||
|
{"filename": ".gitpod.dockerfile",
|
||||||
|
"url": ".gitpod.dockerfile"
|
||||||
|
},
|
||||||
|
{"filename": ".vscode/heroku_config.sh",
|
||||||
|
"url": ".vscode/heroku_config.sh"
|
||||||
|
},
|
||||||
|
{"filename": ".vscode/init_tasks.sh",
|
||||||
|
"url": ".vscode/init_tasks.sh"
|
||||||
|
},
|
||||||
|
{"filename": ".vscode/uptime.sh",
|
||||||
|
"url": ".vscode/uptime.sh"
|
||||||
|
},
|
||||||
|
{"filename": ".vscode/make_url.py",
|
||||||
|
"url": ".vscode/make_url.py"
|
||||||
|
},
|
||||||
|
{"filename": ".vscode/arctictern.py",
|
||||||
|
"url": ".vscode/arctictern.py"
|
||||||
|
}]
|
||||||
|
|
||||||
|
FINAL_LINES = "\nexport POST_UPGRADE_RUN=1\nsource ~/.bashrc\n"
|
||||||
|
|
||||||
|
|
||||||
|
def get_versions():
|
||||||
|
|
||||||
|
if exists(".vscode/version.txt"):
|
||||||
|
with open(".vscode/version.txt", "r") as f:
|
||||||
|
THIS_VERSION = float(f.read().strip())
|
||||||
|
else:
|
||||||
|
with open(".vscode/version.txt", "w") as f:
|
||||||
|
f.write(str(THIS_VERSION))
|
||||||
|
|
||||||
|
r = requests.get(BASE_URL + ".vscode/version.txt")
|
||||||
|
CURRENT_VERSION = float(r.content)
|
||||||
|
|
||||||
|
return {"this_version": THIS_VERSION,
|
||||||
|
"current_version": CURRENT_VERSION}
|
||||||
|
|
||||||
|
def needs_upgrade():
|
||||||
|
"""
|
||||||
|
Checks the version of the current template against
|
||||||
|
this version.
|
||||||
|
Returns True if upgrade is needed, False if not.
|
||||||
|
"""
|
||||||
|
|
||||||
|
versions = get_versions()
|
||||||
|
|
||||||
|
print(f"Upstream version: {versions['current_version']}")
|
||||||
|
print(f"Local version: {versions['this_version']}")
|
||||||
|
|
||||||
|
return versions["current_version"] > versions["this_version"]
|
||||||
|
|
||||||
|
|
||||||
|
def write_version():
|
||||||
|
|
||||||
|
versions = get_versions()
|
||||||
|
|
||||||
|
with open(".vscode/version.txt", "w") as f:
|
||||||
|
f.write(str(versions["current_version"]))
|
||||||
|
|
||||||
|
|
||||||
|
def build_post_upgrade():
|
||||||
|
|
||||||
|
r = requests.get(BASE_URL + ".vscode/upgrades.json")
|
||||||
|
upgrades = json.loads(r.content.decode("utf-8"))
|
||||||
|
content = ""
|
||||||
|
|
||||||
|
for k,v in upgrades.items():
|
||||||
|
if float(k) > THIS_VERSION:
|
||||||
|
print(f"Adding version changes for {k} to post_upgrade.sh")
|
||||||
|
content += v
|
||||||
|
|
||||||
|
if content:
|
||||||
|
content += FINAL_LINES
|
||||||
|
with open(".vscode/post_upgrade.sh", "w") as f:
|
||||||
|
f.writelines(content)
|
||||||
|
|
||||||
|
print("Built post_upgrade.sh. Restart your workspace for it to take effect.")
|
||||||
|
|
||||||
|
|
||||||
|
def process(file, suffix):
|
||||||
|
"""
|
||||||
|
Replaces and optionally backs up the files that
|
||||||
|
need to be changed.
|
||||||
|
Arguments: file - a path and filename
|
||||||
|
suffix - the suffix to the BASE_URL
|
||||||
|
"""
|
||||||
|
|
||||||
|
if file == ".gitpod.dockerfile" or file == ".gitpod.yml":
|
||||||
|
try:
|
||||||
|
shutil.copyfile(file, f"{file}.tmp")
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
with open(file, "wb") as f:
|
||||||
|
r = requests.get(BASE_URL + suffix)
|
||||||
|
f.write(r.content)
|
||||||
|
|
||||||
|
if exists(f"{file}.tmp"):
|
||||||
|
result = os.system(f"diff -q {file} {file}.tmp > /dev/null")
|
||||||
|
if result != 0:
|
||||||
|
os.remove(f"{file}.tmp")
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def start_migration():
|
||||||
|
"""
|
||||||
|
Calls the process function and
|
||||||
|
renames the directory
|
||||||
|
"""
|
||||||
|
push_and_recreate = False
|
||||||
|
|
||||||
|
if not os.path.isdir(".vscode"):
|
||||||
|
print("Creating .vscode directory")
|
||||||
|
os.mkdir(".vscode")
|
||||||
|
|
||||||
|
for file in UPGRADE_FILE_LIST:
|
||||||
|
print(f"Processing: {file['filename']}")
|
||||||
|
result = process(file["filename"], file["url"])
|
||||||
|
if result == True:
|
||||||
|
push_and_recreate = True
|
||||||
|
|
||||||
|
if push_and_recreate:
|
||||||
|
write_version()
|
||||||
|
|
||||||
|
if needs_upgrade() and not push_and_recreate:
|
||||||
|
build_post_upgrade()
|
||||||
|
|
||||||
|
print("Changes saved.")
|
||||||
|
print("Please add, commit and push to GitHub.")
|
||||||
|
print("You may need to stop and restart your workspace for")
|
||||||
|
print("the changes to take effect.\n")
|
||||||
|
|
||||||
|
if push_and_recreate:
|
||||||
|
print(f"{COLOURS['red']}{COLOURS['bold']}*** IMPORTANT INFORMATION ***{COLOURS['reset']}")
|
||||||
|
print("The files used to create this workspace have been updated")
|
||||||
|
print("Please download any files that are in .gitignore and")
|
||||||
|
print("recreate this workspace by clicking on the Gitpod button")
|
||||||
|
print("in GitHub. Then, upload your saved files again.\n")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
print(f"\n🐦 {COLOURS['blue']}{COLOURS['bold']}ArcticTern version 0.3{COLOURS['reset']}")
|
||||||
|
print("CI Template Migration Utility")
|
||||||
|
print("-----------------------------")
|
||||||
|
print("Upgrades the workspace to the latest version.\n")
|
||||||
|
|
||||||
|
if input("Start? Y/N ").lower() == "y":
|
||||||
|
start_migration()
|
||||||
|
else:
|
||||||
|
sys.exit("Migration cancelled by the user")
|
||||||
40
Battleships/battleships-137-main/.vscode/heroku_config.sh
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Script to allow Heroku API key to be pasted
|
||||||
|
# exported as an environment variable
|
||||||
|
#
|
||||||
|
# Matt Rudge, May 2021
|
||||||
|
|
||||||
|
echo Heroku authentication configuration script
|
||||||
|
echo Code Institute, 2021
|
||||||
|
echo
|
||||||
|
echo Get your Heroku API key by going to https://dashboard.heroku.com
|
||||||
|
echo Go to Account Settings and click on Reveal to view your Heroku API key
|
||||||
|
echo
|
||||||
|
|
||||||
|
if [[ -z "${HEROKU_API_KEY}" ]]; then
|
||||||
|
echo Paste your Heroku API key here or press Enter to quit:
|
||||||
|
read apikey
|
||||||
|
if [[ -z "${apikey}" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo export HEROKU_API_KEY=${apikey} >> ~/.bashrc
|
||||||
|
echo Added the export. Refreshing the terminal.
|
||||||
|
. ~/.bashrc > /dev/null
|
||||||
|
echo Done!
|
||||||
|
else
|
||||||
|
echo API key is already set.
|
||||||
|
echo
|
||||||
|
echo To reset the API key please input "'reset'":
|
||||||
|
read reset_trigger
|
||||||
|
if [[ ${reset_trigger} == reset ]]; then
|
||||||
|
unset HEROKU_API_KEY
|
||||||
|
unset reset_trigger
|
||||||
|
echo
|
||||||
|
echo API key removed!
|
||||||
|
else
|
||||||
|
unset reset_trigger
|
||||||
|
echo API key unchanged.
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
echo Exiting
|
||||||
|
fi
|
||||||
13
Battleships/battleships-137-main/.vscode/init_tasks.sh
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Gives a personalised greeting
|
||||||
|
# Adds configuration options for SQLite
|
||||||
|
# Creates run aliases
|
||||||
|
# Author: Matt Rudge
|
||||||
|
|
||||||
|
echo "Setting the greeting"
|
||||||
|
sed -i "s/USER_NAME/$GITPOD_GIT_USER_NAME/g" ${GITPOD_REPO_ROOT}/README.md
|
||||||
|
echo "Creating .sqliterc file"
|
||||||
|
echo ".headers on" > ~/.sqliterc
|
||||||
|
echo ".mode column" >> ~/.sqliterc
|
||||||
|
echo "Your workspace is ready to use. Happy coding!"
|
||||||
14
Battleships/battleships-137-main/.vscode/make_url.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Simple utility for creating the Cloudinary URL from a
|
||||||
|
# cloudinary_python.txt file
|
||||||
|
# Matt Rudge, November 2021
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
with open("cloudinary_python.txt") as f:
|
||||||
|
content = f.readlines()
|
||||||
|
|
||||||
|
cloud_name = re.findall(r"['](.*?)[']",content[15])[0]
|
||||||
|
api_key = re.findall(r"['](.*?)[']",content[16])[0]
|
||||||
|
api_secret = re.findall(r"['](.*?)[']",content[17])[0]
|
||||||
|
|
||||||
|
print(f"cloudinary://{api_key}:{api_secret}@{cloud_name}")
|
||||||
17
Battleships/battleships-137-main/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"python.pythonPath": ".venv/bin/python",
|
||||||
|
"python.formatting.provider": "black",
|
||||||
|
"python.formatting.blackArgs": ["--line-length=79" ],
|
||||||
|
"python.formatting.autopep8Args": ["--max-line-length=79" ],
|
||||||
|
"python.linting.enabled": true,
|
||||||
|
"python.linting.flake8Enabled": true,
|
||||||
|
"python.linting.pylintEnabled": true,
|
||||||
|
"python.linting.lintOnSave": true,
|
||||||
|
"python.linting.flake8Args": [
|
||||||
|
"--max-line-length=79"
|
||||||
|
],
|
||||||
|
"python.linting.pylintArgs": [
|
||||||
|
"--disable=C0111" // Disable missing docstring warnings if needed
|
||||||
|
],
|
||||||
|
"files.autoSave": "onFocusChange"
|
||||||
|
}
|
||||||
23
Battleships/battleships-137-main/.vscode/uptime.sh
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Pings the webhook so that we can gather
|
||||||
|
# basic usage stats. No personally identifiable
|
||||||
|
# data is captured here, and it is impossible to
|
||||||
|
# identify an individual user from the captured data.
|
||||||
|
# Matt Rudge, April 2021
|
||||||
|
|
||||||
|
UUID=$(cat /proc/sys/kernel/random/uuid)
|
||||||
|
URL=https://1xthkmzwg3.execute-api.eu-west-1.amazonaws.com/prod/lrsapi/
|
||||||
|
API_KEY=jceBCdeGZP9RDeUNCfM4jIQ39Cx0jtG51QgcwDwc
|
||||||
|
VERB="started"
|
||||||
|
|
||||||
|
clear
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
|
||||||
|
DATA="{\"activity_time\":\"$(date +%Y-%m-%dT%H:%M:%S).000Z\",\"actor\":\"${UUID}\",\"verb\":\"${VERB}\",\"activity_object\":\"Gitpod Workspace\",\"extra_data\":\"{}\"}"
|
||||||
|
curl -s -X POST -H "x-api-key: ${API_KEY}" -d "${DATA}" ${URL} 1> /dev/null
|
||||||
|
VERB="running"
|
||||||
|
sleep 300
|
||||||
|
|
||||||
|
done
|
||||||
1
Battleships/battleships-137-main/Procfile
Normal file
@@ -0,0 +1 @@
|
|||||||
|
web: node index.js
|
||||||
284
Battleships/battleships-137-main/README.md
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
# [Battleship Game](https://battleships-hedgemonkey-131f157c44ae.herokuapp.com/ "Click to see deployed app")
|
||||||
|
|
||||||
|
This is a simple command-line Battleship game written in Python, with a leader board stored in a google docs spreadsheet.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Click here for Table of Contents</summary>
|
||||||
|
|
||||||
|
[Screenshots](#screenshots)
|
||||||
|
|
||||||
|
[Flow Chart Screenshots](#flow-chart-screenshots)
|
||||||
|
|
||||||
|
[Features](#features)
|
||||||
|
|
||||||
|
[Testing](#testing)
|
||||||
|
|
||||||
|
[Future](#future)
|
||||||
|
|
||||||
|
[Deployment](#deployment)
|
||||||
|
|
||||||
|
[Credits](#credits)
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
| Heroku Deployed App |
|
||||||
|
| :---: |
|
||||||
|
|  |
|
||||||
|
| This is the app showing the Welcome screenwith Leaderboard with scores sourced through Google Docs API |
|
||||||
|
|
||||||
|
## Flow Chart Screenshots
|
||||||
|
| Flow Chart Screenshot |
|
||||||
|
| :---: |
|
||||||
|
|  |
|
||||||
|
| This is a rough flow chart displaying the program processes made using [Milanote](https://milanote.com/)
|
||||||
|
|
||||||
|
[Back to top](#contents)
|
||||||
|
|
||||||
|
## Features
|
||||||
|
* **Player vs. Computer:** Play against a challenging AI opponent.
|
||||||
|
* **Multiple Board Sizes:** Choose a board size between 5x5 and 9x9.
|
||||||
|
* **High Scores:** Track your best scores and compare them to others.
|
||||||
|
* **Colorful Interface:** Enjoy a visually enhanced gameplay experience with colored console output.
|
||||||
|
* **Leaderboard:** Top scores saved to a Google sheets leaderboard using `Google Docs API` and `gspread`
|
||||||
|
|
||||||
|
[Back to top](#contents)
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
### Replit
|
||||||
|
Most of this project was developed using Replit and so testing was done as I was building the project step by step.
|
||||||
|
|
||||||
|
### Manual Testing
|
||||||
|
The following manual tests were conducted to ensure the application works as expected:
|
||||||
|
|
||||||
|
#### Test 1: Welcome Message
|
||||||
|
**Steps:**
|
||||||
|
1. Run the application.
|
||||||
|
2. Observe the welcome message displayed in the console.
|
||||||
|
|
||||||
|
**Expected Result:**
|
||||||
|
- The welcome message should be centered and displayed with appropriate colors.
|
||||||
|
|
||||||
|
**Actual Result:**
|
||||||
|
- The welcome message is displayed correctly.
|
||||||
|
|
||||||
|
**Screenshot:**
|
||||||
|

|
||||||
|
|
||||||
|
#### Test 2: High Scores Display
|
||||||
|
**Steps:**
|
||||||
|
1. Run the application.
|
||||||
|
2. Observe the high scores displayed after the welcome message.
|
||||||
|
|
||||||
|
**Expected Result:**
|
||||||
|
- The high scores should be displayed in a centered format with appropriate colors.
|
||||||
|
|
||||||
|
**Actual Result:**
|
||||||
|
- The high scores are displayed correctly.
|
||||||
|
|
||||||
|
**Screenshot:**
|
||||||
|

|
||||||
|
|
||||||
|
#### Test 3: Board Size Input
|
||||||
|
**Steps:**
|
||||||
|
1. Run the application.
|
||||||
|
2. Enter a valid board size (between 5 and 9).
|
||||||
|
|
||||||
|
**Expected Result:**
|
||||||
|
- The application should accept the input and proceed to the next step.
|
||||||
|
|
||||||
|
**Actual Result:**
|
||||||
|
- The application accepts valid inputs and proceeds correctly.
|
||||||
|
|
||||||
|
**Screenshot:**
|
||||||
|

|
||||||
|
|
||||||
|
#### Test 4: Invalid Board Size Input
|
||||||
|
**Steps:**
|
||||||
|
1. Run the application.
|
||||||
|
2. Enter an invalid board size (outside the range of 5 to 9).
|
||||||
|
|
||||||
|
**Expected Result:**
|
||||||
|
- The application should display an error message and prompt for input again.
|
||||||
|
|
||||||
|
**Actual Result:**
|
||||||
|
- The application displays an error message and prompts for input again.
|
||||||
|
|
||||||
|
**Screenshot:**
|
||||||
|

|
||||||
|
|
||||||
|
#### Test 5: Player Turn
|
||||||
|
**Steps:**
|
||||||
|
1. Run the application.
|
||||||
|
2. Enter valid coordinates for the player's turn.
|
||||||
|
|
||||||
|
**Expected Result:**
|
||||||
|
- The application should update the board and display the result (hit or miss).
|
||||||
|
|
||||||
|
**Actual Result:**
|
||||||
|
- The application updates the board and displays the result correctly.
|
||||||
|
|
||||||
|
**Screenshot:**
|
||||||
|

|
||||||
|
|
||||||
|
#### Test 6: Computer Turn
|
||||||
|
**Steps:**
|
||||||
|
1. Run the application.
|
||||||
|
2. Observe the computer's turn.
|
||||||
|
|
||||||
|
**Expected Result:**
|
||||||
|
- The application should update the board and display the result (hit or miss).
|
||||||
|
|
||||||
|
**Actual Result:**
|
||||||
|
- The application updates the board and displays the result correctly.
|
||||||
|
|
||||||
|
**Screenshot:**
|
||||||
|

|
||||||
|
|
||||||
|
#### Test 7: Game Over
|
||||||
|
**Steps:**
|
||||||
|
1. Run the application.
|
||||||
|
2. Play the game until either the player or the computer wins.
|
||||||
|
|
||||||
|
**Expected Result:**
|
||||||
|
- The application should display the game over message and the final scores.
|
||||||
|
|
||||||
|
**Actual Result:**
|
||||||
|
- The application displays the game over message and the final scores correctly.
|
||||||
|
|
||||||
|
**Screenshot:**
|
||||||
|

|
||||||
|
|
||||||
|
#### Test 8: Save High Score
|
||||||
|
**Steps:**
|
||||||
|
1. Run the application.
|
||||||
|
2. Win the game and choose to save the high score.
|
||||||
|
3. Enter a name when prompted.
|
||||||
|
|
||||||
|
**Expected Result:**
|
||||||
|
The application should save the high score to the Google Sheets and display a success message.
|
||||||
|
|
||||||
|
**Actual Result:**
|
||||||
|
The application saves the high score and displays the success message correctly.
|
||||||
|
|
||||||
|
**Empty Username:** Players can intentionally leave the username field empty if they prefer not to submit a name. The high score will still be recorded on the leaderboard with a blank entry for the name.
|
||||||
|
|
||||||
|
**Screenshot:**
|
||||||
|

|
||||||
|
|
||||||
|
[Back to top](#contents)
|
||||||
|
|
||||||
|
### PEP 8 Compliance
|
||||||
|
|
||||||
|
The project's Python code has been refactored to improve adherence to PEP 8 style guidelines. This enhances readability and maintainability. Specific improvements include:
|
||||||
|
|
||||||
|
* **Reduced Branching:** Complex conditional logic, particularly in the `display_boards` function, has been simplified to reduce the number of branches, improving code clarity.
|
||||||
|
* **Modernized String Formatting:** F-strings (formatted string literals) have been adopted throughout the codebase for more concise and readable string formatting.
|
||||||
|
* **Removed Redundant Code:** Unnecessary `else` clauses following `return`, `break`, and `continue` statements have been eliminated.
|
||||||
|
* **Import Order:** Imports have been reorganized to follow PEP 8 recommendations (standard library imports first, followed by third-party and then local imports).
|
||||||
|
|
||||||
|
These changes were guided by feedback from the `pylint` static analysis tool.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
[Back to top](#contents)
|
||||||
|
|
||||||
|
|
||||||
|
## Future
|
||||||
|
### Potential Future Features
|
||||||
|
* **Player vs. Player:** Perhaps add functionality to allow for a 2 player turn-based mode
|
||||||
|
* **Various Ship Sizes:** It would be nice to add different dized ships more akin to traditional Battleships game, with a choice of orientation
|
||||||
|
* **Number of Ships:** The added functionality to not only choose the board size but to also choose how many ships on the board would also be an attractive addition to the game
|
||||||
|
* **Choose Ship Placement:** The option to decide where you would like to place your ships on the board would also be a nice future feature to incorporate
|
||||||
|
|
||||||
|
[Back to top](#contents)
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
The site was deployed to Heroku. The steps to deploy are as follows:
|
||||||
|
|
||||||
|
- Set up a [Heroku](https://dashboard.heroku.com) Account and create a new App
|
||||||
|
- In Settings add the python and nodejs buildpacks
|
||||||
|
- In `Settings > Config Vars` Add the creds.json contents under the variable `CREDS`
|
||||||
|
- Link the [GitHub repository](https://github.com/hedgemonkey/battleships) to the Heroku app.
|
||||||
|
|
||||||
|
Heroku git URL
|
||||||
|
[https://git.heroku.com/battleships-hedgemonkey.git]
|
||||||
|
|
||||||
|
The live link can be found [here](https://battleships-hedgemonkey-131f157c44ae.herokuapp.com/)
|
||||||
|
|
||||||
|
[Back to top](#contents)
|
||||||
|
|
||||||
|
### Google Docs
|
||||||
|
This project uses a `Google Sheets` spreadsheet hosted on `Google Docs` accessed by `Google Cloud API` this is to keep track of past scores.
|
||||||
|
|
||||||
|
In order to deploy this yourself you would have to get the correct credentials to access this file or specify your own spreadsheet and provide your own Google Cloud API Credentials
|
||||||
|
|
||||||
|
To do this you ned to save your own credentials to `creds.json` and change the line `SHEET = GSPREAD_CLIENT.open('battleship_scores').sheet1` replacing `battleship_scores` with your own spreadsheet filename
|
||||||
|
|
||||||
|
The spreadsheet can be access [HERE](https://docs.google.com/spreadsheets/d/1cUhnYhy8DuxIEW6_BLnj0OFL38dNoRqmyVvkgnQDai8/edit?usp=sharing)
|
||||||
|
|
||||||
|
[Back to top](#contents)
|
||||||
|
|
||||||
|
### Local Deployment
|
||||||
|
|
||||||
|
You can clone or fork this project to make a local copy on your system.
|
||||||
|
|
||||||
|
[Back to top](#contents)
|
||||||
|
|
||||||
|
#### Cloning
|
||||||
|
|
||||||
|
You can clone the repository by following these steps:
|
||||||
|
|
||||||
|
1. Go to the [GitHub repository](https://github.com/Hedgemonkey/battleships).
|
||||||
|
2. Locate the Code button above the list of files and click it.
|
||||||
|
3. Select if you prefer to clone using HTTPS, SSH, or GitHub CLI and click the copy button to copy the URL to your clipboard.
|
||||||
|
4. Open Git Bash or Terminal.
|
||||||
|
5. Change the current working directory to the one where you want the cloned directory.
|
||||||
|
6. In your IDE Terminal, type the following command to clone my repository:
|
||||||
|
- `git clone https://github.com/hedgemonkey/battleships.git`
|
||||||
|
7. Press Enter to create your local clone.
|
||||||
|
|
||||||
|
[Back to top](#contents)
|
||||||
|
|
||||||
|
#### Forking
|
||||||
|
|
||||||
|
By forking the GitHub Repository, we make a copy of the original repository on our GitHub account to view and/or make changes without affecting the original owner's repository.
|
||||||
|
You can fork this repository by using the following steps:
|
||||||
|
|
||||||
|
1. Log in to GitHub and locate the [GitHub repository](https://github.com/Hedgemonkey/battleships).
|
||||||
|
2. At the top of the Repository (not the top of the page) just above the "Settings" Button on the menu, locate the "Fork" Button.
|
||||||
|
3. Once clicked, you should now have a copy of the original repository in your own GitHub account.
|
||||||
|
|
||||||
|
[Back to top](#contents)
|
||||||
|
|
||||||
|
### Local vs Deployment
|
||||||
|
|
||||||
|
There are no notable differences between my locally developed app and the Heroku deployed site aside from slight variances in the terminal colours.
|
||||||
|
|
||||||
|
[Back to top](#contents)
|
||||||
|
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
In this section, I will reference the sources of my content and media, full disclosure of any resources used shall be detailed here.
|
||||||
|
|
||||||
|
- Milanote used to create Flow Chart Diagram
|
||||||
|
|
||||||
|
- Gemini Pro AI Used to help guide me when code wasn't doing as I intended
|
||||||
|
|
||||||
|
[Back to top](#contents)
|
||||||
|
|
||||||
|
### Content
|
||||||
|
|
||||||
|
[Back to top](#contents)
|
||||||
|
|
||||||
|
### Acknowledgements
|
||||||
|
|
||||||
|
- I would like to thank the [Code Institute Slack community](https://code-institute-room.slack.com) for the moral support and general information that helps with my studies.
|
||||||
|
- I would like to also thank Gemini Pro AI for assisting me whenever I needed a bit of quick advice, although it's suggestions often lead to more complications it's explinations and tips were incredibly helpful
|
||||||
|
- YTMusic for providing me with a soundtrack to work to
|
||||||
|
|
||||||
|
[Back to top](#contents)
|
||||||
60
Battleships/battleships-137-main/controllers/default.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
const Pty = require('node-pty');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
exports.install = function () {
|
||||||
|
|
||||||
|
ROUTE('/');
|
||||||
|
WEBSOCKET('/', socket, ['raw']);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function socket() {
|
||||||
|
|
||||||
|
this.encodedecode = false;
|
||||||
|
this.autodestroy();
|
||||||
|
|
||||||
|
this.on('open', function (client) {
|
||||||
|
|
||||||
|
// Spawn terminal
|
||||||
|
client.tty = Pty.spawn('python3', ['run.py'], {
|
||||||
|
name: 'xterm-color',
|
||||||
|
cols: 80,
|
||||||
|
rows: 24,
|
||||||
|
cwd: process.env.PWD,
|
||||||
|
env: process.env
|
||||||
|
});
|
||||||
|
|
||||||
|
client.tty.on('exit', function (code, signal) {
|
||||||
|
client.tty = null;
|
||||||
|
client.close();
|
||||||
|
console.log("Process killed");
|
||||||
|
});
|
||||||
|
|
||||||
|
client.tty.on('data', function (data) {
|
||||||
|
client.send(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on('close', function (client) {
|
||||||
|
if (client.tty) {
|
||||||
|
client.tty.kill(9);
|
||||||
|
client.tty = null;
|
||||||
|
console.log("Process killed and terminal unloaded");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on('message', function (client, msg) {
|
||||||
|
client.tty && client.tty.write(msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.CREDS != null) {
|
||||||
|
console.log("Creating creds.json file.");
|
||||||
|
fs.writeFile('creds.json', process.env.CREDS, 'utf8', function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.log('Error writing file: ', err);
|
||||||
|
socket.emit("console_output", "Error saving credentials: " + err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
30
Battleships/battleships-137-main/index.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// ===================================================
|
||||||
|
// Total.js start script
|
||||||
|
// https://www.totaljs.com
|
||||||
|
// ===================================================
|
||||||
|
|
||||||
|
const options = {};
|
||||||
|
|
||||||
|
// options.ip = '127.0.0.1';
|
||||||
|
options.port = parseInt(process.env.PORT);
|
||||||
|
// options.unixsocket = require('path').join(require('os').tmpdir(), 'app_name');
|
||||||
|
// options.config = { name: 'Total.js' };
|
||||||
|
// options.sleep = 3000;
|
||||||
|
// options.inspector = 9229;
|
||||||
|
// options.watch = ['private'];
|
||||||
|
// options.livereload = 'https://yourhostname';
|
||||||
|
|
||||||
|
// Enables cluster:
|
||||||
|
// options.cluster = 'auto';
|
||||||
|
// options.cluster_limit = 10; // max 10. threads (works only with "auto" scaling)
|
||||||
|
|
||||||
|
// Enables threads:
|
||||||
|
// options.cluster = 'auto';
|
||||||
|
// options.cluster_limit = 10; // max 10. threads (works only with "auto" scaling)
|
||||||
|
// options.timeout = 5000;
|
||||||
|
// options.threads = '/api/';
|
||||||
|
// options.logs = 'isolated';
|
||||||
|
|
||||||
|
var type = process.argv.indexOf('--release', 1) !== -1 || process.argv.indexOf('release', 1) !== -1 ? 'release' : 'debug';
|
||||||
|
// require('total4/' + type)(options);
|
||||||
|
require('total4').http('release', options);
|
||||||
106
Battleships/battleships-137-main/package-lock.json
generated
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
{
|
||||||
|
"name": "terminal",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "terminal",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"node-pty": "^0.10.1",
|
||||||
|
"node-static": "^0.7.11",
|
||||||
|
"total4": "^0.0.45"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/colors": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.1.90"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"mime": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minimist": {
|
||||||
|
"version": "0.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
|
||||||
|
"integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/nan": {
|
||||||
|
"version": "2.20.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz",
|
||||||
|
"integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/node-pty": {
|
||||||
|
"version": "0.10.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-pty/-/node-pty-0.10.1.tgz",
|
||||||
|
"integrity": "sha512-JTdtUS0Im/yRsWJSx7yiW9rtpfmxqxolrtnyKwPLI+6XqTAPW/O2MjS8FYL4I5TsMbH2lVgDb2VMjp+9LoQGNg==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"nan": "^2.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-static": {
|
||||||
|
"version": "0.7.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-static/-/node-static-0.7.11.tgz",
|
||||||
|
"integrity": "sha512-zfWC/gICcqb74D9ndyvxZWaI1jzcoHmf4UTHWQchBNuNMxdBLJMDiUgZ1tjGLEIe/BMhj2DxKD8HOuc2062pDQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"colors": ">=0.6.0",
|
||||||
|
"mime": "^1.2.9",
|
||||||
|
"optimist": ">=0.3.4"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"static": "bin/cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/optimist": {
|
||||||
|
"version": "0.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
|
||||||
|
"integrity": "sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==",
|
||||||
|
"license": "MIT/X11",
|
||||||
|
"dependencies": {
|
||||||
|
"minimist": "~0.0.1",
|
||||||
|
"wordwrap": "~0.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/total4": {
|
||||||
|
"version": "0.0.45",
|
||||||
|
"resolved": "https://registry.npmjs.org/total4/-/total4-0.0.45.tgz",
|
||||||
|
"integrity": "sha512-96vXqejddbAeNL6zpzbfm8ztiWL4G0fOuoUWniHDlu6oSz+DcxekHkzK0Y9X+ErlHCRTMsP2+ieMTqG6waowiA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"total4": "bin/total4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/wordwrap": {
|
||||||
|
"version": "0.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
|
||||||
|
"integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
Battleships/battleships-137-main/package.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "terminal",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "server.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/lechien73/terminal.git"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/lechien73/terminal/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/lechien73/terminal#readme",
|
||||||
|
"dependencies": {
|
||||||
|
"node-static": "^0.7.11",
|
||||||
|
"node-pty": "^0.10.1",
|
||||||
|
"total4": "^0.0.45"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Battleships/battleships-137-main/readme/board_size.jpg
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
Battleships/battleships-137-main/readme/flow_chart.jpg
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
Battleships/battleships-137-main/readme/flow_chart.png
Normal file
|
After Width: | Height: | Size: 139 KiB |
BIN
Battleships/battleships-137-main/readme/game_over.jpg
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
Battleships/battleships-137-main/readme/player_turn.jpg
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
Battleships/battleships-137-main/readme/pylint_screenshot.jpg
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
Battleships/battleships-137-main/readme/save_high_score.jpg
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
Battleships/battleships-137-main/readme/screenshot.jpg
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
Battleships/battleships-137-main/readme/screenshot.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
Battleships/battleships-137-main/readme/welcome.jpg
Normal file
|
After Width: | Height: | Size: 51 KiB |
20
Battleships/battleships-137-main/requirements.txt
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
cachetools==5.5.0
|
||||||
|
certifi==2024.8.30
|
||||||
|
cffi==1.17.1
|
||||||
|
charset-normalizer==3.3.2
|
||||||
|
cryptography==43.0.1
|
||||||
|
google-auth==2.34.0
|
||||||
|
google-auth-oauthlib==1.2.1
|
||||||
|
google-oauth==1.0.1
|
||||||
|
gspread==6.1.2
|
||||||
|
idna==3.8
|
||||||
|
oauthlib==3.2.2
|
||||||
|
pyasn1==0.6.0
|
||||||
|
pyasn1_modules==0.4.0
|
||||||
|
pycparser==2.22
|
||||||
|
pyOpenSSL==24.2.1
|
||||||
|
requests==2.32.3
|
||||||
|
requests-oauthlib==2.0.0
|
||||||
|
rsa==4.9
|
||||||
|
six==1.16.0
|
||||||
|
urllib3==2.2.2
|
||||||
371
Battleships/battleships-137-main/run.py
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
"""This module is a battleship game"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import string # Corrected import order (see point 14)
|
||||||
|
import random
|
||||||
|
import gspread
|
||||||
|
from google.oauth2.service_account import Credentials
|
||||||
|
|
||||||
|
|
||||||
|
SCOPE = [
|
||||||
|
"https://www.googleapis.com/auth/spreadsheets",
|
||||||
|
"https://www.googleapis.com/auth/drive.file",
|
||||||
|
"https://www.googleapis.com/auth/drive"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
CREDS = Credentials.from_service_account_file('creds.json')
|
||||||
|
SCOPED_CREDS = CREDS.with_scopes(SCOPE)
|
||||||
|
GSPREAD_CLIENT = gspread.authorize(SCOPED_CREDS)
|
||||||
|
SHEET = GSPREAD_CLIENT.open('battleship_scores').sheet1
|
||||||
|
|
||||||
|
|
||||||
|
def center_text(text):
|
||||||
|
"""
|
||||||
|
Function to center text in the console
|
||||||
|
"""
|
||||||
|
console_width = os.get_terminal_size().columns
|
||||||
|
text_length = len(re.sub(r'\x1b\[[0-9;]*m', '', text))
|
||||||
|
padding = (console_width - text_length) // 2
|
||||||
|
return " " * padding + text + " " * padding
|
||||||
|
|
||||||
|
|
||||||
|
def pause():
|
||||||
|
"""
|
||||||
|
Function to pause and clear the screen
|
||||||
|
"""
|
||||||
|
input("\n" + Bcolors.OKCYAN + center_text("Press Enter to continue...") +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
os.system('cls' if os.name == 'nt' else 'clear')
|
||||||
|
|
||||||
|
|
||||||
|
class Bcolors:
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
|
"""
|
||||||
|
Colors for console output
|
||||||
|
"""
|
||||||
|
HEADER = '\033[95m'
|
||||||
|
OKBLUE = '\033[34m'
|
||||||
|
OKCYAN = '\033[96m'
|
||||||
|
OKGREEN = '\033[32m'
|
||||||
|
WARNING = '\033[93m'
|
||||||
|
RED = '\033[31m'
|
||||||
|
ENDC = '\033[0m'
|
||||||
|
BOLD = '\033[1m'
|
||||||
|
UNDERLINE = '\033[4m'
|
||||||
|
|
||||||
|
|
||||||
|
def welcome_message():
|
||||||
|
"""
|
||||||
|
Function to display the welcome message with colors
|
||||||
|
"""
|
||||||
|
print(Bcolors.HEADER +
|
||||||
|
Bcolors.BOLD +
|
||||||
|
center_text("Welcome to Battleships!") +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
print("\n" + Bcolors.BOLD +
|
||||||
|
center_text("Welcome to my simple battleships game!") +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
print("\n" + Bcolors.BOLD +
|
||||||
|
center_text("The aim of the game is to hit your opponents ships" +
|
||||||
|
" in the least trys possible!") +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
print("\n" + Bcolors.BOLD +
|
||||||
|
center_text("Just select a gameboard size between a 5x5 grid and a" +
|
||||||
|
" 9x9 grid!") +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
print("\n" + Bcolors.BOLD +
|
||||||
|
center_text("Then enter the co-ordinates of where you want to" +
|
||||||
|
" shoot when prompted!") +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
|
||||||
|
|
||||||
|
def display_high_scores():
|
||||||
|
"""
|
||||||
|
Function to display top 5 high scores
|
||||||
|
"""
|
||||||
|
print("\n" + Bcolors.HEADER + center_text("Current High Scores") +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
print("\n" + Bcolors.OKCYAN + center_text("Top 5 Lowest Misses:") +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
scores = SHEET.get_all_values()
|
||||||
|
sorted_scores = scores[1:]
|
||||||
|
sorted_scores.sort(key=lambda x: int(x[1]))
|
||||||
|
for i in range(1, 6):
|
||||||
|
if i <= len(sorted_scores):
|
||||||
|
print(center_text(f"{i}. {sorted_scores[i-1][0]}: {
|
||||||
|
sorted_scores[i-1][1]}"))
|
||||||
|
else:
|
||||||
|
print(f"{i}. N/A")
|
||||||
|
|
||||||
|
|
||||||
|
def get_board_size():
|
||||||
|
"""
|
||||||
|
Function to get valid board size input
|
||||||
|
"""
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
size = int(input("Choose board size (5-9): "))
|
||||||
|
if 5 <= size <= 9:
|
||||||
|
return size
|
||||||
|
print("Invalid size. Please enter a number between 5 and 9")
|
||||||
|
except ValueError:
|
||||||
|
print("Invalid input. Please enter a number.")
|
||||||
|
|
||||||
|
|
||||||
|
def create_boards(size):
|
||||||
|
"""
|
||||||
|
Function to create and initialize boards
|
||||||
|
"""
|
||||||
|
player_board = [['O' for _ in range(size)] for _ in range(size)]
|
||||||
|
computer_board = [['O' for _ in range(size)] for _ in range(size)]
|
||||||
|
return player_board, computer_board
|
||||||
|
|
||||||
|
|
||||||
|
def place_ships(board, num_ships):
|
||||||
|
"""
|
||||||
|
Function to place ships randomly
|
||||||
|
"""
|
||||||
|
ship_locations = []
|
||||||
|
for _ in range(num_ships):
|
||||||
|
while True:
|
||||||
|
row = random.randint(0, len(board) - 1)
|
||||||
|
col = random.randint(0, len(board[0]) - 1)
|
||||||
|
if board[row][col] == 'O':
|
||||||
|
board[row][col] = 'S'
|
||||||
|
ship_locations.append((row, col))
|
||||||
|
break
|
||||||
|
return ship_locations
|
||||||
|
|
||||||
|
|
||||||
|
def display_boards(player_board, computer_board):
|
||||||
|
"""
|
||||||
|
Function to display both boards side by side with colors and spacing
|
||||||
|
"""
|
||||||
|
board_size = len(player_board)
|
||||||
|
header_spacing = board_size - 3 - max(0, board_size - 6)
|
||||||
|
print("\n" + center_text(Bcolors.RED + "Player Board " +
|
||||||
|
" "*header_spacing +
|
||||||
|
Bcolors.ENDC + " | " +
|
||||||
|
Bcolors.RED +
|
||||||
|
" Computer Board" +
|
||||||
|
Bcolors.ENDC))
|
||||||
|
print("\n" + center_text(Bcolors.OKCYAN + " " +
|
||||||
|
" ".join([str(i) for i in range(
|
||||||
|
1, board_size + 1)]) +
|
||||||
|
" " + Bcolors.ENDC +
|
||||||
|
" |" +
|
||||||
|
" " + Bcolors.OKCYAN +
|
||||||
|
" ".join([str(i) for i in range(
|
||||||
|
1, board_size + 1)]) +
|
||||||
|
" " +
|
||||||
|
Bcolors.ENDC))
|
||||||
|
letters = list(string.ascii_uppercase[:board_size])
|
||||||
|
for i in range(board_size):
|
||||||
|
player_row = []
|
||||||
|
computer_row = []
|
||||||
|
for j in range(board_size):
|
||||||
|
if player_board[i][j] == 'X':
|
||||||
|
player_row.append(Bcolors.RED +
|
||||||
|
Bcolors.BOLD +
|
||||||
|
'X' +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
elif player_board[i][j] == 'S':
|
||||||
|
player_row.append(Bcolors.OKBLUE +
|
||||||
|
Bcolors.BOLD +
|
||||||
|
'S' +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
elif player_board[i][j] == 'M':
|
||||||
|
player_row.append(Bcolors.OKGREEN +
|
||||||
|
Bcolors.BOLD +
|
||||||
|
'M' +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
else:
|
||||||
|
player_row.append(player_board[i][j])
|
||||||
|
if computer_board[i][j] == 'X':
|
||||||
|
computer_row.append(Bcolors.RED +
|
||||||
|
Bcolors.BOLD +
|
||||||
|
'X' +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
elif computer_board[i][j] == 'M':
|
||||||
|
computer_row.append(Bcolors.OKGREEN +
|
||||||
|
Bcolors.BOLD +
|
||||||
|
'M' +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
else:
|
||||||
|
computer_row.append('O')
|
||||||
|
player_row_str = ' '.join(player_row)
|
||||||
|
computer_row_str = ' '.join(computer_row)
|
||||||
|
row_str = f"{Bcolors.OKCYAN}{letters[i]: <2} {Bcolors.ENDC}{
|
||||||
|
player_row_str: <{len(player_row_str) + 2}} | {
|
||||||
|
Bcolors.OKCYAN}{
|
||||||
|
letters[i]: <2}{
|
||||||
|
Bcolors.ENDC} {
|
||||||
|
computer_row_str: <{len(computer_row_str) + 2}}"
|
||||||
|
print(center_text(row_str))
|
||||||
|
|
||||||
|
|
||||||
|
def get_target(board):
|
||||||
|
"""
|
||||||
|
Function to get valid target coordinates
|
||||||
|
"""
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
row_letter = input(f"Enter row (A-{chr(ord('A') + len(board) - 1)}). ").upper()
|
||||||
|
row = string.ascii_uppercase.index(row_letter.upper())
|
||||||
|
col = int(input(f"Enter column (1-{len(board)}). ")) - 1
|
||||||
|
if 0 <= row < len(board) and 0 <= col < len(board[0]):
|
||||||
|
return row, col
|
||||||
|
print("Invalid coordinates. Please enter numbers within the" +
|
||||||
|
" board size.")
|
||||||
|
except ValueError:
|
||||||
|
print("Invalid input. Please enter letters for Rows and numbers" +
|
||||||
|
" for columns.")
|
||||||
|
|
||||||
|
|
||||||
|
def player_turn(player_board, computer_board, computer_ships, misses):
|
||||||
|
"""
|
||||||
|
Function to handle player's turn
|
||||||
|
"""
|
||||||
|
print(Bcolors.OKBLUE + "\nYour turn:" + Bcolors.ENDC)
|
||||||
|
display_boards(player_board, computer_board)
|
||||||
|
while True:
|
||||||
|
row, col = get_target(computer_board)
|
||||||
|
if computer_board[row][col] == 'M' or computer_board[row][col] == 'X':
|
||||||
|
print(Bcolors.WARNING +
|
||||||
|
"You already tried that target. Choose another one.\n" +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
else:
|
||||||
|
if (row, col) in computer_ships:
|
||||||
|
computer_board[row][col] = 'X'
|
||||||
|
computer_ships.remove((row, col))
|
||||||
|
print(Bcolors.OKGREEN +
|
||||||
|
"Hit! Target: " +
|
||||||
|
chr(ord('A') + row) +
|
||||||
|
" " +
|
||||||
|
str(col + 1) +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
else:
|
||||||
|
computer_board[row][col] = 'M'
|
||||||
|
print(Bcolors.RED +
|
||||||
|
"Miss! Target: " +
|
||||||
|
chr(ord('A') + row) +
|
||||||
|
" " +
|
||||||
|
str(col + 1) +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
misses += 1
|
||||||
|
print(Bcolors.OKCYAN +
|
||||||
|
"\nMisses: " +
|
||||||
|
Bcolors.ENDC +
|
||||||
|
str(misses))
|
||||||
|
break
|
||||||
|
return computer_board, computer_ships, misses
|
||||||
|
|
||||||
|
|
||||||
|
def computer_turn(player_board, player_ships, misses):
|
||||||
|
"""
|
||||||
|
Function to handle computer's turn
|
||||||
|
"""
|
||||||
|
print(Bcolors.OKCYAN + "\nComputer's turn:" + Bcolors.ENDC)
|
||||||
|
while True:
|
||||||
|
row = random.randint(0, len(player_board) - 1)
|
||||||
|
col = random.randint(0, len(player_board[0]) - 1)
|
||||||
|
if player_board[row][col] == 'M' or player_board[row][col] == 'X':
|
||||||
|
continue
|
||||||
|
if (row, col) in player_ships:
|
||||||
|
player_board[row][col] = 'X'
|
||||||
|
player_ships.remove((row, col))
|
||||||
|
print(Bcolors.OKGREEN +
|
||||||
|
"Computer hit! Target: " +
|
||||||
|
chr(ord('A') + row) +
|
||||||
|
" " +
|
||||||
|
str(col + 1) +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
break
|
||||||
|
player_board[row][col] = 'M'
|
||||||
|
print(Bcolors.RED +
|
||||||
|
"Computer missed! Target: " +
|
||||||
|
chr(ord('A') + row) +
|
||||||
|
" " +
|
||||||
|
str(col + 1) +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
misses += 1
|
||||||
|
break
|
||||||
|
pause()
|
||||||
|
return player_board, player_ships, misses
|
||||||
|
|
||||||
|
|
||||||
|
def play_game():
|
||||||
|
"""
|
||||||
|
Function to handle the game loop
|
||||||
|
"""
|
||||||
|
while True:
|
||||||
|
os.system('cl' if os.name == 'nt' else 'clear')
|
||||||
|
welcome_message()
|
||||||
|
display_high_scores()
|
||||||
|
board_size = get_board_size()
|
||||||
|
pause()
|
||||||
|
player_board, computer_board = create_boards(board_size)
|
||||||
|
player_ships = place_ships(player_board, 5)
|
||||||
|
computer_ships = place_ships(computer_board, 5)
|
||||||
|
player_misses = 0
|
||||||
|
computer_misses = 0
|
||||||
|
while player_ships and computer_ships:
|
||||||
|
computer_board, computer_ships, player_misses = player_turn(
|
||||||
|
player_board,
|
||||||
|
computer_board,
|
||||||
|
computer_ships,
|
||||||
|
player_misses)
|
||||||
|
if not computer_ships:
|
||||||
|
print(Bcolors.OKGREEN + "\nCongratulations! You win!" +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
save_to_high_scores(player_misses)
|
||||||
|
break
|
||||||
|
player_board, player_ships, computer_misses = computer_turn(
|
||||||
|
player_board,
|
||||||
|
player_ships,
|
||||||
|
computer_misses)
|
||||||
|
if not player_ships:
|
||||||
|
print(Bcolors.RED + "\nYou lose! Better luck next time." +
|
||||||
|
Bcolors.ENDC)
|
||||||
|
break
|
||||||
|
print("\nFinal Score:")
|
||||||
|
print(f"Player: {player_misses}")
|
||||||
|
print(f"Computer: {computer_misses}")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
play_again = input("\nPlay again? (y/n): ").lower()
|
||||||
|
if play_again in ('y', 'n'):
|
||||||
|
os.system('cls' if os.name == 'nt' else 'clear')
|
||||||
|
break
|
||||||
|
print("Invalid input. Please enter 'y' or 'n'.")
|
||||||
|
if play_again == 'n':
|
||||||
|
print("Goodbye!")
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def save_to_high_scores(misses):
|
||||||
|
"""
|
||||||
|
Function to handle saving scores to the spreadsheet
|
||||||
|
"""
|
||||||
|
while True:
|
||||||
|
save_score = input("Do you want to save your score to the high " +
|
||||||
|
"scores? (y/n): ")
|
||||||
|
if save_score.lower() == 'y':
|
||||||
|
name = input("Enter your name: ")
|
||||||
|
SHEET.append_row([name, misses])
|
||||||
|
os.system('cls' if os.name == 'nt' else 'clear')
|
||||||
|
print("Score saved successfully!")
|
||||||
|
display_high_scores()
|
||||||
|
break
|
||||||
|
if save_score.lower() == 'n':
|
||||||
|
os.system('cls' if os.name == 'nt' else 'clear')
|
||||||
|
print("Score not saved.")
|
||||||
|
display_high_scores()
|
||||||
|
break
|
||||||
|
print("Invalid input. Please enter 'y' or 'n'.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
play_game()
|
||||||
1
Battleships/battleships-137-main/runtime.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
python-3.12.2
|
||||||
27
Battleships/battleships-137-main/views/index.html
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<body>
|
||||||
|
<button onclick="window.location.reload()">Run Program</button>
|
||||||
|
<div id="terminal"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var term = new Terminal({
|
||||||
|
cols: 80,
|
||||||
|
rows: 24
|
||||||
|
});
|
||||||
|
term.open(document.getElementById('terminal'));
|
||||||
|
term.writeln('Running startup command: python3 run.py');
|
||||||
|
term.writeln('');
|
||||||
|
|
||||||
|
var ws = new WebSocket(location.protocol.replace('http', 'ws') + '//' + location.hostname + (location.port ? (
|
||||||
|
':' + location.port) : '') + '/');
|
||||||
|
|
||||||
|
ws.onopen = function () {
|
||||||
|
new attach.attach(term, ws);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onerror = function (e) {
|
||||||
|
console.log(e);
|
||||||
|
};
|
||||||
|
// Set focus in the terminal
|
||||||
|
document.getElementsByClassName("xterm-helper-textarea")[0].focus();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
173
Battleships/battleships-137-main/views/layout.html
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/xterm/3.14.5/xterm.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/xterm/3.14.5/addons/attach/attach.js"></script>
|
||||||
|
<title>Python Terminal by Code Institute</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default styles for xterm.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
.xterm {
|
||||||
|
font-feature-settings: "liga"0;
|
||||||
|
position: relative;
|
||||||
|
user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm.focus,
|
||||||
|
.xterm:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .xterm-helpers {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
/**
|
||||||
|
* The z-index of the helpers must be higher than the canvases in order for
|
||||||
|
* IMEs to appear on top.
|
||||||
|
*/
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .xterm-helper-textarea {
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
/* Move textarea out of the screen to the far left, so that the cursor is not visible */
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
left: -9999em;
|
||||||
|
top: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
z-index: -5;
|
||||||
|
/** Prevent wrapping so the IME appears against the textarea at the correct position */
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .composition-view {
|
||||||
|
/* TODO: Composition position got messed up somewhere */
|
||||||
|
background: #000;
|
||||||
|
color: #FFF;
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
white-space: nowrap;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .composition-view.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .xterm-viewport {
|
||||||
|
/* On OS X this is required in order for the scroll bar to appear fully opaque */
|
||||||
|
background-color: #000;
|
||||||
|
overflow-y: scroll;
|
||||||
|
cursor: default;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgb(0, 0, 0);
|
||||||
|
width: 730px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .xterm-screen {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .xterm-screen canvas {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .xterm-scroll-area {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm-char-measure-element {
|
||||||
|
display: inline-block;
|
||||||
|
visibility: hidden;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: -9999em;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm {
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm.enable-mouse-events {
|
||||||
|
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm.xterm-cursor-pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm.column-select.focus {
|
||||||
|
/* Column selection mode */
|
||||||
|
cursor: crosshair;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .xterm-accessibility,
|
||||||
|
.xterm .xterm-message {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 10;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .live-region {
|
||||||
|
position: absolute;
|
||||||
|
left: -9999px;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm-dim {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm-underline {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 200px;
|
||||||
|
height: 40px;
|
||||||
|
background-color: #E84610;
|
||||||
|
border: 1px solid grey;
|
||||||
|
color: white;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin: 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
@{body}
|
||||||
|
|
||||||
|
</html>
|
||||||
41
Battleships/lesson_1.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# BATTLESHIPS - Grade 7 Python Game
|
||||||
|
# Lesson 2: Full mini-game with 3 ships and turns!
|
||||||
|
|
||||||
|
import random
|
||||||
|
|
||||||
|
# Step 1: Create 3 hidden ships (as a list of [row, col])
|
||||||
|
ships = []
|
||||||
|
while len(ships) < 3:
|
||||||
|
r = random.randint(0, 4)
|
||||||
|
c = random.randint(0, 4)
|
||||||
|
if [r, c] not in ships: # avoid duplicates
|
||||||
|
ships.append([r, c])
|
||||||
|
|
||||||
|
print("3 ships are hidden on a 5x5 grid!")
|
||||||
|
print("You have 10 turns to find them all.")
|
||||||
|
|
||||||
|
hits = 0
|
||||||
|
turns = 10
|
||||||
|
|
||||||
|
# Step 2: Game loop
|
||||||
|
for turn in range(turns):
|
||||||
|
print("\nTurn", turn + 1)
|
||||||
|
|
||||||
|
# Get guess
|
||||||
|
guess_row = int(input("Row (0-4): "))
|
||||||
|
guess_col = int(input("Col (0-4): "))
|
||||||
|
|
||||||
|
# Check if guess is a ship
|
||||||
|
if [guess_row, guess_col] in ships:
|
||||||
|
print("🎯 HIT!")
|
||||||
|
ships.remove([guess_row, guess_col]) # remove found ship
|
||||||
|
hits += 1
|
||||||
|
if hits == 3:
|
||||||
|
print("🏆 You found all ships! You win!")
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print("💦 MISS!")
|
||||||
|
|
||||||
|
# Step 3: Game over message
|
||||||
|
if hits < 3:
|
||||||
|
print("Game over! You found", hits, "out of 3 ships.")
|
||||||
22
Battleships/lesson_2.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# BATTLESHIPS - Grade 7 Python Game
|
||||||
|
# Lesson 1: Find the hidden ship!
|
||||||
|
|
||||||
|
import random
|
||||||
|
|
||||||
|
# Step 1: Create a secret ship location (row 0-4, col 0-4)
|
||||||
|
ship_row = random.randint(0, 4)
|
||||||
|
ship_col = random.randint(0, 4)
|
||||||
|
|
||||||
|
# Step 2: Ask the player for a guess (we'll improve this later!)
|
||||||
|
print("Guess the ship location!")
|
||||||
|
guess_row = int(input("Row (0-4): "))
|
||||||
|
guess_col = int(input("Col (0-4): "))
|
||||||
|
|
||||||
|
# Step 3: Check if they hit the ship
|
||||||
|
if guess_row == ship_row and guess_col == ship_col:
|
||||||
|
print("🎯 HIT! You sank the ship!")
|
||||||
|
else:
|
||||||
|
print("💦 MISS! Try again.")
|
||||||
|
|
||||||
|
# Step 4: (Optional) Show where the ship really was
|
||||||
|
print("The ship was at row", ship_row, "and col", ship_col)
|
||||||