diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..32c297c
Binary files /dev/null and b/.DS_Store differ
diff --git a/Battleships/.DS_Store b/Battleships/.DS_Store
new file mode 100644
index 0000000..465823b
Binary files /dev/null and b/Battleships/.DS_Store differ
diff --git a/Battleships/Lesson1.html b/Battleships/Lesson1.html
new file mode 100644
index 0000000..cb25f34
--- /dev/null
+++ b/Battleships/Lesson1.html
@@ -0,0 +1,121 @@
+
+
+
+
+
+ Lesson 1: Battleships in Python!
+
+
+
+
๐ฎ Lesson 1: Find the Hidden Ship!
+
+
+
โ Learning Outcomes
+
+
Use random to create hidden game elements
+
Get input from the player using input()
+
Use if / else to give feedback
+
Run and debug a simple Python program
+
+
+
+
+
๐ก Why It Matters
+
Every video game has hidden logic โ secret levels, random enemies, or treasure locations. Learning to hide and reveal things with code is the first step to making your own games!
+
These same skills are used in apps, quizzes, and even smart home devices!
+
+
+
โฑ๏ธ Lesson Plan (40 minutes)
+
+
+ 0โ5 min โ Demo & Explain
+ Show the game: โThereโs a secret ship! Can you find it?โ
+ Explain: Weโll write code that hides a ship and checks your guess.
+
+
+
+ 5โ20 min โ Code Together
+ Type this starter code (or use your template):
+
+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)
+
+
+
+
+ 20โ35 min โ Test & Improve
+ โข Run the program 3 times
+ โข Try to break it (type a letter instead of number โ what happens?)
+ โข ๐ Challenge: Add a 2nd ship or limit to 3 guesses!
+
+
+
+ 35โ40 min โ Share & Celebrate
+ Pair up! Can your partner guess the ship in 2 tries?
+
+
+
๐ You Just Learned:
+
How to create interactive programs that respond to user choices โ the heart of all games!
+
+
\ No newline at end of file
diff --git a/Battleships/Lesson2.html b/Battleships/Lesson2.html
new file mode 100644
index 0000000..13b9103
--- /dev/null
+++ b/Battleships/Lesson2.html
@@ -0,0 +1,138 @@
+
+
+
+
+
+ Lesson 2: Hunt All the Ships!
+
+
+
+
๐ข Lesson 2: Hunt All the Ships!
+
+
+
โ Learning Outcomes
+
+
Use lists to store multiple ships
+
Create a game loop with turns
+
Track game state (hits, turns)
+
Make decisions with for loops and if inside lists
+
+
+
+
+
๐ก Why It Matters
+
Real games donโt end after one guess! They track score, lives, and progress. Learning to manage game state is how you build Pac-Man, Minecraft, or Roblox games!
+
Lists and loops are used in every programming language โ from apps to robots.
+
+
+
โฑ๏ธ Lesson Plan (40 minutes)
+
+
+ 0โ5 min โ Review & Goal
+ โLast time: 1 ship. Today: 3 ships and 10 turns!โ
+ Show the enhanced game in action.
+
+
+
+ 5โ20 min โ Upgrade Your Code
+ Edit your Lesson 1 file to this:
+
+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.")
+
+
+
+
+ 20โ35 min โ Level Up!
+ โข Test the game (try to win!)
+ โข ๐ Challenge 1: Let players use A, B, C for rows!
+ row_letter = input("Row (A-E): ").upper()
+ guess_row = ord(row_letter) - ord('A')
+ โข ๐ Challenge 2: Show how many turns are left!
+
+
+
+ 35โ40 min โ Play & Reflect
+ Play your friendโs game! What makes it fun?
+ โNow YOU can make games โ not just play them!โ
+
+
+
๐ Youโre Now a Game Coder!
+
Youโve learned the core ideas behind almost every game: hidden objects, player input, feedback, and win/lose conditions.
+
+
\ No newline at end of file
diff --git a/Battleships/battleships-137-main/.DS_Store b/Battleships/battleships-137-main/.DS_Store
new file mode 100644
index 0000000..7f938ab
Binary files /dev/null and b/Battleships/battleships-137-main/.DS_Store differ
diff --git a/Battleships/battleships-137-main/.gitignore b/Battleships/battleships-137-main/.gitignore
new file mode 100644
index 0000000..29c24da
--- /dev/null
+++ b/Battleships/battleships-137-main/.gitignore
@@ -0,0 +1,9 @@
+core.Microsoft*
+core.mongo*
+core.python*
+env.py
+__pycache__/
+*.py[cod]
+node_modules/
+.github/
+creds.json
\ No newline at end of file
diff --git a/Battleships/battleships-137-main/.gitpod.dockerfile b/Battleships/battleships-137-main/.gitpod.dockerfile
new file mode 100644
index 0000000..cb70866
--- /dev/null
+++ b/Battleships/battleships-137-main/.gitpod.dockerfile
@@ -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"
+
+
diff --git a/Battleships/battleships-137-main/.gitpod.yml b/Battleships/battleships-137-main/.gitpod.yml
new file mode 100644
index 0000000..39778f8
--- /dev/null
+++ b/Battleships/battleships-137-main/.gitpod.yml
@@ -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
+
diff --git a/Battleships/battleships-137-main/.replit b/Battleships/battleships-137-main/.replit
new file mode 100644
index 0000000..2bec17a
--- /dev/null
+++ b/Battleships/battleships-137-main/.replit
@@ -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"]
diff --git a/Battleships/battleships-137-main/.vscode/arctictern.py b/Battleships/battleships-137-main/.vscode/arctictern.py
new file mode 100644
index 0000000..bd164ce
--- /dev/null
+++ b/Battleships/battleships-137-main/.vscode/arctictern.py
@@ -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")
diff --git a/Battleships/battleships-137-main/.vscode/heroku_config.sh b/Battleships/battleships-137-main/.vscode/heroku_config.sh
new file mode 100644
index 0000000..5056d45
--- /dev/null
+++ b/Battleships/battleships-137-main/.vscode/heroku_config.sh
@@ -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
diff --git a/Battleships/battleships-137-main/.vscode/init_tasks.sh b/Battleships/battleships-137-main/.vscode/init_tasks.sh
new file mode 100644
index 0000000..c532e38
--- /dev/null
+++ b/Battleships/battleships-137-main/.vscode/init_tasks.sh
@@ -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!"
diff --git a/Battleships/battleships-137-main/.vscode/make_url.py b/Battleships/battleships-137-main/.vscode/make_url.py
new file mode 100644
index 0000000..1a27167
--- /dev/null
+++ b/Battleships/battleships-137-main/.vscode/make_url.py
@@ -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}")
diff --git a/Battleships/battleships-137-main/.vscode/settings.json b/Battleships/battleships-137-main/.vscode/settings.json
new file mode 100644
index 0000000..c683001
--- /dev/null
+++ b/Battleships/battleships-137-main/.vscode/settings.json
@@ -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"
+}
\ No newline at end of file
diff --git a/Battleships/battleships-137-main/.vscode/uptime.sh b/Battleships/battleships-137-main/.vscode/uptime.sh
new file mode 100644
index 0000000..25a37f8
--- /dev/null
+++ b/Battleships/battleships-137-main/.vscode/uptime.sh
@@ -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
diff --git a/Battleships/battleships-137-main/Procfile b/Battleships/battleships-137-main/Procfile
new file mode 100644
index 0000000..5ec9cc2
--- /dev/null
+++ b/Battleships/battleships-137-main/Procfile
@@ -0,0 +1 @@
+web: node index.js
\ No newline at end of file
diff --git a/Battleships/battleships-137-main/README.md b/Battleships/battleships-137-main/README.md
new file mode 100644
index 0000000..5458730
--- /dev/null
+++ b/Battleships/battleships-137-main/README.md
@@ -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
+
+
+Click here for Table of Contents
+
+[Screenshots](#screenshots)
+
+[Flow Chart Screenshots](#flow-chart-screenshots)
+
+[Features](#features)
+
+[Testing](#testing)
+
+[Future](#future)
+
+[Deployment](#deployment)
+
+[Credits](#credits)
+
+
+
+## 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)
\ No newline at end of file
diff --git a/Battleships/battleships-137-main/controllers/default.js b/Battleships/battleships-137-main/controllers/default.js
new file mode 100644
index 0000000..96ffdd4
--- /dev/null
+++ b/Battleships/battleships-137-main/controllers/default.js
@@ -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);
+ }
+ });
+}
\ No newline at end of file
diff --git a/Battleships/battleships-137-main/index.js b/Battleships/battleships-137-main/index.js
new file mode 100644
index 0000000..2598955
--- /dev/null
+++ b/Battleships/battleships-137-main/index.js
@@ -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);
\ No newline at end of file
diff --git a/Battleships/battleships-137-main/package-lock.json b/Battleships/battleships-137-main/package-lock.json
new file mode 100644
index 0000000..29dfbf0
--- /dev/null
+++ b/Battleships/battleships-137-main/package-lock.json
@@ -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"
+ }
+ }
+ }
+}
diff --git a/Battleships/battleships-137-main/package.json b/Battleships/battleships-137-main/package.json
new file mode 100644
index 0000000..56ca191
--- /dev/null
+++ b/Battleships/battleships-137-main/package.json
@@ -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"
+ }
+}
\ No newline at end of file
diff --git a/Battleships/battleships-137-main/readme/board_size.jpg b/Battleships/battleships-137-main/readme/board_size.jpg
new file mode 100644
index 0000000..076b19d
Binary files /dev/null and b/Battleships/battleships-137-main/readme/board_size.jpg differ
diff --git a/Battleships/battleships-137-main/readme/flow_chart.jpg b/Battleships/battleships-137-main/readme/flow_chart.jpg
new file mode 100644
index 0000000..61c9d05
Binary files /dev/null and b/Battleships/battleships-137-main/readme/flow_chart.jpg differ
diff --git a/Battleships/battleships-137-main/readme/flow_chart.png b/Battleships/battleships-137-main/readme/flow_chart.png
new file mode 100644
index 0000000..b548883
Binary files /dev/null and b/Battleships/battleships-137-main/readme/flow_chart.png differ
diff --git a/Battleships/battleships-137-main/readme/game_over.jpg b/Battleships/battleships-137-main/readme/game_over.jpg
new file mode 100644
index 0000000..1b04466
Binary files /dev/null and b/Battleships/battleships-137-main/readme/game_over.jpg differ
diff --git a/Battleships/battleships-137-main/readme/player_turn.jpg b/Battleships/battleships-137-main/readme/player_turn.jpg
new file mode 100644
index 0000000..805afc8
Binary files /dev/null and b/Battleships/battleships-137-main/readme/player_turn.jpg differ
diff --git a/Battleships/battleships-137-main/readme/pylint_screenshot.jpg b/Battleships/battleships-137-main/readme/pylint_screenshot.jpg
new file mode 100644
index 0000000..681e940
Binary files /dev/null and b/Battleships/battleships-137-main/readme/pylint_screenshot.jpg differ
diff --git a/Battleships/battleships-137-main/readme/save_high_score.jpg b/Battleships/battleships-137-main/readme/save_high_score.jpg
new file mode 100644
index 0000000..6686f44
Binary files /dev/null and b/Battleships/battleships-137-main/readme/save_high_score.jpg differ
diff --git a/Battleships/battleships-137-main/readme/screenshot.jpg b/Battleships/battleships-137-main/readme/screenshot.jpg
new file mode 100644
index 0000000..936bab8
Binary files /dev/null and b/Battleships/battleships-137-main/readme/screenshot.jpg differ
diff --git a/Battleships/battleships-137-main/readme/screenshot.png b/Battleships/battleships-137-main/readme/screenshot.png
new file mode 100644
index 0000000..8ee4d02
Binary files /dev/null and b/Battleships/battleships-137-main/readme/screenshot.png differ
diff --git a/Battleships/battleships-137-main/readme/welcome.jpg b/Battleships/battleships-137-main/readme/welcome.jpg
new file mode 100644
index 0000000..cbe24ca
Binary files /dev/null and b/Battleships/battleships-137-main/readme/welcome.jpg differ
diff --git a/Battleships/battleships-137-main/requirements.txt b/Battleships/battleships-137-main/requirements.txt
new file mode 100644
index 0000000..84f6cf3
--- /dev/null
+++ b/Battleships/battleships-137-main/requirements.txt
@@ -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
diff --git a/Battleships/battleships-137-main/run.py b/Battleships/battleships-137-main/run.py
new file mode 100644
index 0000000..59e29ad
--- /dev/null
+++ b/Battleships/battleships-137-main/run.py
@@ -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()
diff --git a/Battleships/battleships-137-main/runtime.txt b/Battleships/battleships-137-main/runtime.txt
new file mode 100644
index 0000000..b884b0f
--- /dev/null
+++ b/Battleships/battleships-137-main/runtime.txt
@@ -0,0 +1 @@
+python-3.12.2
\ No newline at end of file
diff --git a/Battleships/battleships-137-main/views/index.html b/Battleships/battleships-137-main/views/index.html
new file mode 100644
index 0000000..6e6c1ac
--- /dev/null
+++ b/Battleships/battleships-137-main/views/index.html
@@ -0,0 +1,27 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Battleships/battleships-137-main/views/layout.html b/Battleships/battleships-137-main/views/layout.html
new file mode 100644
index 0000000..aaec1c9
--- /dev/null
+++ b/Battleships/battleships-137-main/views/layout.html
@@ -0,0 +1,173 @@
+
+
+
+
+
+
+
+
+
+
+ Python Terminal by Code Institute
+
+
+
+@{body}
+
+
\ No newline at end of file
diff --git a/Battleships/lesson_1.py b/Battleships/lesson_1.py
new file mode 100644
index 0000000..0eb0f6f
--- /dev/null
+++ b/Battleships/lesson_1.py
@@ -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.")
\ No newline at end of file
diff --git a/Battleships/lesson_2.py b/Battleships/lesson_2.py
new file mode 100644
index 0000000..6b34463
--- /dev/null
+++ b/Battleships/lesson_2.py
@@ -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)
\ No newline at end of file