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
60 changes: 60 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,63 @@ Use GitHub Copilot to refactor the code for this game to add more advanced featu
- The game should be responsive and work well on both desktop and mobile devices.
- UI colors should be visually appealing and accessible.
- Completed and correct puzzles should display a congratulatory message with the time taken and hints used and ask for the user's name for Top 10 times.

## Running the Tests

Run the test suite with:

```bash
python -m pytest -q
```

## Features Implemented

- Sudoku puzzle generator with a unique solution
- Difficulty selector (Easy, Medium, Hard)
- Timer
- Hint button
- Check Puzzle button
- Immediate feedback for invalid entries
- Top 10 leaderboard using browser localStorage
- Dark mode
- Responsive design
- Congratulatory message when the puzzle is solved

## Code Quality

The legacy Sudoku application was refactored into modular and reusable components.

- Game generation and validation logic are separated into `sudoku_logic.py`.
- Flask routes are implemented in `app.py`.
- HTML templates are organized in the `templates` folder.
- CSS and JavaScript are organized in the `static` folder.
- Automated tests are stored in the `tests` folder.

The application uses consistent error handling by returning appropriate JSON error messages for invalid requests or when no active game is available.

All functionality was verified by running the application and executing the pytest test suite after each major feature was added.

## Comments and Documentation

Comments were added to explain important sections of the application, including:

- Sudoku puzzle generation
- Unique solution validation
- Hint generation
- Solution checking
- Flask routes

These comments improve readability and make the project easier to understand and maintain. Consistent naming conventions and formatting were followed throughout the project.

## Screenshots

The `Screenshots` folder contains GitHub Copilot conversations for the major development milestones, including:

- `copilot_testing_framework.png`
- `copilot_unique_solution_prompt.png`
- `copilot_top10_scores.png`
- `copilot_grid_styling.png`
- `copilot_timer.png`
- `copilot_darkmode.png`
- `copilot_hint.png`
- `copilot_check_puzzle.png`
Binary file added starter/__pycache__/app.cpython-314.pyc
Binary file not shown.
Binary file added starter/__pycache__/sudoku_logic.cpython-314.pyc
Binary file not shown.
39 changes: 32 additions & 7 deletions starter/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,28 @@
import sudoku_logic

app = Flask(__name__)

# Keep a simple in-memory store for current puzzle and solution
# Store the current game state, including the puzzle, solution, and difficulty.
CURRENT = {
'puzzle': None,
'solution': None
'solution': None,
'difficulty': 'medium',
}

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

# Start a new Sudoku game using the selected difficulty
@app.route('/new')
def new_game():
clues = int(request.args.get('clues', 35))
puzzle, solution = sudoku_logic.generate_puzzle(clues)
difficulty = request.args.get('difficulty', 'medium').lower()
puzzle, solution = sudoku_logic.generate_puzzle(difficulty=difficulty)
CURRENT['puzzle'] = puzzle
CURRENT['solution'] = solution
return jsonify({'puzzle': puzzle})
CURRENT['difficulty'] = difficulty
return jsonify({'puzzle': puzzle, 'difficulty': difficulty})

# Compare the player's board with the correct solution
@app.route('/check', methods=['POST'])
def check_solution():
data = request.json
Expand All @@ -35,5 +38,27 @@ def check_solution():
incorrect.append([i, j])
return jsonify({'incorrect': incorrect})

# Return one valid hint for an empty cell
@app.route('/hint', methods=['POST'])
def get_hint():
data = request.json
board = data.get('board')
solution = CURRENT.get('solution')
current_puzzle = CURRENT.get('puzzle')

if solution is None or current_puzzle is None:
return jsonify({'error': 'No game in progress'}), 400

board_to_update = current_puzzle if board is None else board
for i in range(sudoku_logic.SIZE):
for j in range(sudoku_logic.SIZE):
if board_to_update[i][j] == 0:
value = solution[i][j]
board_to_update[i][j] = value
CURRENT['puzzle'] = board_to_update
return jsonify({'row': i, 'col': j, 'value': value})

return jsonify({'error': 'No empty cells left'}), 400

if __name__ == '__main__':
app.run(debug=True)
4 changes: 4 additions & 0 deletions starter/inspect_html.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import requests
html = requests.get('http://127.0.0.1:5000/').text
print('has select', 'id="difficulty"' in html)
print('has script', '/static/main.js' in html)
7 changes: 7 additions & 0 deletions starter/inspect_solver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import sudoku_logic as s
board = [[8,6,4,5,2,9,7,3,1],[3,5,1,7,4,8,9,2,6],[9,7,2,6,3,1,8,4,5],[4,1,3,8,9,7,5,6,2],[6,9,8,4,5,2,1,7,3],[5,2,7,1,6,3,4,9,8],[7,8,6,2,1,4,3,5,9],[2,4,9,3,8,5,6,1,7],[1,3,5,9,7,6,2,8,4]]
board[0][0] = 0
print('safe 8', s.is_safe(board, 0, 0, 8))
print('safe 7', s.is_safe(board, 0, 0, 7))
print('empties', [(r, c) for r in range(9) for c in range(9) if board[r][c] == 0])
print('solutions', s.count_solutions(board, limit=2))
57 changes: 57 additions & 0 deletions starter/instruction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# GitHub Copilot Instructions

## Project Overview
This project is a Flask-based Sudoku game refactored using GitHub Copilot.

## Coding Style
- Use modern Python and Flask best practices.
- Keep functions small and reusable.
- Follow consistent naming conventions.
- Add comments for important logic.
- Avoid duplicate code.

## Project Structure
- Keep game logic in `sudoku_logic.py`.
- Keep Flask routes in `app.py`.
- Keep HTML templates inside `templates/`.
- Keep CSS and JavaScript inside `static/`.
- Store tests inside the `tests/` folder.

## Testing
- Write or update pytest tests for new functionality.
- Ensure all tests pass before submitting changes.

## UI Guidelines
- Keep the interface responsive.
- Support both light and dark mode.
- Maintain consistent styling across components.

## Error Handling
- Return meaningful error messages.
- Handle invalid user input gracefully.

## Copilot Guidance
When suggesting code:
- Reuse existing project patterns.
- Preserve existing functionality.
- Explain major code changes before applying them.
- Prefer clean, readable, and maintainable code.

## Refactor Legacy Code to Modern Standards

### Modular Design
- Break code into reusable, single-responsibility components.
- Separate Sudoku game logic, Flask routes, UI rendering, validation, and leaderboard logic.
- Reuse helper functions instead of duplicating code.
- Keep functions small, focused, and easy to test.

### Documentation
- Add comments for complex algorithms such as Sudoku generation, unique solution checking, hint generation, and puzzle validation.
- Use meaningful variable and function names.
- Keep formatting and naming consistent throughout the project.

### Error Handling
- Validate all user inputs before processing.
- Return meaningful JSON error messages from Flask routes.
- Handle missing game state or invalid requests gracefully.
- Avoid crashes by checking for invalid or empty values.
2 changes: 2 additions & 0 deletions starter/pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[pytest]
testpaths = tests
1 change: 1 addition & 0 deletions starter/requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
Flask>=2.0
pytest>=7.0
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_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.
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_feature.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.
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_timer_feature.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.
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