Skip to content

Commit 2891d6f

Browse files
committed
Project cleanup
1 parent bb536bd commit 2891d6f

File tree

7 files changed

+145
-46
lines changed

7 files changed

+145
-46
lines changed

.github/workflows/lint.yml

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Run linters
2+
3+
on: [ push ]
4+
5+
jobs:
6+
build:
7+
runs-on: ubuntu-latest
8+
strategy:
9+
matrix:
10+
python-version: [ "3.10", "3.11" ]
11+
steps:
12+
- uses: actions/checkout@v3
13+
- name: Set up Python ${{ matrix.python-version }}
14+
uses: actions/setup-python@v3
15+
with:
16+
python-version: ${{ matrix.python-version }}
17+
- name: Install dependencies
18+
run: |
19+
python -m pip install --upgrade pip
20+
pip install --editable .
21+
pip install '.[lint]'
22+
- name: Analysing the code with pylint
23+
run: |
24+
pylint $(git ls-files '*.py')
25+
- name: Analysing the code with mypy
26+
run: |
27+
mypy --install-types --non-interactive $(git ls-files '*.py')

.pre-commit-config.yaml

+20-23
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,34 @@
11
# See https://pre-commit.com for more information
22
# See https://pre-commit.com/hooks.html for more hooks
33
repos:
4-
- repo: https://github.com/pre-commit/pre-commit-hooks
4+
- repo: https://github.com/pre-commit/pre-commit-hooks
55
rev: v3.2.0
66
hooks:
7-
- id: trailing-whitespace
8-
- id: end-of-file-fixer
9-
- id: check-yaml
10-
- id: check-added-large-files
11-
- repo: https://github.com/Yelp/detect-secrets
7+
- id: trailing-whitespace
8+
- id: end-of-file-fixer
9+
- id: check-yaml
10+
- id: check-added-large-files
11+
- repo: https://github.com/Yelp/detect-secrets
1212
rev: v1.4.0
1313
hooks:
14-
- id: detect-secrets
15-
- repo: https://github.com/PyCQA/pylint
16-
rev: v2.16.1
14+
- id: detect-secrets
15+
- repo: https://github.com/pre-commit/mirrors-autopep8
16+
rev: v2.0.1
17+
hooks:
18+
- id: autopep8
19+
entry: autopep8
20+
- repo: local
21+
# These hooks are run from the local virtual env (and it's assumed they are there)
22+
# to allow these tools to find project dependencies.
1723
hooks:
18-
- id: pylint
24+
- id: pylint
1925
name: pylint
2026
entry: pylint
2127
language: system
22-
types: [python]
23-
- repo: https://github.com/pre-commit/mirrors-mypy
24-
rev: 'v1.0.0'
25-
hooks:
26-
- id: mypy
28+
types: [ python ]
29+
- id: mypy
2730
name: mypy
2831
entry: mypy
2932
language: system
30-
types: [python]
31-
- repo: https://github.com/pre-commit/mirrors-autopep8
32-
rev: v2.0.1
33-
hooks:
34-
- id: autopep8
35-
entry: autopep8
36-
language: system
37-
types: [python]
33+
types: [ python ]
34+
args: [ '--install-types', '--non-interactive' ]

ccspp/ch2/cannibals.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from __future__ import annotations
66
from attrs import define, field, Factory
77
from typing import List, Optional, Iterator
8-
from ch2.maze import bfs, to_path
8+
from .maze import bfs, to_path
99

1010
MAX_NUM: int = 3
1111

ccspp/ch3/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Constraint satisfaction problems."""

ccspp/ch3/csp.py

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"""Constraint solvers."""
2+
3+
from abc import ABC, abstractmethod
4+
from dataclasses import dataclass, field
5+
from typing import Generic, TypeVar, List, Dict, Set, Iterable, Optional
6+
7+
V = TypeVar("V") # variable type
8+
D = TypeVar("D") # domain type
9+
10+
11+
@dataclass(frozen=True)
12+
class Constraint(Generic[V, D], ABC):
13+
"""Base class for all constraints."""
14+
variables: Set[V] = field()
15+
16+
@abstractmethod
17+
def satisfied(self, assignment: Dict[V, D]) -> bool:
18+
"""Verify that the constraint satisfies the assignment."""
19+
20+
21+
def _validate_empty_difference(set1: Set[V], set2: Iterable[V], /):
22+
diff = set1.difference(set2)
23+
if diff:
24+
raise LookupError(f"Unknown variables: [{diff}]")
25+
26+
27+
@dataclass(frozen=True)
28+
class CSP(Generic[V, D]):
29+
"""A constraint satisfaction problem has variables of type V
30+
that have ranges of values known as domains D and constraints
31+
that determine if a variable's domain selection is satisfied."""
32+
variables: Set[V] = field()
33+
domains: Dict[V, List[D]] = field()
34+
constraints: Dict[V, List[Constraint[V, D]]] = field(default_factory=dict)
35+
36+
def __post_init__(self) -> None:
37+
_validate_empty_difference(self.variables, self.domains.keys())
38+
39+
def append_constraint(self, constraint: Constraint[V, D]) -> None:
40+
"""Update constraints"""
41+
_validate_empty_difference(self.variables, constraint.variables)
42+
for convar in constraint.variables:
43+
if convar in self.constraints:
44+
self.constraints[convar].append(constraint)
45+
else:
46+
self.constraints[convar] = [constraint]
47+
48+
def is_consistent(self, variable: V, assignment: Dict[V, D]) -> bool:
49+
"""Verify that all constraints of variable are satisfied by the assignment."""
50+
return all((c.satisfied(assignment) for c in self.constraints[variable]))
51+
52+
def backtracking_search(self, assignment: Dict[V, D]) -> Optional[Dict[V, D]]:
53+
"""Use backtracking to search for an assignment that satisfies all constraints
54+
for all variables."""
55+
if not assignment:
56+
assignment = {}
57+
58+
if len(assignment) == len(self.variables):
59+
return assignment
60+
61+
unassigned = self.variables.difference(assignment.keys())
62+
first: V = next(iter(unassigned))
63+
for domain in self.domains[first]:
64+
local_assignment = assignment.copy()
65+
local_assignment[first] = domain
66+
if self.is_consistent(first, local_assignment):
67+
result: Optional[Dict[V, D]] = self.backtracking_search(
68+
local_assignment)
69+
if result:
70+
return result
71+
return None

pyproject.toml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[project]
2+
name = "ccspp_razvan"
3+
version = "0.0.1"
4+
authors = [
5+
{ name = "Razvan Mihai", email = "[email protected]" },
6+
]
7+
description = "Classic computer science problems in Python."
8+
readme = "README.md"
9+
requires-python = ">=3.9"
10+
classifiers = [
11+
"Programming Language :: Python :: 3",
12+
"License :: OSI Approved :: Apache Software License",
13+
"Operating System :: OS Independent",
14+
]
15+
dependencies = [
16+
"attrs==22.2.0", # todo: remove
17+
]
18+
19+
[project.optional-dependencies]
20+
lint = ['pylint', 'mypy']
21+
dev = ['pre-commit']
22+
23+
[project.urls]
24+
"Homepage" = "https://github.com/razvan/classic-compsci-python"
25+
"Bug Tracker" = "https://github.com/razvan/classic-compsci-python/issues"

requirements.txt

-22
This file was deleted.

0 commit comments

Comments
 (0)