Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added starter/My_Project.zip
Binary file not shown.
Binary file added starter/__pycache__/sudoku_logic.cpython-313.pyc
Binary file not shown.
174 changes: 149 additions & 25 deletions starter/app.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,163 @@
"""
Flask Sudoku Application

This file contains the Flask routes that power the Sudoku game.
It handles puzzle generation, solution checking, hints,
real-time validation and communication with the frontend.
"""

from flask import Flask, render_template, jsonify, request
import sudoku_logic

app = Flask(__name__)

# Keep a simple in-memory store for current puzzle and solution
# Stores the current puzzle and its solution in memory.
CURRENT = {
'puzzle': None,
'solution': None
"puzzle": None,
"solution": None
}

@app.route('/')

@app.route("/")
def index():
return render_template('index.html')
"""
Render the main Sudoku game page.
"""
return render_template("index.html")

@app.route('/new')

@app.route("/new")
def new_game():
clues = int(request.args.get('clues', 35))
puzzle, solution = sudoku_logic.generate_puzzle(clues)
CURRENT['puzzle'] = puzzle
CURRENT['solution'] = solution
return jsonify({'puzzle': puzzle})
"""
Generate a new Sudoku puzzle.

Query Parameters:
clues (int): Number of visible cells.

Returns:
JSON response containing the generated puzzle.
"""
try:
clues = int(request.args.get("clues", 35))

if clues < 20 or clues > 60:
return jsonify({"error": "Clues must be between 20 and 60."}), 400

puzzle, solution = sudoku_logic.generate_puzzle(clues)

CURRENT["puzzle"] = puzzle
CURRENT["solution"] = solution

return jsonify({"puzzle": puzzle})

except ValueError:
return jsonify({"error": "Invalid clues value."}), 400

@app.route('/check', methods=['POST'])
except Exception as error:
print(f"Error generating puzzle: {error}")
return jsonify({"error": "Unable to generate puzzle."}), 500


@app.route("/check", methods=["POST"])
def check_solution():
data = request.json
board = data.get('board')
solution = CURRENT.get('solution')
if solution is None:
return jsonify({'error': 'No game in progress'}), 400
incorrect = []
for i in range(sudoku_logic.SIZE):
for j in range(sudoku_logic.SIZE):
if board[i][j] != solution[i][j]:
incorrect.append([i, j])
return jsonify({'incorrect': incorrect})

if __name__ == '__main__':
"""
Compare the player's board with the solution.

Returns:
List of incorrect cell coordinates.
"""
try:
data = request.get_json()

if not data or "board" not in data:
return jsonify({"error": "Board data is missing."}), 400

board = data["board"]

solution = CURRENT.get("solution")

if solution is None:
return jsonify({"error": "No active game."}), 400

incorrect = []

for i in range(sudoku_logic.SIZE):
for j in range(sudoku_logic.SIZE):
if board[i][j] != solution[i][j]:
incorrect.append([i, j])

return jsonify({"incorrect": incorrect})

except Exception as error:
print(f"Check error: {error}")
return jsonify({"error": "Unable to check solution."}), 500


@app.route("/hint")
def hint():
"""
Reveal one correct cell and lock it.

Returns:
JSON containing row, column and value.
"""
try:
puzzle = CURRENT.get("puzzle")
solution = CURRENT.get("solution")

if puzzle is None or solution is None:
return jsonify({"error": "No active game."}), 400

for i in range(sudoku_logic.SIZE):
for j in range(sudoku_logic.SIZE):

if puzzle[i][j] == 0:
puzzle[i][j] = solution[i][j]

return jsonify({
"row": i,
"col": j,
"value": solution[i][j]
})

return jsonify({"error": "Puzzle already complete."}), 400

except Exception as error:
print(f"Hint error: {error}")
return jsonify({"error": "Unable to generate hint."}), 500


@app.route("/validate", methods=["POST"])
def validate():
"""
Validate a single Sudoku cell.

Returns:
JSON indicating whether the entered value is correct.
"""
try:
data = request.get_json()

if not data:
return jsonify({"error": "Missing request data."}), 400

row = data.get("row")
col = data.get("col")
value = data.get("value")

solution = CURRENT.get("solution")

if solution is None:
return jsonify({"error": "No active game."}), 400

return jsonify({
"correct": solution[row][col] == value
})

except Exception as error:
print(f"Validation error: {error}")
return jsonify({"error": "Validation failed."}), 500


if __name__ == "__main__":
app.run(debug=True)
47 changes: 47 additions & 0 deletions starter/instruction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# GitHub Copilot Instructions

## Project
Refactor a legacy Python Flask Sudoku application into a modern, maintainable web application.

## Coding Standards

- Use Python best practices (PEP 8).
- Write modular and reusable functions.
- Keep functions small and focused.
- Add comments where logic is complex.
- Handle errors gracefully.
- Do not duplicate code.
- Prefer readability over clever code.

## Sudoku Requirements

- Generate puzzles with exactly one unique solution.
- Support Easy, Medium and Hard difficulty levels.
- Lock all prefilled cells.
- Validate user moves.
- Provide Hint and Check features.
- Display a completion message.
- Maintain a Top 10 leaderboard using browser local storage.
- Support dark mode.
- Display a timer.

## Frontend

- Use responsive design.
- Alternate colours for each 3×3 Sudoku block.
- Keep the UI usable in both light and dark themes.

## Testing

- Use pytest.
- Ensure existing functionality continues to work after refactoring.

## Copilot Guidance

When suggesting code:

- Explain complex logic.
- Prefer modular implementations.
- Avoid unnecessary libraries.
- Keep Flask routes simple.
- Write maintainable code.
Binary file added starter/screenshots/copilot_dark_mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added starter/screenshots/copilot_grid_styling.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added starter/screenshots/copilot_hint_button.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added starter/screenshots/copilot_leaderboard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added starter/screenshots/copilot_unique_solution.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added starter/screenshots/initial_tests.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading