From b4b67550183e18f69418ade8002b2dc057ade3fe Mon Sep 17 00:00:00 2001 From: Dave Date: Sun, 30 Sep 2018 23:21:37 -0400 Subject: [PATCH 01/25] Blank line between cluster outputs --- Chapter6/governors.py | 2 +- Chapter6/mj.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Chapter6/governors.py b/Chapter6/governors.py index cfb526e..72111ad 100644 --- a/Chapter6/governors.py +++ b/Chapter6/governors.py @@ -59,4 +59,4 @@ def __repr__(self) -> str: kmeans: KMeans[Governor] = KMeans(2, governors) gov_clusters: List[KMeans.Cluster] = kmeans.run() for index, cluster in enumerate(gov_clusters): - print(f"Cluster {index}: {cluster.points}") + print(f"Cluster {index}: {cluster.points}\n") diff --git a/Chapter6/mj.py b/Chapter6/mj.py index a2023a9..8716c45 100644 --- a/Chapter6/mj.py +++ b/Chapter6/mj.py @@ -40,4 +40,4 @@ def __repr__(self) -> str: kmeans: KMeans[Album] = KMeans(2, albums) clusters: List[KMeans.Cluster] = kmeans.run() for index, cluster in enumerate(clusters): - print(f"Cluster {index} Avg Length {cluster.centroid.dimensions[0]} Avg Tracks {cluster.centroid.dimensions[1]}: {cluster.points}") + print(f"Cluster {index} Avg Length {cluster.centroid.dimensions[0]} Avg Tracks {cluster.centroid.dimensions[1]}: {cluster.points}\n") From bec011a8d14bccfc9ef04dd7dc7793c89ccccb99 Mon Sep 17 00:00:00 2001 From: Dave Date: Sun, 4 Nov 2018 00:47:51 -0400 Subject: [PATCH 02/25] Removed unnecessary import of Optional --- Chapter4/weighted_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter4/weighted_graph.py b/Chapter4/weighted_graph.py index 6ea62b2..0acb273 100644 --- a/Chapter4/weighted_graph.py +++ b/Chapter4/weighted_graph.py @@ -13,7 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import TypeVar, Generic, List, Tuple, Optional +from typing import TypeVar, Generic, List, Tuple from graph import Graph from weighted_edge import WeightedEdge From 2633c6da4fb0b96d4a26d683403886471a0a75f3 Mon Sep 17 00:00:00 2001 From: Dave Date: Wed, 7 Nov 2018 01:12:31 -0500 Subject: [PATCH 03/25] Fixed typo --- Chapter2/missionaries.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter2/missionaries.py b/Chapter2/missionaries.py index 09be34c..92a5692 100644 --- a/Chapter2/missionaries.py +++ b/Chapter2/missionaries.py @@ -31,7 +31,7 @@ def __init__(self, missionaries: int, cannibals: int, boat: bool) -> None: def __str__(self) -> str: return ("On the west bank there are {} missionaries and {} cannibals.\n" "On the east bank there are {} missionaries and {} cannibals.\n" - "The boast is on the {} bank.")\ + "The boat is on the {} bank.")\ .format(self.wm, self.wc, self.em, self.ec, ("west" if self.boat else "east")) def goal_test(self) -> bool: From 66f0f1b1d44334e7495f3f4e5c66fb4fcde5278d Mon Sep 17 00:00:00 2001 From: Dave Date: Fri, 9 Nov 2018 01:14:13 -0500 Subject: [PATCH 04/25] Python 3.7.1 properly print Enum str values --- Chapter1/calculating_pi.py | 4 +++- Chapter8/connectfour.py | 3 +++ Chapter8/tictactoe.py | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Chapter1/calculating_pi.py b/Chapter1/calculating_pi.py index 845426c..61abfc6 100644 --- a/Chapter1/calculating_pi.py +++ b/Chapter1/calculating_pi.py @@ -13,6 +13,8 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + + def calculate_pi(n_terms: int) -> float: numerator: float = 4.0 denominator: float = 1.0 @@ -26,4 +28,4 @@ def calculate_pi(n_terms: int) -> float: if __name__ == "__main__": - print(calculate_pi(1000000)) \ No newline at end of file + print(calculate_pi(1000000)) diff --git a/Chapter8/connectfour.py b/Chapter8/connectfour.py index 6f6f900..98bfa22 100644 --- a/Chapter8/connectfour.py +++ b/Chapter8/connectfour.py @@ -33,6 +33,9 @@ def opposite(self) -> C4Piece: else: return C4Piece.E + def __str__(self) -> str: + return self.value + def generate_segments(num_columns: int, num_rows: int, segment_length: int) -> List[List[Tuple[int, int]]]: segments: List[List[Tuple[int, int]]] = [] diff --git a/Chapter8/tictactoe.py b/Chapter8/tictactoe.py index 4547962..74192ff 100644 --- a/Chapter8/tictactoe.py +++ b/Chapter8/tictactoe.py @@ -33,6 +33,9 @@ def opposite(self) -> TTTPiece: else: return TTTPiece.E + def __str__(self) -> str: + return self.value + class TTTBoard(Board): def __init__(self, position: List[TTTPiece] = [TTTPiece.E] * 9, turn: TTTPiece = TTTPiece.X) -> None: From d75ab153f11611cbbf9bb8e03e71f0ea34cbc9ed Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 22 Nov 2018 01:30:32 -0500 Subject: [PATCH 05/25] tiny cleanups --- Chapter2/generic_search.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Chapter2/generic_search.py b/Chapter2/generic_search.py index 51b6ea3..6e0ceb7 100644 --- a/Chapter2/generic_search.py +++ b/Chapter2/generic_search.py @@ -16,7 +16,6 @@ from __future__ import annotations from typing import TypeVar, Iterable, Sequence, Generic, List, Callable, Set, Deque, Dict, Any, Optional from typing_extensions import Protocol -from functools import total_ordering from heapq import heappush, heappop T = TypeVar('T') @@ -175,7 +174,7 @@ def empty(self) -> bool: return not self._container # not is true for empty container def push(self, item: T) -> None: - heappush(self._container, item) # priority determined by order of item + heappush(self._container, item) # in by priority def pop(self) -> T: return heappop(self._container) # out by priority From 61b5864b1cda69b3095d6a5dae362be797acedfe Mon Sep 17 00:00:00 2001 From: Dave Date: Sun, 25 Nov 2018 23:49:19 -0500 Subject: [PATCH 06/25] cleaned up some comments; added a missing annotation --- Chapter3/queens.py | 6 ++++-- Chapter4/dijkstra.py | 21 ++++++++++++++------- Chapter4/mst.py | 6 ++++-- Chapter4/priority_queue.py | 2 +- Chapter4/weighted_edge.py | 2 +- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Chapter3/queens.py b/Chapter3/queens.py index 8ef820f..31a82a5 100644 --- a/Chapter3/queens.py +++ b/Chapter3/queens.py @@ -23,8 +23,10 @@ def __init__(self, columns: List[int]) -> None: self.columns: List[int] = columns def satisfied(self, assignment: Dict[int, int]) -> bool: - for q1c, q1r in assignment.items(): # q1c = queen 1 column, q1r = queen 1 row - for q2c in range(q1c + 1, len(self.columns) + 1): # q2c = queen 2 column + # q1c = queen 1 column, q1r = queen 1 row + for q1c, q1r in assignment.items(): + # q2c = queen 2 column + for q2c in range(q1c + 1, len(self.columns) + 1): if q2c in assignment: q2r: int = assignment[q2c] # q2r = queen 2 row if q1r == q2r: # same row? diff --git a/Chapter4/dijkstra.py b/Chapter4/dijkstra.py index b172ce6..9bdee27 100644 --- a/Chapter4/dijkstra.py +++ b/Chapter4/dijkstra.py @@ -38,7 +38,8 @@ def __eq__(self, other: DijkstraNode) -> bool: def dijkstra(wg: WeightedGraph[V], root: V) -> Tuple[List[Optional[float]], Dict[int, WeightedEdge]]: first: int = wg.index_of(root) # find starting index - distances: List[Optional[float]] = [None] * wg.vertex_count # distances are unknown at first + # distances are unknown at first + distances: List[Optional[float]] = [None] * wg.vertex_count distances[first] = 0 # the root is 0 away from the root path_dict: Dict[int, WeightedEdge] = {} # how we got to each vertex pq: PriorityQueue[DijkstraNode] = PriorityQueue() @@ -47,12 +48,18 @@ def dijkstra(wg: WeightedGraph[V], root: V) -> Tuple[List[Optional[float]], Dict while not pq.empty: u: int = pq.pop().vertex # explore the next closest vertex dist_u: float = distances[u] # should already have seen it - for we in wg.edges_for_index(u): # look at every edge/vertex from the vertex in question - dist_v: float = distances[we.v] # the old distance to this vertex - if dist_v is None or dist_v > we.weight + dist_u: # no old distance or found shorter path - distances[we.v] = we.weight + dist_u # update distance to this vertex - path_dict[we.v] = we # update the edge on the shortest path to this vertex - pq.push(DijkstraNode(we.v, we.weight + dist_u)) # explore it soon + # look at every edge/vertex from the vertex in question + for we in wg.edges_for_index(u): + # the old distance to this vertex + dist_v: float = distances[we.v] + # no old distance or found shorter path + if dist_v is None or dist_v > we.weight + dist_u: + # update distance to this vertex + distances[we.v] = we.weight + dist_u + # update the edge on the shortest path to this vertex + path_dict[we.v] = we + # explore it soon + pq.push(DijkstraNode(we.v, we.weight + dist_u)) return distances, path_dict diff --git a/Chapter4/mst.py b/Chapter4/mst.py index 77865a7..0fbaeaf 100644 --- a/Chapter4/mst.py +++ b/Chapter4/mst.py @@ -35,7 +35,8 @@ def mst(wg: WeightedGraph[V], start: int = 0) -> Optional[WeightedPath]: def visit(index: int): visited[index] = True # mark as visited - for edge in wg.edges_for_index(index): # add all edges coming from here to pq + for edge in wg.edges_for_index(index): + # add all edges coming from here to pq if not visited[edge.v]: pq.push(edge) @@ -45,7 +46,8 @@ def visit(index: int): edge = pq.pop() if visited[edge.v]: continue # don't ever revisit - result.append(edge) # this is the current smallest, so add it to solution + # this is the current smallest, so add it to solution + result.append(edge) visit(edge.v) # visit where this connects return result diff --git a/Chapter4/priority_queue.py b/Chapter4/priority_queue.py index c4e36ef..a8dfc81 100644 --- a/Chapter4/priority_queue.py +++ b/Chapter4/priority_queue.py @@ -29,7 +29,7 @@ def empty(self) -> bool: return not self._container # not is true for empty container def push(self, item: T) -> None: - heappush(self._container, item) # priority determined by order of item + heappush(self._container, item) # in by priority def pop(self) -> T: return heappop(self._container) # out by priority diff --git a/Chapter4/weighted_edge.py b/Chapter4/weighted_edge.py index 4e0d095..666f2d7 100644 --- a/Chapter4/weighted_edge.py +++ b/Chapter4/weighted_edge.py @@ -26,7 +26,7 @@ def reversed(self) -> WeightedEdge: return WeightedEdge(self.v, self.u, self.weight) # so that we can order edges by weight to find the minimum weight edge - def __lt__(self, other: WeightedEdge): + def __lt__(self, other: WeightedEdge) -> bool: return self.weight < other.weight def __str__(self) -> str: From 31e4b308327d91af0eb0fbf07b6d2a02c2f0ebb4 Mon Sep 17 00:00:00 2001 From: Dave Date: Sun, 2 Dec 2018 12:41:27 -0500 Subject: [PATCH 07/25] cleaned up some comments --- Chapter5/genetic_algorithm.py | 3 ++- Chapter5/list_compression.py | 3 ++- Chapter6/kmeans.py | 2 +- Chapter8/minimax.py | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Chapter5/genetic_algorithm.py b/Chapter5/genetic_algorithm.py index a56fbdf..86ef925 100644 --- a/Chapter5/genetic_algorithm.py +++ b/Chapter5/genetic_algorithm.py @@ -77,7 +77,8 @@ def _mutate(self) -> None: def run(self) -> C: best: C = max(self._population, key=self._fitness_key) for generation in range(self._max_generations): - if best.fitness() >= self._threshold: # early exit if we beat threshold + # early exit if we beat threshold + if best.fitness() >= self._threshold: return best print(f"Generation {generation} Best {best.fitness()} Avg {mean(map(self._fitness_key, self._population))}") self._reproduce_and_replace() diff --git a/Chapter5/list_compression.py b/Chapter5/list_compression.py index 8ff37be..c85e32d 100644 --- a/Chapter5/list_compression.py +++ b/Chapter5/list_compression.py @@ -23,7 +23,8 @@ from sys import getsizeof from pickle import dumps -PEOPLE: List[str] = ["Michael", "Sarah", "Joshua", "Narine", "David", "Sajid", "Melanie", "Daniel", "Wei", "Dean", "Brian", "Murat", "Lisa"] # 165 bytes compressed +# 165 bytes compressed +PEOPLE: List[str] = ["Michael", "Sarah", "Joshua", "Narine", "David", "Sajid", "Melanie", "Daniel", "Wei", "Dean", "Brian", "Murat", "Lisa"] class ListCompression(Chromosome): diff --git a/Chapter6/kmeans.py b/Chapter6/kmeans.py index 19e2f23..fdff5cf 100644 --- a/Chapter6/kmeans.py +++ b/Chapter6/kmeans.py @@ -100,7 +100,7 @@ def run(self, max_iterations: int = 100) -> List[KMeans.Cluster]: for cluster in self._clusters: # clear all clusters cluster.points.clear() self._assign_clusters() # find cluster each point is closest to - old_centroids: List[DataPoint] = deepcopy(self._centroids) # record centroids + old_centroids: List[DataPoint] = deepcopy(self._centroids) # record self._generate_centroids() # find new centroids if old_centroids == self._centroids: # have centroids moved? print(f"Converged after {iteration} iterations") diff --git a/Chapter8/minimax.py b/Chapter8/minimax.py index efdccee..0d358ae 100644 --- a/Chapter8/minimax.py +++ b/Chapter8/minimax.py @@ -60,7 +60,8 @@ def alphabeta(board: Board, maximizing: bool, original_player: Piece, max_depth: return beta -# Find the best possible move in the current position looking up to max_depth ahead +# Find the best possible move in the current position +# looking up to max_depth ahead def find_best_move(board: Board, max_depth: int = 8) -> Move: best_eval: float = float("-inf") best_move: Move = Move(-1) From 3f1190efe545882229932f4f8f84bd1d6cb303d5 Mon Sep 17 00:00:00 2001 From: Dave Date: Tue, 8 Jan 2019 23:55:10 -0500 Subject: [PATCH 08/25] pep8 end file with blank line --- Chapter1/fib4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter1/fib4.py b/Chapter1/fib4.py index 648b4f0..86446c2 100644 --- a/Chapter1/fib4.py +++ b/Chapter1/fib4.py @@ -25,4 +25,4 @@ def fib4(n: int) -> int: # same definition as fib2() if __name__ == "__main__": print(fib4(5)) - print(fib4(50)) \ No newline at end of file + print(fib4(50)) From e113648dcd36c37dee6f6190b58a7504a0a85e4b Mon Sep 17 00:00:00 2001 From: Steve Nicholson Date: Mon, 18 Feb 2019 14:39:07 -0800 Subject: [PATCH 09/25] Small typo in comment --- Chapter5/chromosome.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter5/chromosome.py b/Chapter5/chromosome.py index b75dbb1..3b26a40 100644 --- a/Chapter5/chromosome.py +++ b/Chapter5/chromosome.py @@ -20,7 +20,7 @@ T = TypeVar('T', bound='Chromosome') # for returning self -# Base class for all chromosomes; all methods must be o overridden +# Base class for all chromosomes; all methods must be overridden class Chromosome(ABC): @abstractmethod def fitness(self) -> float: From f427b31212e2d1f02ac39f736765d7a435e3638a Mon Sep 17 00:00:00 2001 From: Dave Date: Fri, 15 Mar 2019 12:54:01 -0400 Subject: [PATCH 10/25] updated readme for final release --- Chapter5/genetic_algorithm.py | 2 +- README.md | 14 +++++++++++--- cover.jpg | Bin 0 -> 12894 bytes 3 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 cover.jpg diff --git a/Chapter5/genetic_algorithm.py b/Chapter5/genetic_algorithm.py index 86ef925..7304882 100644 --- a/Chapter5/genetic_algorithm.py +++ b/Chapter5/genetic_algorithm.py @@ -86,5 +86,5 @@ def run(self) -> C: highest: C = max(self._population, key=self._fitness_key) if highest.fitness() > best.fitness(): best = highest # found a new best - return best # best we found in max_generations + return best # best we found in _max_generations diff --git a/README.md b/README.md index ac64832..df3d725 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,22 @@ # Classic Computer Science Problems in Python -This repository contains source code to accompany the forthcoming book *Classic Computer Science Problems in Python* by David Kopec. You will find the source organized by chapter. As you read the book, each code listing contains a file name that corresponds to a file in this repository. +This repository contains source code to accompany the book *Classic Computer Science Problems in Python* by David Kopec. You will find the source organized by chapter. **As you read the book, each code listing contains a file name that corresponds to a file in this repository.** +![Classic Computer Science Problems in Python Cover](cover.jpg) ## Get the Book -The book is now available in early access form [through Manning's MEAP program](https://www.manning.com/books/classic-computer-science-problems-in-python). By purchasing the MEAP you will get access to each chapter's draft and join me on the manuscript's development journey. You will also receive the final version of the book upon publication in late 2018/early 2019. +- [Manning](https://www.manning.com/books/classic-computer-science-problems-in-python) the publisher sells both hard copy and DRM-free eBook editions. +- [Amazon](https://amzn.to/2ui96Op) if you buy the hard copy from Amazon, it will come with a way to download the eBook for free from the publisher ## Versioning and Packages The source code in this repository requires Python 3.7 and installation of the [typing_extensions](https://github.com/python/typing/tree/master/typing_extensions) package. Due to its extensive use of Python 3.7 features (data classes, advanced type hints, etc.), most of the source code will not work with earlier versions of Python. You can install the `typing_extensions` package with `pip3 install typing_extensions` or `pip install typing_extensions` depending on your Python/pip setup. +## Questions about the Book +You can find general questions and descriptive information about the book on the [Classic Computer Science Problems](https://classicproblems.com/) website. Also, feel free to reach out to me on Twitter, [@davekopec](https://twitter.com/davekopec). If you think you found an error in the source code, please open an issue up here on GitHub. + +## Free Content Based on the Book +- [Article: Constraint-Satisfaction Problems in Python](https://freecontent.manning.com/constraint-satisfaction-problems-in-python/) + ## License All of the source code in this repository is released under the Apache License version 2.0. See `LICENSE`. -## Other Books in the Series +## Other Books and Languages This is the second book in the Classic Computer Science Problems series by David Kopec and published by Manning. It aims to teach classic computer science problems in a Pythonic way. You may also want to checkout the first book in the series, *Classic Computer Science Problems in Swift*, which covers most of the same problems in a more Swifty way. You can check out the repository for that book on [GitHub as well](https://github.com/davecom/ClassicComputerScienceProblemsInSwift). A reader has also reimplemented the first five chapters of the book [in C++](https://github.com/araya-andres/classic_computer_sci). diff --git a/cover.jpg b/cover.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a9739eab12a10cd3f9ed66af7317243658bf14b6 GIT binary patch literal 12894 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 VZ1S|j!8Wt_H`&JoDABN){{uHBXfFT& literal 0 HcmV?d00001 From 06fcd49edaa6820bc14367c80d46e7bf33865bb3 Mon Sep 17 00:00:00 2001 From: David Kopec Date: Fri, 15 Mar 2019 12:54:58 -0400 Subject: [PATCH 11/25] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index df3d725..3ff43c9 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # Classic Computer Science Problems in Python This repository contains source code to accompany the book *Classic Computer Science Problems in Python* by David Kopec. You will find the source organized by chapter. **As you read the book, each code listing contains a file name that corresponds to a file in this repository.** + ![Classic Computer Science Problems in Python Cover](cover.jpg) ## Get the Book From 57d5f945e20eab0b88bea202d5a01e7318a5a613 Mon Sep 17 00:00:00 2001 From: David Kopec Date: Fri, 15 Mar 2019 12:55:50 -0400 Subject: [PATCH 12/25] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ff43c9..8ee2be4 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This repository contains source code to accompany the book *Classic Computer Sci ![Classic Computer Science Problems in Python Cover](cover.jpg) ## Get the Book -- [Manning](https://www.manning.com/books/classic-computer-science-problems-in-python) the publisher sells both hard copy and DRM-free eBook editions. +- [Manning](https://www.manning.com/books/classic-computer-science-problems-in-python) the publisher sells both hard copy and DRM-free eBook editions - [Amazon](https://amzn.to/2ui96Op) if you buy the hard copy from Amazon, it will come with a way to download the eBook for free from the publisher ## Versioning and Packages From 4ed4ba0ce4ca75093e29ffefe2d02d1151465cf0 Mon Sep 17 00:00:00 2001 From: David Kopec Date: Thu, 12 Dec 2019 02:42:49 -0500 Subject: [PATCH 13/25] fixed off by one error; closes #13 --- Chapter3/word_search.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Chapter3/word_search.py b/Chapter3/word_search.py index 890a0d5..c6a6085 100644 --- a/Chapter3/word_search.py +++ b/Chapter3/word_search.py @@ -43,8 +43,8 @@ def generate_domain(word: str, grid: Grid) -> List[List[GridLocation]]: length: int = len(word) for row in range(height): for col in range(width): - columns: range = range(col, col + length + 1) - rows: range = range(row, row + length + 1) + columns: range = range(col, col + length) + rows: range = range(row, row + length) if col + length <= width: # left to right domain.append([GridLocation(row, c) for c in columns]) From 742bc9d34f2332e28d2c0b8c8c24b3efcc9599ad Mon Sep 17 00:00:00 2001 From: SuperManEver Date: Fri, 5 Jun 2020 13:40:51 +0500 Subject: [PATCH 14/25] adjust type annotation --- Chapter4/mst.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter4/mst.py b/Chapter4/mst.py index 0fbaeaf..d9f7ba1 100644 --- a/Chapter4/mst.py +++ b/Chapter4/mst.py @@ -31,7 +31,7 @@ def mst(wg: WeightedGraph[V], start: int = 0) -> Optional[WeightedPath]: return None result: WeightedPath = [] # holds the final MST pq: PriorityQueue[WeightedEdge] = PriorityQueue() - visited: [bool] = [False] * wg.vertex_count # where we've been + visited: List[bool] = [False] * wg.vertex_count # where we've been def visit(index: int): visited[index] = True # mark as visited From 4c0fec9bee622fddc2ea485810c667f0acd09cb9 Mon Sep 17 00:00:00 2001 From: David Kopec Date: Wed, 24 Jun 2020 20:42:34 -0400 Subject: [PATCH 15/25] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8ee2be4..d5f9cf9 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This repository contains source code to accompany the book *Classic Computer Sci ![Classic Computer Science Problems in Python Cover](cover.jpg) ## Get the Book -- [Manning](https://www.manning.com/books/classic-computer-science-problems-in-python) the publisher sells both hard copy and DRM-free eBook editions +- [Manning](https://www.manning.com/books/classic-computer-science-problems-in-python?a_aid=oaksnow&a_bid=d326fe0b) the publisher sells both hard copy and DRM-free eBook editions - [Amazon](https://amzn.to/2ui96Op) if you buy the hard copy from Amazon, it will come with a way to download the eBook for free from the publisher ## Versioning and Packages From de7015e5fc3b23535d17879574d9ba316fbab389 Mon Sep 17 00:00:00 2001 From: David Kopec Date: Wed, 24 Jun 2020 20:57:24 -0400 Subject: [PATCH 16/25] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d5f9cf9..482c76f 100644 --- a/README.md +++ b/README.md @@ -20,4 +20,6 @@ You can find general questions and descriptive information about the book on the All of the source code in this repository is released under the Apache License version 2.0. See `LICENSE`. ## Other Books and Languages -This is the second book in the Classic Computer Science Problems series by David Kopec and published by Manning. It aims to teach classic computer science problems in a Pythonic way. You may also want to checkout the first book in the series, *Classic Computer Science Problems in Swift*, which covers most of the same problems in a more Swifty way. You can check out the repository for that book on [GitHub as well](https://github.com/davecom/ClassicComputerScienceProblemsInSwift). A reader has also reimplemented the first five chapters of the book [in C++](https://github.com/araya-andres/classic_computer_sci). +- [Classic Computer Science Problems in Java](https://github.com/davecom/ClassicComputerScienceProblemsInJava) +- [Classic Computer Science Problems in Swift](https://github.com/davecom/ClassicComputerScienceProblemsInSwift) +- [A Reimplementation of the Book in C++ (not by the author)](https://github.com/araya-andres/classic_computer_sci) From fae25cbf0dea053447efa7030a273bd414998c2b Mon Sep 17 00:00:00 2001 From: David Kopec Date: Thu, 20 Aug 2020 00:12:42 -0400 Subject: [PATCH 17/25] Update README.md --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 482c76f..f535748 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,12 @@ You can find general questions and descriptive information about the book on the All of the source code in this repository is released under the Apache License version 2.0. See `LICENSE`. ## Other Books and Languages +Official Books from the Series by @davecom - [Classic Computer Science Problems in Java](https://github.com/davecom/ClassicComputerScienceProblemsInJava) - [Classic Computer Science Problems in Swift](https://github.com/davecom/ClassicComputerScienceProblemsInSwift) -- [A Reimplementation of the Book in C++ (not by the author)](https://github.com/araya-andres/classic_computer_sci) + +Ports +- [C++ implementation by @aray-andres](https://github.com/araya-andres/classic_computer_sci) +- [Go implementation by @arlima](https://github.com/arlima/problemas_classicos_CC) +- [PHP implementation by @SaschaKersken (German translator of CCSPiP)](https://github.com/SaschaKersken/ClassicComputerScienceProblemsInPhp) +- [JavaScript implementation by @SaschaKersken (German translator of CCSPiP)](https://github.com/SaschaKersken/ClassicComputerScienceProblemsInJavaScript) From 8a164b6c2153cecf744a742c691274c538444200 Mon Sep 17 00:00:00 2001 From: David Kopec Date: Mon, 26 Oct 2020 14:21:00 -0400 Subject: [PATCH 18/25] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f535748..9099fac 100644 --- a/README.md +++ b/README.md @@ -29,3 +29,4 @@ Ports - [Go implementation by @arlima](https://github.com/arlima/problemas_classicos_CC) - [PHP implementation by @SaschaKersken (German translator of CCSPiP)](https://github.com/SaschaKersken/ClassicComputerScienceProblemsInPhp) - [JavaScript implementation by @SaschaKersken (German translator of CCSPiP)](https://github.com/SaschaKersken/ClassicComputerScienceProblemsInJavaScript) +- [Ruby implementation by @tj84](https://github.com/tj84/cs_problems) From d7538915a57dfd13a1bb258896ef9e0f481223fa Mon Sep 17 00:00:00 2001 From: Kyungwon Chun Date: Mon, 2 Oct 2023 09:03:07 +0000 Subject: [PATCH 19/25] Update word_search.py Fix the conditional to check the valid location of the diagonal towards the bottom left. --- Chapter3/word_search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter3/word_search.py b/Chapter3/word_search.py index c6a6085..9606c0f 100644 --- a/Chapter3/word_search.py +++ b/Chapter3/word_search.py @@ -55,7 +55,7 @@ def generate_domain(word: str, grid: Grid) -> List[List[GridLocation]]: # top to bottom domain.append([GridLocation(r, col) for r in rows]) # diagonal towards bottom left - if col - length >= 0: + if col + 1 - length >= 0: domain.append([GridLocation(r, col - (r - row)) for r in rows]) return domain From 5e030219fc1b37cc8f0cd67b0f8f8191eb7a9dbb Mon Sep 17 00:00:00 2001 From: Kyungwon Chun Date: Wed, 29 Nov 2023 23:45:47 +0900 Subject: [PATCH 20/25] Address vulnerability in mutable default argument https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments --- Chapter4/graph.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Chapter4/graph.py b/Chapter4/graph.py index f08601e..1622355 100644 --- a/Chapter4/graph.py +++ b/Chapter4/graph.py @@ -21,7 +21,9 @@ class Graph(Generic[V]): - def __init__(self, vertices: List[V] = []) -> None: + def __init__(self, vertices: List[V] = None) -> None: + if vertices is None: + vertices = [] self._vertices: List[V] = vertices self._edges: List[List[Edge]] = [[] for _ in vertices] From ec77cef025ef3d55d9c88306350f3112620e1aa9 Mon Sep 17 00:00:00 2001 From: Kyungwon Chun Date: Fri, 1 Dec 2023 07:31:38 +0900 Subject: [PATCH 21/25] Add Optional to type annotation for vertices parameter The 'vertices' parameter can be None; thus, include 'Optional' in the type annotation. --- Chapter4/graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter4/graph.py b/Chapter4/graph.py index 1622355..f92a5aa 100644 --- a/Chapter4/graph.py +++ b/Chapter4/graph.py @@ -21,7 +21,7 @@ class Graph(Generic[V]): - def __init__(self, vertices: List[V] = None) -> None: + def __init__(self, vertices: Optional[List[V]] = None) -> None: if vertices is None: vertices = [] self._vertices: List[V] = vertices From 3efaf0c45cc0762d6fec020dacfbe3ed93595a2b Mon Sep 17 00:00:00 2001 From: Kyungwon Chun Date: Sat, 2 Dec 2023 05:42:06 +0900 Subject: [PATCH 22/25] Address vulnerability in mutable default argument https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments --- Chapter4/weighted_graph.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Chapter4/weighted_graph.py b/Chapter4/weighted_graph.py index 0acb273..0a1d177 100644 --- a/Chapter4/weighted_graph.py +++ b/Chapter4/weighted_graph.py @@ -21,7 +21,9 @@ class WeightedGraph(Generic[V], Graph[V]): - def __init__(self, vertices: List[V] = []) -> None: + def __init__(self, vertices: Optional[List[V]] = None) -> None: + if vertices is None: + vertices = [] self._vertices: List[V] = vertices self._edges: List[List[WeightedEdge]] = [[] for _ in vertices] From 9310ac0ab946c0a91cc730e62b36ed641009a300 Mon Sep 17 00:00:00 2001 From: Kyungwon Chun Date: Sun, 3 Dec 2023 06:25:28 +0900 Subject: [PATCH 23/25] Add missing import --- Chapter4/weighted_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter4/weighted_graph.py b/Chapter4/weighted_graph.py index 0a1d177..e96d5fa 100644 --- a/Chapter4/weighted_graph.py +++ b/Chapter4/weighted_graph.py @@ -13,7 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import TypeVar, Generic, List, Tuple +from typing import TypeVar, Generic, List, Tuple, Optional from graph import Graph from weighted_edge import WeightedEdge From 203d7cacec139bcc0a400e2cbed524791e970b9b Mon Sep 17 00:00:00 2001 From: David Kopec Date: Sat, 13 Jan 2024 11:28:48 -0500 Subject: [PATCH 24/25] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9099fac..0f5fbff 100644 --- a/README.md +++ b/README.md @@ -30,3 +30,4 @@ Ports - [PHP implementation by @SaschaKersken (German translator of CCSPiP)](https://github.com/SaschaKersken/ClassicComputerScienceProblemsInPhp) - [JavaScript implementation by @SaschaKersken (German translator of CCSPiP)](https://github.com/SaschaKersken/ClassicComputerScienceProblemsInJavaScript) - [Ruby implementation by @tj84](https://github.com/tj84/cs_problems) +- [Rust implementation by @marpetercontribs](https://github.com/marpetercontribs/classic-computer-science-problems-in-rust) From 1ce96baa128bc94fafcc418c4d136e4b47dc868a Mon Sep 17 00:00:00 2001 From: David Kopec Date: Sun, 9 Mar 2025 19:51:16 -0400 Subject: [PATCH 25/25] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 0f5fbff..b02c6ad 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,9 @@ Official Books from the Series by @davecom - [Classic Computer Science Problems in Java](https://github.com/davecom/ClassicComputerScienceProblemsInJava) - [Classic Computer Science Problems in Swift](https://github.com/davecom/ClassicComputerScienceProblemsInSwift) +My Latest Book +- [Computer Science from Scratch: Building Interpreters, Art, Emulators and ML in Python](https://github.com/davecom/ComputerScienceFromScratch) + Ports - [C++ implementation by @aray-andres](https://github.com/araya-andres/classic_computer_sci) - [Go implementation by @arlima](https://github.com/arlima/problemas_classicos_CC)