Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
18304a5
Refactor: extract board helpers into board.py
vuppalapati09 Jul 28, 2026
9f7bc75
Clean cache files and rename screenshots
vuppalapati09 Jul 28, 2026
48125d3
Rename screenshots and clean repository
vuppalapati09 Jul 28, 2026
97fdcb5
Refactor: extract validation logic into validator.py
vuppalapati09 Jul 28, 2026
47e052c
Refactor: extract solver logic into solver.py
vuppalapati09 Jul 28, 2026
3920e4c
Refactor: extract puzzle generation into generator.py
vuppalapati09 Jul 28, 2026
5ea6b9a
Feature: add difficulty selector
vuppalapati09 Jul 28, 2026
34537f4
Feature: ensure unique Sudoku solution
vuppalapati09 Jul 28, 2026
8814528
Feature: add game timer
vuppalapati09 Jul 28, 2026
0d5ed84
Feature: add Top 10 leaderboard
vuppalapati09 Jul 28, 2026
83becad
Feature: add hint button
vuppalapati09 Jul 28, 2026
8688f35
Feature: add hint button
vuppalapati09 Jul 28, 2026
d61db33
Feature: add dark mode
vuppalapati09 Jul 28, 2026
233d666
Style: responsive layout and 3x3 block colors
vuppalapati09 Jul 28, 2026
c50e647
Update README and add final screenshots
vuppalapati09 Jul 28, 2026
481c4f7
Add project instructions for refactoring Flask app
vuppalapati09 Jul 28, 2026
55f9ce5
Delete instruction.md
vuppalapati09 Jul 28, 2026
9f6a0a5
Add instruction file
vuppalapati09 Jul 28, 2026
18aafdc
Document Copilot evaluation and refine leaderboard rendering
vuppalapati09 Jul 28, 2026
5183477
Fix review feedback: instruction file, immediate validation, leaderbo…
vuppalapati09 Jul 28, 2026
8947e8e
Update final UI screenshot
vuppalapati09 Jul 28, 2026
de5fa38
Add Copilot rejection evidence
vuppalapati09 Jul 28, 2026
786e03d
Document Copilot evaluation comments
vuppalapati09 Jul 28, 2026
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
16 changes: 12 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Ignore system files
.DS_Store
Thumbs.db
# Python
__pycache__/
*.py[cod]
.pytest_cache/

# Ignore Python virtual environment
# Virtual environment
.venv/

# VS Code
.vscode/

# OS files
.DS_Store
Thumbs.db
128 changes: 128 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,131 @@ 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.


# Sudoku Game (Flask)

A web-based Sudoku game built using Python Flask. The project was refactored into a modular architecture using GitHub Copilot while preserving the original functionality.

## Features

- Generate random Sudoku puzzles
- Three difficulty levels (Easy, Medium, Hard)
- Sudoku solver
- Hint system
- Check solution
- Game timer
- Top 10 leaderboard
- Dark mode
- Responsive UI
- Unique-solution puzzle generation
- Automated testing with Pytest

## Project Structure

```
starter/
│── app.py
│── board.py
│── validator.py
│── solver.py
│── generator.py
│── sudoku_logic.py
│── static/
│── templates/
│── tests/
```

## Installation

Clone the repository.

```bash
git clone https://github.com/vuppalapati09/github-copilot-python.git
```

Move into the project.

```bash
cd github-copilot-python/starter
```

Create a virtual environment.

```bash
python -m venv .venv
```

Activate it.

Windows PowerShell:

```powershell
.\.venv\Scripts\Activate.ps1
```

Install dependencies.

```bash
pip install -r requirements.txt
```

## Run the Application

```bash
python app.py
```

Open:

```
http://127.0.0.1:5000
```

## Run Tests

```bash
pytest -q
```

All tests should pass successfully.

## Refactoring Summary

The application was refactored into separate modules:

- board.py
- validator.py
- solver.py
- generator.py

The original functionality was preserved while improving readability and maintainability.

## Screenshots

### Final Application

![Final UI](starter/screenshots/final_ui.png)

### Copilot Refactoring

![Copilot Refactor](starter/screenshots/copilot_refactor.png)

### Testing Framework

![Testing](starter/screenshots/copilot_testing_framework.png)

## Technologies Used

- Python
- Flask
- HTML
- CSS
- JavaScript
- Pytest
- Git
- GitHub Copilot

## Author

Vuppalapati Surya prakash
Empty file.
Binary file added starter/__pycache__/board.cpython-314.pyc
Binary file not shown.
Binary file added starter/__pycache__/sudoku_logic.cpython-314.pyc
Binary file not shown.
39 changes: 37 additions & 2 deletions starter/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,30 @@
'solution': None
}


def get_clues_for_difficulty(difficulty):
difficulty_map = {
'easy': 45,
'medium': 35,
'hard': 25,
}
if difficulty is None:
return difficulty_map['medium']
normalized = difficulty.lower()
return difficulty_map.get(normalized, difficulty_map['medium'])


@app.route('/')
def index():
return render_template('index.html')

@app.route('/new')
def new_game():
clues = int(request.args.get('clues', 35))
clue_arg = request.args.get('clues')
if clue_arg is not None:
clues = int(clue_arg)
else:
clues = get_clues_for_difficulty(request.args.get('difficulty'))
puzzle, solution = sudoku_logic.generate_puzzle(clues)
CURRENT['puzzle'] = puzzle
CURRENT['solution'] = solution
Expand All @@ -33,7 +50,25 @@ def check_solution():
for j in range(sudoku_logic.SIZE):
if board[i][j] != solution[i][j]:
incorrect.append([i, j])
return jsonify({'incorrect': incorrect})
completed = len(incorrect) == 0
return jsonify({'incorrect': incorrect, 'completed': completed})


@app.route('/hint', methods=['POST'])
def provide_hint():
data = request.json
board = data.get('board')
solution = CURRENT.get('solution')
if solution is None:
return jsonify({'error': 'No game in progress'}), 400

for i in range(sudoku_logic.SIZE):
for j in range(sudoku_logic.SIZE):
if board[i][j] == 0:
return jsonify({'row': i, 'col': j, 'value': solution[i][j]})

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


if __name__ == '__main__':
app.run(debug=True)
12 changes: 12 additions & 0 deletions starter/board.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import copy

SIZE = 9
EMPTY = 0


def deep_copy(board):
return copy.deepcopy(board)


def create_empty_board():
return [[EMPTY for _ in range(SIZE)] for _ in range(SIZE)]
64 changes: 64 additions & 0 deletions starter/generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from board import EMPTY, SIZE, create_empty_board, deep_copy
from solver import fill_board
from validator import is_safe


def remove_cells(board, clues):
import random

attempts = SIZE * SIZE - clues
while attempts > 0:
row = random.randrange(SIZE)
col = random.randrange(SIZE)
if board[row][col] != EMPTY:
board[row][col] = EMPTY
attempts -= 1


def count_solutions(board, limit=2):
board_copy = deep_copy(board)
solutions = 0

def search(state):
nonlocal solutions

if solutions >= limit:
return

next_empty = None
for row in range(SIZE):
for col in range(SIZE):
if state[row][col] == EMPTY:
next_empty = (row, col)
break
if next_empty is not None:
break

if next_empty is None:
solutions += 1
return

row, col = next_empty
for candidate in range(1, SIZE + 1):
if not is_safe(state, row, col, candidate):
continue
state[row][col] = candidate
search(state)
if solutions >= limit:
state[row][col] = EMPTY
return
state[row][col] = EMPTY

search(board_copy)
return solutions


def generate_puzzle(clues=35):
while True:
board = create_empty_board()
fill_board(board)
solution = deep_copy(board)
remove_cells(board, clues)
puzzle = deep_copy(board)
if count_solutions(puzzle, limit=2) == 1:
return puzzle, solution
31 changes: 31 additions & 0 deletions starter/instruction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# GitHub Copilot Instructions

## Project Goal

Refactor the Flask Sudoku application into a clean, modular, and maintainable project while preserving existing functionality.

## Python Guidelines

- Follow PEP 8.
- Use descriptive variable and function names.
- Keep functions small and reusable.
- Avoid duplicate code.
- Add type hints where appropriate.

## Flask Guidelines

- Keep routes thin.
- Move business logic outside app.py.
- Separate UI from game logic.

## Testing

- Run pytest after every major change.
- Preserve all existing functionality.
- Do not introduce breaking changes.

## Refactoring

- Perform small incremental refactoring.
- Preserve backward compatibility.
- Keep public function names unchanged.
2 changes: 2 additions & 0 deletions starter/pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[pytest]
pythonpath = .
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>=8.0
Binary file added starter/screenshots/copilot_completion.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_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_difficulty.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_colors.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.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.
Binary file added starter/screenshots/copilot_refactor.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_rejection.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_rejection_before.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_solver_refactor.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_timer.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_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.
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/final_ui.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.
20 changes: 20 additions & 0 deletions starter/solver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import random

from board import EMPTY, SIZE
from validator import is_safe


def fill_board(board):
for row in range(SIZE):
for col in range(SIZE):
if board[row][col] == EMPTY:
possible = list(range(1, SIZE + 1))
random.shuffle(possible)
for candidate in possible:
if is_safe(board, row, col, candidate):
board[row][col] = candidate
if fill_board(board):
return True
board[row][col] = EMPTY
return False
return True
Loading