Name | sudoku-mip-solver JSON |
Version |
0.2.0
JSON |
| download |
home_page | None |
Summary | A Sudoku puzzle solver and generator using Mixed Integer Programming (MIP) |
upload_time | 2025-07-13 20:59:39 |
maintainer | None |
docs_url | None |
author | Rasmus Ørnstrup Mikkelsen |
requires_python | >=3.9 |
license | MIT License
Copyright (c) 2025 Rasmus Ørnstrup Mikkelsen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
|
keywords |
|
VCS |
 |
bugtrack_url |
|
requirements |
pulp
pytest
|
Travis-CI |
No Travis.
|
coveralls test coverage |
|
# Sudoku MIP Solver
[](https://github.com/DenHvideDvaerg/sudoku-mip-solver/actions/workflows/CI.yml)
[](https://github.com/DenHvideDvaerg/sudoku-mip-solver/actions/workflows/CI.yml?query=branch%3Amain+is%3Asuccess)
[](https://pypi.org/project/sudoku-mip-solver/)
A Sudoku puzzle solver and generator using Mixed Integer Programming (MIP).
## Table of Contents
- [Features](#features)
- [Installation](#installation)
- [Requirements](#requirements)
- [Quick Start](#quick-start)
- [Command Line Interface](#command-line-interface)
- [SudokuMIPSolver API](#sudokumipsolver-api)
- [Examples](#examples)
- [License](#license)
## Features
This package provides tools to:
- Solve Sudoku puzzles of any size using MIP optimization techniques
- Generate random Sudoku puzzles with varying difficulty levels
- Find all possible solutions for a given puzzle
- Support non-standard Sudoku grid dimensions (e.g., 12x12 with 4x3 sub-grids)
## Installation
```bash
pip install sudoku-mip-solver
```
## Requirements
- Python 3.9+
- PuLP (for the MIP solver)
## Quick Start
```python
from sudoku_mip_solver import SudokuMIPSolver
# Create a solver from a string representation of a 9x9 puzzle
puzzle_string = "530070000600195000098000060800060003400803001700020006060000280000419005000080079"
solver = SudokuMIPSolver.from_string(puzzle_string)
# Solve the puzzle
if solver.solve():
solver.pretty_print(solver.get_solution())
else:
print("No solution found!")
# Generate a random puzzle
new_solver, difficulty = SudokuMIPSolver.generate_random_puzzle(
sub_grid_width=3,
sub_grid_height=3,
target_difficulty=0.75
)
print(f"Generated puzzle with difficulty {difficulty:.2f}:")
new_solver.pretty_print(new_solver.board)
```
## Command Line Interface
The package includes a command-line interface for solving and generating puzzles.
### Basic Usage
```bash
# Display the version of the package
sudoku-mip-solver --version
# Solve a puzzle provided as a string
sudoku-mip-solver -s "530070000600195000098000060800060003400803001700020006060000280000419005000080079"
# Read a puzzle from a file
sudoku-mip-solver -f puzzle.txt
# Generate a random puzzle with medium difficulty
sudoku-mip-solver
# Generate but don't solve a puzzle
sudoku-mip-solver --generate-only
# Find all solutions to a puzzle
sudoku-mip-solver -f puzzle.txt -m -1
# Solve a non-standard 6x6 puzzle (2x3 sub-grids)
sudoku-mip-solver -s "530070600195098000" -w 2 -H 3
```
### Command Line Options
#### Input Options
| Option | Description |
| ------ | ----------- |
| `-s`, `--string` | Input puzzle as a string |
| `-f`, `--file` | Path to a file containing the puzzle |
| `--generate-only` | Generate a random puzzle without solving it |
#### Grid Dimensions
| Option | Description |
| ------ | ----------- |
| `-w`, `--width` | Width of each sub-grid (default: 3) |
| `-H`, `--height` | Height of each sub-grid (default: same as width) |
#### Random Puzzle Options
| Option | Description |
| ------ | ----------- |
| `-d`, `--difficulty` | Controls number of clues (0.0=easiest, 1.0=hardest, default: 0.75) |
| `--non-unique` | Skip uniqueness check, allowing multiple solutions |
#### Solver Options
| Option | Description |
| ------ | ----------- |
| `-m`, `--max-solutions` | Maximum solutions to find (default: 1, use -1 for all) |
#### Output Options
| Option | Description |
| ------ | ----------- |
| `-o`, `--output` | Save the solution or generated puzzle to a file |
| `-v`, `--verbose` | Show detailed solver information |
| `-q`, `--quiet` | Suppress all output except error messages |
| `--version` | Display the version number of the package |
## SudokuMIPSolver API
### Creating a Solver
```python
# From a 2D array
board = [[5,3,0,0,7,0,0,0,0],
[6,0,0,1,9,5,0,0,0],
# ... (additional rows)
]
solver = SudokuMIPSolver(board, sub_grid_width=3, sub_grid_height=3)
# From a string representation
solver = SudokuMIPSolver.from_string("530070000...", sub_grid_width=3)
# Generate a random puzzle
solver, difficulty = SudokuMIPSolver.generate_random_puzzle(
sub_grid_width=3,
sub_grid_height=3,
target_difficulty=0.75,
unique_solution=True
)
```
### Core Methods
| Method | Description |
| ------ | ----------- |
| `build_model()` | Build the MIP model with all Sudoku constraints |
| `solve(show_output=False)` | Solve the puzzle and return True if solution found |
| `find_all_solutions(max_solutions=None)` | Find all solutions (or up to max_solutions) |
| `get_solution()` | Get the current solution |
| `reset_model()` | Remove all solution cuts, restoring original constraints |
### Utility Methods
| Method | Description |
| ------ | ----------- |
| `to_string(board=None, delimiter=None)` | Convert board to string representation |
| `get_pretty_string(board=None)` | Get the board as a formatted string with grid lines showing sub-grids |
| `pretty_print(board=None)` | Print the board with grid lines showing sub-grids |
| `extract_solution()` | Extract solution from model variables |
| `print_model()` | Print the model in a readable format |
### Class Methods
| Method | Description |
| ------ | ----------- |
| `from_string(sudoku_string, sub_grid_width=3, sub_grid_height=None, delimiter=None)` | Create solver from string representation |
| `generate_random_puzzle(sub_grid_width=3, sub_grid_height=None, target_difficulty=0.75, unique_solution=True, max_attempts=100, random_seed=None)` | Generate a random puzzle with specified parameters |
### Algorithm Details
The solver uses Mixed Integer Programming (MIP) to model and solve Sudoku puzzles:
1. **Decision Variables**: Binary variables x[i,j,k] representing whether cell (i,j) contains value k
2. **Constraints**:
- Each cell must contain exactly one value
- Each row must contain all values exactly once
- Each column must contain all values exactly once
- Each sub-grid must contain all values exactly once
- Initial clues are fixed to their given values
3. **Solution Finding**:
- The MIP solver (provided by PuLP) finds a feasible solution satisfying all constraints
- For multiple solutions, solution cuts are added to exclude previously found solutions
The random puzzle generator works by:
1. Creating a complete, solved Sudoku grid
2. Systematically removing values while ensuring the puzzle maintains a unique solution
3. Continuing removal until the target difficulty level is reached
## Examples
### Solving a Puzzle
```python
# Standard 9x9 puzzle
puzzle = "530070000600195000098000060800060003400803001700020006060000280000419005000080079"
solver = SudokuMIPSolver.from_string(puzzle)
solver.solve()
solver.pretty_print(solver.get_solution())
```
### Getting Formatted Output as String
```python
# Get the formatted puzzle as a string instead of printing directly
puzzle = "530070000600195000098000060800060003400803001700020006060000280000419005000080079"
solver = SudokuMIPSolver.from_string(puzzle)
solver.solve()
# Get the formatted string
formatted_solution = solver.get_pretty_string(solver.get_solution())
print("Solution:")
print(formatted_solution)
# You can also save it to a file or process it further
with open("solution.txt", "w") as f:
f.write(formatted_solution)
```
### Finding Multiple Solutions
```python
# Find all solutions to an under-constrained puzzle
puzzle = "123456789000000000000000000000000000000000000000000000000000000000000000000000000"
solver = SudokuMIPSolver.from_string(puzzle)
solutions = solver.find_all_solutions(max_solutions=5) # Limit to 5 solutions
print(f"Found {len(solutions)} solutions")
```
### Working with Non-Standard Grids
```python
# Create a 6x6 puzzle with 2x3 sub-grids
puzzle = "123456000000000000000000000000000000"
solver = SudokuMIPSolver.from_string(puzzle, sub_grid_width=2, sub_grid_height=3)
solver.solve()
solver.pretty_print(solver.get_solution())
```
### Generating Puzzles with Different Difficulties
The `target_difficulty` parameter controls the number of clues in the generated puzzle:
- 0.0 = maximum clues (easiest puzzles)
- 1.0 = minimum clues (hardest puzzles)
For standard 9×9 Sudoku puzzles, a difficulty of 1.0 targets the theoretical minimum of 17 clues (mathematically proven lower bound). For puzzles of other sizes, the minimum is (wrongly) estimated as N clues for an N×N grid.
```python
# Very easy puzzle (more clues)
easy_solver, difficulty = SudokuMIPSolver.generate_random_puzzle(target_difficulty=0.3)
print(f"Easy puzzle (difficulty: {difficulty:.2f})")
easy_solver.pretty_print(easy_solver.board)
# Harder puzzle (fewer clues)
hard_solver, difficulty = SudokuMIPSolver.generate_random_puzzle(target_difficulty=0.9)
print(f"Hard puzzle (difficulty: {difficulty:.2f})")
hard_solver.pretty_print(hard_solver.board)
```
## License
This project is licensed under the [MIT License](LICENSE).
Raw data
{
"_id": null,
"home_page": null,
"name": "sudoku-mip-solver",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": null,
"author": "Rasmus \u00d8rnstrup Mikkelsen",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/b0/b7/c965c1bebcd855bad8d6417a7229ad4f58e982d0fd40280135d10465a4fd/sudoku_mip_solver-0.2.0.tar.gz",
"platform": null,
"description": "# Sudoku MIP Solver\r\n\r\n[](https://github.com/DenHvideDvaerg/sudoku-mip-solver/actions/workflows/CI.yml)\r\n[](https://github.com/DenHvideDvaerg/sudoku-mip-solver/actions/workflows/CI.yml?query=branch%3Amain+is%3Asuccess)\r\n[](https://pypi.org/project/sudoku-mip-solver/)\r\n\r\nA Sudoku puzzle solver and generator using Mixed Integer Programming (MIP).\r\n\r\n## Table of Contents\r\n- [Features](#features)\r\n- [Installation](#installation)\r\n- [Requirements](#requirements)\r\n- [Quick Start](#quick-start)\r\n- [Command Line Interface](#command-line-interface)\r\n- [SudokuMIPSolver API](#sudokumipsolver-api)\r\n- [Examples](#examples)\r\n- [License](#license)\r\n\r\n## Features\r\n\r\nThis package provides tools to:\r\n- Solve Sudoku puzzles of any size using MIP optimization techniques\r\n- Generate random Sudoku puzzles with varying difficulty levels\r\n- Find all possible solutions for a given puzzle\r\n- Support non-standard Sudoku grid dimensions (e.g., 12x12 with 4x3 sub-grids)\r\n\r\n## Installation\r\n\r\n```bash\r\npip install sudoku-mip-solver\r\n```\r\n\r\n## Requirements\r\n\r\n- Python 3.9+\r\n- PuLP (for the MIP solver)\r\n\r\n## Quick Start\r\n\r\n```python\r\nfrom sudoku_mip_solver import SudokuMIPSolver\r\n\r\n# Create a solver from a string representation of a 9x9 puzzle\r\npuzzle_string = \"530070000600195000098000060800060003400803001700020006060000280000419005000080079\"\r\nsolver = SudokuMIPSolver.from_string(puzzle_string)\r\n\r\n# Solve the puzzle\r\nif solver.solve():\r\n solver.pretty_print(solver.get_solution())\r\nelse:\r\n print(\"No solution found!\")\r\n \r\n# Generate a random puzzle\r\nnew_solver, difficulty = SudokuMIPSolver.generate_random_puzzle(\r\n sub_grid_width=3,\r\n sub_grid_height=3,\r\n target_difficulty=0.75\r\n)\r\nprint(f\"Generated puzzle with difficulty {difficulty:.2f}:\")\r\nnew_solver.pretty_print(new_solver.board)\r\n```\r\n\r\n## Command Line Interface\r\n\r\nThe package includes a command-line interface for solving and generating puzzles.\r\n\r\n### Basic Usage\r\n\r\n```bash\r\n# Display the version of the package\r\nsudoku-mip-solver --version\r\n\r\n# Solve a puzzle provided as a string\r\nsudoku-mip-solver -s \"530070000600195000098000060800060003400803001700020006060000280000419005000080079\"\r\n\r\n# Read a puzzle from a file\r\nsudoku-mip-solver -f puzzle.txt\r\n\r\n# Generate a random puzzle with medium difficulty\r\nsudoku-mip-solver\r\n\r\n# Generate but don't solve a puzzle\r\nsudoku-mip-solver --generate-only\r\n\r\n# Find all solutions to a puzzle\r\nsudoku-mip-solver -f puzzle.txt -m -1\r\n\r\n# Solve a non-standard 6x6 puzzle (2x3 sub-grids)\r\nsudoku-mip-solver -s \"530070600195098000\" -w 2 -H 3\r\n```\r\n\r\n### Command Line Options\r\n\r\n#### Input Options\r\n\r\n| Option | Description |\r\n| ------ | ----------- |\r\n| `-s`, `--string` | Input puzzle as a string |\r\n| `-f`, `--file` | Path to a file containing the puzzle |\r\n| `--generate-only` | Generate a random puzzle without solving it |\r\n\r\n#### Grid Dimensions\r\n\r\n| Option | Description |\r\n| ------ | ----------- |\r\n| `-w`, `--width` | Width of each sub-grid (default: 3) |\r\n| `-H`, `--height` | Height of each sub-grid (default: same as width) |\r\n\r\n#### Random Puzzle Options\r\n\r\n| Option | Description |\r\n| ------ | ----------- |\r\n| `-d`, `--difficulty` | Controls number of clues (0.0=easiest, 1.0=hardest, default: 0.75) |\r\n| `--non-unique` | Skip uniqueness check, allowing multiple solutions |\r\n\r\n#### Solver Options\r\n\r\n| Option | Description |\r\n| ------ | ----------- |\r\n| `-m`, `--max-solutions` | Maximum solutions to find (default: 1, use -1 for all) |\r\n\r\n#### Output Options\r\n\r\n| Option | Description |\r\n| ------ | ----------- |\r\n| `-o`, `--output` | Save the solution or generated puzzle to a file |\r\n| `-v`, `--verbose` | Show detailed solver information |\r\n| `-q`, `--quiet` | Suppress all output except error messages |\r\n| `--version` | Display the version number of the package |\r\n\r\n## SudokuMIPSolver API\r\n\r\n### Creating a Solver\r\n\r\n```python\r\n# From a 2D array\r\nboard = [[5,3,0,0,7,0,0,0,0], \r\n [6,0,0,1,9,5,0,0,0],\r\n # ... (additional rows)\r\n ]\r\nsolver = SudokuMIPSolver(board, sub_grid_width=3, sub_grid_height=3)\r\n\r\n# From a string representation\r\nsolver = SudokuMIPSolver.from_string(\"530070000...\", sub_grid_width=3)\r\n\r\n# Generate a random puzzle\r\nsolver, difficulty = SudokuMIPSolver.generate_random_puzzle(\r\n sub_grid_width=3,\r\n sub_grid_height=3,\r\n target_difficulty=0.75,\r\n unique_solution=True\r\n)\r\n```\r\n\r\n### Core Methods\r\n\r\n| Method | Description |\r\n| ------ | ----------- |\r\n| `build_model()` | Build the MIP model with all Sudoku constraints |\r\n| `solve(show_output=False)` | Solve the puzzle and return True if solution found |\r\n| `find_all_solutions(max_solutions=None)` | Find all solutions (or up to max_solutions) |\r\n| `get_solution()` | Get the current solution |\r\n| `reset_model()` | Remove all solution cuts, restoring original constraints |\r\n\r\n### Utility Methods\r\n\r\n| Method | Description |\r\n| ------ | ----------- |\r\n| `to_string(board=None, delimiter=None)` | Convert board to string representation |\r\n| `get_pretty_string(board=None)` | Get the board as a formatted string with grid lines showing sub-grids |\r\n| `pretty_print(board=None)` | Print the board with grid lines showing sub-grids |\r\n| `extract_solution()` | Extract solution from model variables |\r\n| `print_model()` | Print the model in a readable format |\r\n\r\n### Class Methods\r\n\r\n| Method | Description |\r\n| ------ | ----------- |\r\n| `from_string(sudoku_string, sub_grid_width=3, sub_grid_height=None, delimiter=None)` | Create solver from string representation |\r\n| `generate_random_puzzle(sub_grid_width=3, sub_grid_height=None, target_difficulty=0.75, unique_solution=True, max_attempts=100, random_seed=None)` | Generate a random puzzle with specified parameters |\r\n\r\n### Algorithm Details\r\n\r\nThe solver uses Mixed Integer Programming (MIP) to model and solve Sudoku puzzles:\r\n\r\n1. **Decision Variables**: Binary variables x[i,j,k] representing whether cell (i,j) contains value k\r\n2. **Constraints**:\r\n - Each cell must contain exactly one value\r\n - Each row must contain all values exactly once\r\n - Each column must contain all values exactly once\r\n - Each sub-grid must contain all values exactly once\r\n - Initial clues are fixed to their given values\r\n3. **Solution Finding**: \r\n - The MIP solver (provided by PuLP) finds a feasible solution satisfying all constraints\r\n - For multiple solutions, solution cuts are added to exclude previously found solutions\r\n\r\nThe random puzzle generator works by:\r\n1. Creating a complete, solved Sudoku grid\r\n2. Systematically removing values while ensuring the puzzle maintains a unique solution\r\n3. Continuing removal until the target difficulty level is reached\r\n\r\n## Examples\r\n\r\n### Solving a Puzzle\r\n\r\n```python\r\n# Standard 9x9 puzzle\r\npuzzle = \"530070000600195000098000060800060003400803001700020006060000280000419005000080079\"\r\nsolver = SudokuMIPSolver.from_string(puzzle)\r\nsolver.solve()\r\nsolver.pretty_print(solver.get_solution())\r\n```\r\n\r\n### Getting Formatted Output as String\r\n\r\n```python\r\n# Get the formatted puzzle as a string instead of printing directly\r\npuzzle = \"530070000600195000098000060800060003400803001700020006060000280000419005000080079\"\r\nsolver = SudokuMIPSolver.from_string(puzzle)\r\nsolver.solve()\r\n\r\n# Get the formatted string\r\nformatted_solution = solver.get_pretty_string(solver.get_solution())\r\nprint(\"Solution:\")\r\nprint(formatted_solution)\r\n\r\n# You can also save it to a file or process it further\r\nwith open(\"solution.txt\", \"w\") as f:\r\n f.write(formatted_solution)\r\n```\r\n\r\n### Finding Multiple Solutions\r\n\r\n```python\r\n# Find all solutions to an under-constrained puzzle\r\npuzzle = \"123456789000000000000000000000000000000000000000000000000000000000000000000000000\"\r\nsolver = SudokuMIPSolver.from_string(puzzle)\r\nsolutions = solver.find_all_solutions(max_solutions=5) # Limit to 5 solutions\r\nprint(f\"Found {len(solutions)} solutions\")\r\n```\r\n\r\n### Working with Non-Standard Grids\r\n\r\n```python\r\n# Create a 6x6 puzzle with 2x3 sub-grids\r\npuzzle = \"123456000000000000000000000000000000\"\r\nsolver = SudokuMIPSolver.from_string(puzzle, sub_grid_width=2, sub_grid_height=3)\r\nsolver.solve()\r\nsolver.pretty_print(solver.get_solution())\r\n```\r\n\r\n### Generating Puzzles with Different Difficulties\r\n\r\nThe `target_difficulty` parameter controls the number of clues in the generated puzzle:\r\n- 0.0 = maximum clues (easiest puzzles)\r\n- 1.0 = minimum clues (hardest puzzles)\r\n\r\nFor standard 9\u00d79 Sudoku puzzles, a difficulty of 1.0 targets the theoretical minimum of 17 clues (mathematically proven lower bound). For puzzles of other sizes, the minimum is (wrongly) estimated as N clues for an N\u00d7N grid.\r\n\r\n```python\r\n# Very easy puzzle (more clues)\r\neasy_solver, difficulty = SudokuMIPSolver.generate_random_puzzle(target_difficulty=0.3)\r\nprint(f\"Easy puzzle (difficulty: {difficulty:.2f})\")\r\neasy_solver.pretty_print(easy_solver.board)\r\n\r\n# Harder puzzle (fewer clues)\r\nhard_solver, difficulty = SudokuMIPSolver.generate_random_puzzle(target_difficulty=0.9)\r\nprint(f\"Hard puzzle (difficulty: {difficulty:.2f})\")\r\nhard_solver.pretty_print(hard_solver.board)\r\n```\r\n\r\n## License\r\n\r\nThis project is licensed under the [MIT License](LICENSE).\r\n",
"bugtrack_url": null,
"license": "MIT License\r\n \r\n Copyright (c) 2025 Rasmus \u00d8rnstrup Mikkelsen\r\n \r\n Permission is hereby granted, free of charge, to any person obtaining a copy\r\n of this software and associated documentation files (the \"Software\"), to deal\r\n in the Software without restriction, including without limitation the rights\r\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n copies of the Software, and to permit persons to whom the Software is\r\n furnished to do so, subject to the following conditions:\r\n \r\n The above copyright notice and this permission notice shall be included in all\r\n copies or substantial portions of the Software.\r\n \r\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n SOFTWARE.\r\n ",
"summary": "A Sudoku puzzle solver and generator using Mixed Integer Programming (MIP)",
"version": "0.2.0",
"project_urls": {
"Bug Tracker": "https://github.com/DenHvideDvaerg/sudoku-mip-solver/issues",
"Homepage": "https://github.com/DenHvideDvaerg/sudoku-mip-solver"
},
"split_keywords": [],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "557d07f2a83c5c9b3a2a55ec3c6e1e9f045b8e0e885d21393666ce550e1a817c",
"md5": "738e1854c51434847b23d924d8e9de46",
"sha256": "e5da6f38eb3db10dca93f8baece135f3a5f0b7d9a6fb8e1bf683ba90316ae973"
},
"downloads": -1,
"filename": "sudoku_mip_solver-0.2.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "738e1854c51434847b23d924d8e9de46",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 17127,
"upload_time": "2025-07-13T20:59:38",
"upload_time_iso_8601": "2025-07-13T20:59:38.677320Z",
"url": "https://files.pythonhosted.org/packages/55/7d/07f2a83c5c9b3a2a55ec3c6e1e9f045b8e0e885d21393666ce550e1a817c/sudoku_mip_solver-0.2.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "b0b7c965c1bebcd855bad8d6417a7229ad4f58e982d0fd40280135d10465a4fd",
"md5": "830f9f5a833233c5c3db3e4784bf3213",
"sha256": "676ae768c49c8c1883cd4de2f40be05fdebedbfc0de443b3f3473e12a82025d6"
},
"downloads": -1,
"filename": "sudoku_mip_solver-0.2.0.tar.gz",
"has_sig": false,
"md5_digest": "830f9f5a833233c5c3db3e4784bf3213",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 28481,
"upload_time": "2025-07-13T20:59:39",
"upload_time_iso_8601": "2025-07-13T20:59:39.949365Z",
"url": "https://files.pythonhosted.org/packages/b0/b7/c965c1bebcd855bad8d6417a7229ad4f58e982d0fd40280135d10465a4fd/sudoku_mip_solver-0.2.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-13 20:59:39",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "DenHvideDvaerg",
"github_project": "sudoku-mip-solver",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"requirements": [
{
"name": "pulp",
"specs": []
},
{
"name": "pytest",
"specs": []
}
],
"lcname": "sudoku-mip-solver"
}