From 627df08f6ec54e9dbe8b2ef616fe7b0288d3edf2 Mon Sep 17 00:00:00 2001 From: Shoaib Dar Date: Sat, 14 Jan 2023 10:39:17 -0500 Subject: [PATCH 01/10] more simple and clear solution for 1.7 - Rotate Matrix --- .../1.7 - Rotate Matrix/rotateMatrix2.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 chapter01/1.7 - Rotate Matrix/rotateMatrix2.js diff --git a/chapter01/1.7 - Rotate Matrix/rotateMatrix2.js b/chapter01/1.7 - Rotate Matrix/rotateMatrix2.js new file mode 100644 index 0000000..9e5e080 --- /dev/null +++ b/chapter01/1.7 - Rotate Matrix/rotateMatrix2.js @@ -0,0 +1,22 @@ +function rotateMatrix(matrix) { + // Create a new matrix with the same dimensions as the original + const n = matrix.length; + const rotatedMatrix = new Array(n).fill(0).map(() => new Array(n).fill(0)); + + // Iterate through the original matrix's rows + for (let i = 0; i < matrix.length; i++) { + // Iterate through the original matrix's columns + for (let j = 0; j < matrix[i].length; j++) { + // Rotate the matrix by placing the original matrix's column in the new matrix's row + rotatedMatrix[j][matrix.length - 1 - i] = matrix[i][j]; + } + } + return rotatedMatrix; +} + +const testMatrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]; +console.log('initial matrix:') +console.log(testMatrix); +const rotatedMatrix = rotateMatrix(testMatrix); +console.log('rotated matrix:') +console.log(rotatedMatrix); \ No newline at end of file From 280632934c0c644d53612cdf073fd1742a30b6f1 Mon Sep 17 00:00:00 2001 From: Shoaib Dar Date: Fri, 20 Jan 2023 14:34:29 -0500 Subject: [PATCH 02/10] added additional way to do buildOrder - 4.7 --- chapter04/4.07 - Build Order/buildOrder2.js | 37 +++++++++++++++++++ .../firstCommonAncestor2.js | 19 ++++++++++ 2 files changed, 56 insertions(+) create mode 100644 chapter04/4.07 - Build Order/buildOrder2.js create mode 100644 chapter04/4.08 - First Common Ancestor/firstCommonAncestor2.js diff --git a/chapter04/4.07 - Build Order/buildOrder2.js b/chapter04/4.07 - Build Order/buildOrder2.js new file mode 100644 index 0000000..cb7fa4c --- /dev/null +++ b/chapter04/4.07 - Build Order/buildOrder2.js @@ -0,0 +1,37 @@ +const buildOrder2 = (projects, dependencies) => { + let graph = {}; + let totalDegrees = {}; + let queue = []; + let order = []; + + //create graph and totalDegrees + for (let project of projects) { + graph[project] = []; + totalDegrees[project] = 0; + } + + //add edges and degree count + for(let [from, to] of dependencies){ + graph[from].push(to) + totalDegrees[to]++; + } + + //add nodes with 0 degrees to the queue + for(let project in totalDegrees) + if (totalDegrees[project] === 0) + queue.push(project) + + //perform topological sorting + while(queue.length> 0){ + let current = queue.shift(); + order.push(current); + for(let neighbor of graph[current]){ + totalDegrees[neighbor]--; + if(totalDegrees[neighbor]===0) + queue.push(neighbor) + } + } + if(order.length!== projects.length) throw Error + + return order; +} \ No newline at end of file diff --git a/chapter04/4.08 - First Common Ancestor/firstCommonAncestor2.js b/chapter04/4.08 - First Common Ancestor/firstCommonAncestor2.js new file mode 100644 index 0000000..19d8910 --- /dev/null +++ b/chapter04/4.08 - First Common Ancestor/firstCommonAncestor2.js @@ -0,0 +1,19 @@ +class Node { + constructor(value) { + this.value = value; + this.left = null; + this.right = null; + } +} + +function findCommonAncestor(root, node1, node2) { + if (!root) return null; + if (root === node1 || root === node2) return root; + + let left = findCommonAncestor(root.left, node1, node2); + let right = findCommonAncestor(root.right, node1, node2); + + if (left && right) return root; + + return left ? left : right; +} \ No newline at end of file From eed9e45b6cdd65b272166dfe2c0503654c686c81 Mon Sep 17 00:00:00 2001 From: Shoaib Dar Date: Fri, 20 Jan 2023 15:16:29 -0500 Subject: [PATCH 03/10] additional answer for 4.01 Route Between Nodes --- .../routeBetweenNodes2.js | 42 +++++++++++++++++++ .../firstCommonAncestor2.js | 19 ++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 chapter04/4.01 - Route Between Nodes/routeBetweenNodes2.js diff --git a/chapter04/4.01 - Route Between Nodes/routeBetweenNodes2.js b/chapter04/4.01 - Route Between Nodes/routeBetweenNodes2.js new file mode 100644 index 0000000..e40049b --- /dev/null +++ b/chapter04/4.01 - Route Between Nodes/routeBetweenNodes2.js @@ -0,0 +1,42 @@ +const Graph = require('./../util/Graph'); + +Graph.prototype.hasRoute = function(startNode, endNode) { + if (!this.hasNode(startNode) || !this.hasNode(endNode)) { + return 'One or both of the nodes do not exist in the graph'; + } + let queue = [startNode]; + let visited = new Set(); + while (queue.length > 0) { + let currentNode = queue.shift(); + visited.add(currentNode); + for (let edge in this.findEdges(currentNode)) { + if (edge === endNode) { + return true; + } + if (!visited.has(edge)) { + queue.push(edge); + } + } + } + return false; +}; + +/* TEST */ +const graph = new Graph(); +graph.addNode('A'); +graph.addNode('B'); +graph.addNode('C'); +graph.addNode('D'); +graph.addNode('E'); + +graph.addEdge('A', 'B'); +graph.addEdge('A', 'C'); +graph.addEdge('B', 'C'); + +graph.addEdge('D', 'E'); + + +console.log(graph.hasRoute('A', 'C', graph), true); +console.log(graph.hasRoute('A', 'E', graph), false); +console.log(graph.hasRoute('B', 'A', graph), true); +console.log(graph.hasRoute('D', 'E', graph), true); \ No newline at end of file diff --git a/chapter04/4.08 - First Common Ancestor/firstCommonAncestor2.js b/chapter04/4.08 - First Common Ancestor/firstCommonAncestor2.js index 19d8910..e643cc5 100644 --- a/chapter04/4.08 - First Common Ancestor/firstCommonAncestor2.js +++ b/chapter04/4.08 - First Common Ancestor/firstCommonAncestor2.js @@ -16,4 +16,21 @@ function findCommonAncestor(root, node1, node2) { if (left && right) return root; return left ? left : right; -} \ No newline at end of file +} + +const root = new Node(1); +root.left = new Node(2); +root.right = new Node(3); +root.left.left = new Node(4); +root.left.right = new Node(5); +root.right.left = new Node(6); +root.right.right = new Node(7); + +let node1 = root.right.left; //6 +let node2 = root.right.right; //7 +console.log(findCommonAncestor(root, node1, node2).value); // Outputs: 3 + +node1 = root.left.left; // 4 +node2 = root.left.right; // 5 + +console.log(findCommonAncestor(root, node1, node2).value); // Outputs: 2 \ No newline at end of file From 3c7d847ac388f035ea4e2bee79beeb05331889c4 Mon Sep 17 00:00:00 2001 From: Shoaib Dar Date: Fri, 20 Jan 2023 18:23:59 -0500 Subject: [PATCH 04/10] better solution for 4.02 minimial tree --- chapter04/4.02 - Minimal Tree/minimalTree2.js | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 chapter04/4.02 - Minimal Tree/minimalTree2.js diff --git a/chapter04/4.02 - Minimal Tree/minimalTree2.js b/chapter04/4.02 - Minimal Tree/minimalTree2.js new file mode 100644 index 0000000..71a1e90 --- /dev/null +++ b/chapter04/4.02 - Minimal Tree/minimalTree2.js @@ -0,0 +1,37 @@ +const BST = require('./../util/BST'); + +const createMinimalBST = (arr) => { + return createMinimalBSTHelper(arr, 0, arr.length - 1); +}; + +const createMinimalBSTHelper = (arr, start, end) => { + if (end < start) { + return null; + } + let mid = Math.floor((start + end) / 2); + let bst = new BST(arr[mid]); + bst.left = createMinimalBSTHelper(arr, start, mid - 1); + bst.right = createMinimalBSTHelper(arr, mid + 1, end); + return bst; +}; + +const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; +let root = createMinimalBST(arr); +root.printLevelOrder(); + +const arr2 = [1, 2, 3, 4, 5, 6, 7]; +root = createMinimalBST(arr2); +root.printLevelOrder(); + +// This algorithm uses a divide and conquer approach to create the binary search tree, +//similar to the previous example. It starts by finding the middle element in the array +//and creating a new BST object with that value. Then it recursively creates the left and +// right subtrees by calling the same function on the left and right halves of the original array. + +// The key idea is that by choosing the middle element of the array as the root, we ensure that the tree +//is balanced and the height is minimal. Because the array is sorted and it's unique, the left and right +//subtrees will also be balanced and the tree will be a minimal height binary search tree. + +// This algorithm has a time complexity of O(n) and a space complexity of O(n) where n is the number of elements +//in the array because it uses a recursive call for each element of the array and constructs a new BST object for +// each element. From 3f60285575570062d19315b5c624f6912f70a9b0 Mon Sep 17 00:00:00 2001 From: Shoaib Dar Date: Fri, 20 Jan 2023 20:51:23 -0500 Subject: [PATCH 05/10] list of deatphs 4.03 solution --- .../4.03 - List of Depths/listOfDeatphs2.js | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 chapter04/4.03 - List of Depths/listOfDeatphs2.js diff --git a/chapter04/4.03 - List of Depths/listOfDeatphs2.js b/chapter04/4.03 - List of Depths/listOfDeatphs2.js new file mode 100644 index 0000000..c96ded5 --- /dev/null +++ b/chapter04/4.03 - List of Depths/listOfDeatphs2.js @@ -0,0 +1,71 @@ +class Node { + constructor(value) { + this.value = value; + this.left = null; + this.right = null; + } +} + +class LinkedList { + constructor() { + this.head = null; + this.tail = null; + } + + addNode(node) { + if (this.tail) { + this.tail.next = node; + this.tail = node; + } else { + this.head = node; + this.tail = node; + } + } +} + +const createLinkedLists = (root) => { + let lists = []; + createLinkedListsHelper(root, lists, 0); + return lists; +}; + +const createLinkedListsHelper = (root, lists, level) => { + if (!root) return; + let list; + if (lists.length === level) { + list = new LinkedList(); + lists.push(list); + } else { + list = lists[level]; + } + list.addNode(root); + createLinkedListsHelper(root.left, lists, level + 1); + createLinkedListsHelper(root.right, lists, level + 1); +}; + +let root = new Node(1); +root.left = new Node(2); +root.right = new Node(3); +root.left.left = new Node(4); +root.left.right = new Node(5); +root.right.left = new Node(6); +root.right.right = new Node(7); + +console.log(createLinkedLists(root)); + +/* + +This algorithm uses a depth-first traversal approach, it creates a new linked list for each level of the tree and +uses recursion to traverse through the tree. It starts by initializing an empty array called lists that will hold +the linked lists for each level of the tree. Then, it calls the helper function createLinkedListsHelper to traverse +through the tree and create the linked lists. + +In the helper function, first it checks if the current node is null, if so it returns. Then, it checks if the current +level of the tree is already in the lists array. If it is not, it creates a new linked list, otherwise, it gets the +current linked list. Then it adds the current node to the current linked list. Finally, it recursively calls the +helper function on the left and right children of the current node, and increments the level by 1. + +The time complexity of this algorithm is O(n) where n is the number of nodes in the tree, and space complexity is O(d) +where d is the depth of the tree, because it creates a linked list for each level of the tree. + +*/ \ No newline at end of file From 31f75fc8bed6e6616c78b2c58b50352d03e1f57b Mon Sep 17 00:00:00 2001 From: Shoaib Dar Date: Fri, 20 Jan 2023 22:17:09 -0500 Subject: [PATCH 06/10] added file on trie --- .../{listOfDeatphs2.js => listOfDepths2.js} | 0 .../4.13 - Real World Examples/about.txt | 9 +++ .../4.13 - Real World Examples/realworld.txt | 33 +++++++++ chapter04/4.14 - Extra/Trie.js | 72 +++++++++++++++++++ 4 files changed, 114 insertions(+) rename chapter04/4.03 - List of Depths/{listOfDeatphs2.js => listOfDepths2.js} (100%) create mode 100644 chapter04/4.13 - Real World Examples/about.txt create mode 100644 chapter04/4.13 - Real World Examples/realworld.txt create mode 100644 chapter04/4.14 - Extra/Trie.js diff --git a/chapter04/4.03 - List of Depths/listOfDeatphs2.js b/chapter04/4.03 - List of Depths/listOfDepths2.js similarity index 100% rename from chapter04/4.03 - List of Depths/listOfDeatphs2.js rename to chapter04/4.03 - List of Depths/listOfDepths2.js diff --git a/chapter04/4.13 - Real World Examples/about.txt b/chapter04/4.13 - Real World Examples/about.txt new file mode 100644 index 0000000..9930b6d --- /dev/null +++ b/chapter04/4.13 - Real World Examples/about.txt @@ -0,0 +1,9 @@ +In-order, pre-order, and post-order traversal are all methods of traversing a binary tree, but they differ in the order in which they visit the nodes. + +In-order traversal visits the left subtree first, then the current node, and finally the right subtree. This order is useful for sorting elements in a binary search tree, as it visits the nodes in a sorted order. + +Pre-order traversal visits the current node first, then the left subtree, and finally the right subtree. This order is useful for representing a file system hierarchy, where the parent node is visited before its children. + +Post-order traversal visits the left subtree first, then the right subtree, and finally the current node. This order is useful for deleting a tree or a subtree efficiently. + +In summary, In-order traversal visits left subtree first, then root and then right subtree. Pre-order traversal visits root first, then left subtree and then right subtree. Post-order traversal visits left subtree first, then right subtree and then root. \ No newline at end of file diff --git a/chapter04/4.13 - Real World Examples/realworld.txt b/chapter04/4.13 - Real World Examples/realworld.txt new file mode 100644 index 0000000..77619bf --- /dev/null +++ b/chapter04/4.13 - Real World Examples/realworld.txt @@ -0,0 +1,33 @@ +Binary Tree In-order traversal is a way to visit all the nodes of a binary tree in a specific order. Some real-world examples where this traversal method could be used include: + +Sorting algorithms: In-order traversal can be used to sort elements in a binary search tree, since it visits the nodes in a sorted order. + +Database indexing: In-order traversal can be used to traverse a B-Tree, which is a type of self-balancing search tree used in databases to optimize search performance. + +Compiler Design: In-order traversal can be used to generate the three address code in the intermediate code generation phase of a compiler. + +Expression Trees: In-order traversal can be used to evaluate mathematical expressions represented as expression trees. It will give the infix notation of the expression. + +Other Applications: In-order traversal is also used in a few other applications like creating a thread-safe iterator, serializing a tree into a list, etc. + +It is important to note that there are other traversal methods such as pre-order, post-order and level-order traversal that can also be used for various use cases depending on the requirements and the tree structure. + +File System: Pre-order traversal can be used to represent a file system hierarchy, where the parent node is visited before its children. This corresponds to the way file systems are typically represented in a file explorer, where the directory is listed before its contents. + + + +A min-heap is a specific type of binary heap data structure where the root node is the node with the smallest value. Here are a few examples of real-life scenarios where a min-heap could be used: + +Priority Queue: A min-heap can be used to implement a priority queue, where each element has a priority associated with it. The element with the smallest priority is always on top of the heap. + +Dijkstra's algorithm: Dijkstra's algorithm is a shortest-path algorithm that uses a min-heap to efficiently find the next closest vertex to visit. + +Huffman coding: Huffman coding is an algorithm used for lossless data compression that uses a min-heap to efficiently construct a Huffman tree. + +Median maintenance: A min-heap can be used to efficiently maintain the median of a stream of numbers. + +Event-driven simulation: A min-heap can be used to efficiently schedule the next event in a simulation by ordering events by their timestamp + +Resource allocation: A min-heap can be used to allocate resources efficiently, where resources with the least usage are allocated first. + + diff --git a/chapter04/4.14 - Extra/Trie.js b/chapter04/4.14 - Extra/Trie.js new file mode 100644 index 0000000..4bc79de --- /dev/null +++ b/chapter04/4.14 - Extra/Trie.js @@ -0,0 +1,72 @@ +/* +A Trie (Prefix Tree) is a tree-like data structure that is used to store an associative array where the keys are sequences, usually strings. Here's a simple example where a Trie could be used: + +Let's say we have a list of words: "apple", "banana", "cherry", "orange" and "pear" + +We can use a Trie to efficiently store and search for these words. Each character in a word is inserted as a new node in the Trie. + +To search for a word, we start at the root and follow the edges corresponding to each character in the word. If we reach a null edge (indicating that the word is not in the Trie), we know that the word is not present. If we reach a leaf node (indicating the end of a word), we know that the word is present in the Trie. + +For example, to search for the word "cherry", we start at the root and follow the edges corresponding to 'c', 'h', 'e', 'r', 'r' and 'y'. We reach a leaf node, indicating that the word "cherry" is present in the Trie. + +In summary, Trie is a tree-based data structure that is used to store a dynamic set or associative array where the keys are sequences, usually strings. It is used in many word processing application for efficient searching of words and prefixes. +*/ + +class Trie { + constructor() { + this.root = {}; + } + + //insert takes a word and adds it to the Trie by iterating through each character + // and creating a new node for each character if it doesn't already exist. + insert(word) { + let current = this.root; + + for (let char of word) { + if (!current[char]) { + current[char] = {}; + } + current = current[char]; + } + + current.isEnd = true; + } + + //search method takes a word and checks if it exists in the Trie by iterating + // through each character and checking if it exists in the Trie. + search(word) { + let current = this.root; + + for (let char of word) { + if (!current[char]) { + return false; + } + current = current[char]; + } + + return current.isEnd === true; + } + + // startsWith method takes a prefix and checks if it exists in the Trie by + // iterating through each character and checking if it exists in the Trie + startsWith(prefix) { + let current = this.root; + + for (let char of prefix) { + if (!current[char]) { + return false; + } + current = current[char]; + } + + return true; + } +} + +let trie = new Trie(); +trie.insert("apple"); +trie.insert("banana"); +trie.insert("cherry"); +console.log(trie.search("cherry")); // true +console.log(trie.startsWith("che")); // true +console.log(trie.search("app")); // false From c6f2debc50f8cbc0f4684b60ce842c5680bf1dcf Mon Sep 17 00:00:00 2001 From: Shoaib Dar Date: Thu, 26 Jan 2023 10:04:52 -0500 Subject: [PATCH 07/10] second solution for theApocalpyse 6.07 --- .../6.07 - The Apocalypse/theApocalypse2.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 chapter06/6.07 - The Apocalypse/theApocalypse2.js diff --git a/chapter06/6.07 - The Apocalypse/theApocalypse2.js b/chapter06/6.07 - The Apocalypse/theApocalypse2.js new file mode 100644 index 0000000..6a60508 --- /dev/null +++ b/chapter06/6.07 - The Apocalypse/theApocalypse2.js @@ -0,0 +1,19 @@ +function simulateGenderRatio() { + let boys = 0; + let girls = 0; + for (let i = 0; i < 10000; i++) { + let hasGirl = false; + while (!hasGirl) { + let baby = Math.random() < 0.5 ? "boy" : "girl"; + if (baby === "girl") { + hasGirl = true; + girls++; + } else { + boys++; + } + } + } + console.log(`boys: ${boys}, girls: ${girls}, ratio: ${boys/girls}`); + } + + simulateGenderRatio(); \ No newline at end of file From 553826c8f4cb4b7b1e45ce4e214a06c6c52131c2 Mon Sep 17 00:00:00 2001 From: Shoaib Dar Date: Thu, 26 Jan 2023 10:08:07 -0500 Subject: [PATCH 08/10] simple explanation for poison problem 6.10 --- chapter02/2.5 - Sum Lists/forward2.js | 49 +++++++++++++++++++ .../2.5 - Sum Lists/sumLists - forward.js | 1 + chapter06/6.10 - Poison/poison2.js | 17 +++++++ 3 files changed, 67 insertions(+) create mode 100644 chapter02/2.5 - Sum Lists/forward2.js create mode 100644 chapter06/6.10 - Poison/poison2.js diff --git a/chapter02/2.5 - Sum Lists/forward2.js b/chapter02/2.5 - Sum Lists/forward2.js new file mode 100644 index 0000000..60a25a6 --- /dev/null +++ b/chapter02/2.5 - Sum Lists/forward2.js @@ -0,0 +1,49 @@ +const LinkedList = require('../util/LinkedList') +const printList = require('../util/printList') + +function Node(data) { + this.data = data + this.next = null + } + + +function addLists(l1, l2) { + let dummy = new Node(0); + let current = dummy; // 1 + let carry = 0; + + while (l1 || l2) { + let x = l1 ? l1.data : 0; + let y = l2 ? l2.data : 0; + let sum = x + y + carry; + carry = Math.floor(sum / 10); // 0 + current.next = new Node(sum % 10); //7 + current = current.next; + if (l1) l1 = l1.next; + if (l2) l2 = l2.next; + } + + if (carry > 0) { + current.next = new Node(carry); + } + + return dummy.next; +} + +// First linked list (representing the number 543) +let l1 = new Node(3); +l1.next = new Node(4); + +// Second linked list (representing the number 678) +let l2 = new Node(8); +l2.next = new Node(2); + +// Add the two linked lists +let sum = addLists(l1, l2); + +// Print the sum +let current = sum; +while (current) { + console.log(current.data); + current = current.next; +} \ No newline at end of file diff --git a/chapter02/2.5 - Sum Lists/sumLists - forward.js b/chapter02/2.5 - Sum Lists/sumLists - forward.js index bbb7dd3..ca7fd7f 100644 --- a/chapter02/2.5 - Sum Lists/sumLists - forward.js +++ b/chapter02/2.5 - Sum Lists/sumLists - forward.js @@ -1,6 +1,7 @@ const LinkedList = require('./../util/LinkedList') const printList = require('./../util/printList') + function sumLinkedListsForward(list1, list2) { if (!list1 && !list2) { return null diff --git a/chapter06/6.10 - Poison/poison2.js b/chapter06/6.10 - Poison/poison2.js new file mode 100644 index 0000000..e19c599 --- /dev/null +++ b/chapter06/6.10 - Poison/poison2.js @@ -0,0 +1,17 @@ +// To figure out the poisoned bottle in as few days as possible, I would use a binary search algorithm to divide the bottles into smaller and smaller groups, testing a sample from each group until I find the poisoned bottle. + +// Here is one way to implement this algorithm: + +// Divide the 1000 bottles into 10 groups of 100 bottles each. +// Take one test strip and use it to test a sample of 10 bottles from the first group. +// If the test strip turns positive, then I know the poisoned bottle is in that group of 100 bottles. +// If the test strip is negative, repeat step 2 for the next group of 100 bottles, using a new test strip. +// Once I have narrowed down the poisoned bottle to a group of 100 bottles, I will repeat step 2, but this time testing 10 bottles from each of the 10 groups of 10 bottles within that group. +// I will continue narrowing down the group of bottles until I have isolated the poisoned bottle to a single bottle. +// It will take 7 days for the first test, 7 days for second test and so on. So total 7*log(1000) days. + +// A computer simulation of this algorithm would involve creating a function that takes in the number of bottles and test strips as input, and uses a while loop to repeatedly divide the group of bottles in half and test a sample from the group until the poisoned bottle is found. The function would output the number of days it takes to find the poisoned bottle. + + + + From d170ddb104ba4a4f18f688ec665b78359c82c86a Mon Sep 17 00:00:00 2001 From: Shoaib Dar Date: Fri, 27 Jan 2023 09:33:03 -0500 Subject: [PATCH 09/10] clearer example of blackjack class --- chapter07/7.01 - Deck of Cards/deck2.js | 126 ++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 chapter07/7.01 - Deck of Cards/deck2.js diff --git a/chapter07/7.01 - Deck of Cards/deck2.js b/chapter07/7.01 - Deck of Cards/deck2.js new file mode 100644 index 0000000..a5cc74f --- /dev/null +++ b/chapter07/7.01 - Deck of Cards/deck2.js @@ -0,0 +1,126 @@ +class Card { + constructor(rank, suit, value) { + this.rank = rank; + this.suit = suit; + this.value = value; + } +} + +class Deck { + constructor() { + this.cards = []; + const suits = ['hearts', 'diamonds', 'clubs', 'spades']; + const ranks = ['ace', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'jack', 'queen', 'king']; + const values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10]; + for (let i = 0; i < suits.length; i++) { + for (let j = 0; j < ranks.length; j++) { + const card = new Card(ranks[j], suits[i], values[j]); + this.cards.push(card); + } + } + } + + shuffle() { + for (let i = this.cards.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.cards[i], this.cards[j]] = [this.cards[j], this.cards[i]]; + } + } + + drawCard() { + return this.cards.pop(); + } + +} + +class Blackjack extends Deck{ + constructor() { + super(); + this.deck = new Deck(); + this.playerCards = []; + this.dealerCards = []; + this.playerScore = 0; + this.dealerScore = 0; + } + + start() { + this.deck.shuffle(); + this.playerCards.push(this.deck.drawCard()); + this.dealerCards.push(this.deck.drawCard()); + this.playerCards.push(this.deck.drawCard()); + this.dealerCards.push(this.deck.drawCard()); + this.playerScore = this.calculateScore(this.playerCards); + this.dealerScore = this.calculateScore(this.dealerCards); + } + + hit() { + this.playerCards.push(this.deck.drawCard()); + this.playerScore = this.calculateScore(this.playerCards); + } + + stand() { + while (this.dealerScore < 17) { + this.dealerCards.push(this.deck.drawCard()); + this.dealerScore = this.calculateScore(this.dealerCards); + } + } + + doubleDown() { + this.hit(); + // perform double down logic + } + + split() { + // perform split logic + } + + calculateScore(cards) { + let score = 0; + let aceCount = 0; + for (let i = 0; i < cards.length; i++) { + score += cards[i].value; + if (cards[i].rank === 'ace') { + aceCount++; + } + } + while (score > 21 && aceCount > 0) { + score -= 10; + aceCount--; + } + return score; + } + + checkWin() { + if (this.playerScore > 21) { + return "Player lost"; + } else if (this.dealerScore > 21) { + return "Player won"; + } else if (this.playerScore > this.dealerScore) { + return "Player won"; + } else if (this.playerScore < this.dealerScore) { + return "Player lost"; + } else { + return "Tie"; + } + } +} + +let game = new Blackjack(); +game.start(); +console.log("Player cards: ", game.playerCards); +console.log("Player score: ", game.playerScore); +console.log("Dealer cards: ", game.dealerCards); +console.log("Dealer score: ", game.dealerScore); + +// player chooses to hit +game.hit(); +console.log("Player cards: ", game.playerCards); +console.log("Player score: ", game.playerScore); + +// player chooses to stand +game.stand(); +console.log("Dealer cards: ", game.dealerCards); +console.log("Dealer score: ", game.dealerScore); + +// check the outcome of the game +console.log(game.checkWin()); From f3b8ed33aa47edf1288a7ccab7baa75e10892d7e Mon Sep 17 00:00:00 2001 From: Shoaib Dar Date: Fri, 3 Feb 2023 17:38:10 -0500 Subject: [PATCH 10/10] added jigsaw answer using classes --- chapter07/7.06 - Jigsaw/jigsaw2.js | 191 +++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 chapter07/7.06 - Jigsaw/jigsaw2.js diff --git a/chapter07/7.06 - Jigsaw/jigsaw2.js b/chapter07/7.06 - Jigsaw/jigsaw2.js new file mode 100644 index 0000000..8b3d9dd --- /dev/null +++ b/chapter07/7.06 - Jigsaw/jigsaw2.js @@ -0,0 +1,191 @@ +/* +One possible implementation of the NxN jigsaw puzzle is to use a 2D array to represent the puzzle and a queue to keep track of the unassembled pieces. Each cell in the 2D array will either contain a piece or be null. + +Here is the algorithm to solve the puzzle: + +Create a 2D array to represent the puzzle, with all cells initially set to null. +Create a queue of unassembled pieces. +Pick a piece from the queue and place it in the top-left cell of the puzzle. +Iterate over the neighbors of the current piece, and for each unassembled neighbor, check if it fits with one of the edges of the current piece using the fitsWith method. +If a fitting piece is found, add it to the puzzle, update the current piece to be the newly placed piece, and add its unassembled neighbors to the queue. +Repeat steps 4 and 5 until the queue is empty or there are no more fitting pieces. +If the puzzle is complete, return it. If not, backtrack to a previous piece and try a different fitting piece. +This algorithm uses a depth-first search approach to assemble the puzzle and backtracks when necessary to try different options. The time complexity of this algorithm is O(N^2 * 2^N), where N is the number of puzzle pieces, since each piece has at most 4 edges and each edge can either be assembled or not assembled. + +*/ + +class Edge { + constructor(isAssembled = false) { + this.isAssembled = isAssembled; + } +} + +class Piece { + constructor(edges) { + this.edges = edges; + } + + fitsWith(otherPiece) { + // Write the implementation to check if this piece fits with the other piece + } +} + +class Puzzle { + constructor(n, pieces, fitsWith) { + this.n = n; + this.pieces = pieces; + this.fitsWith = fitsWith; + this.grid = new Array(n).fill(null).map(() => new Array(n).fill(null)); + } + + addPiece(piece) { + this.pieces.push(piece); + } + + // Create an instance of the Puzzle class, with the desired size n. + // Add pieces to the puzzle by creating instances of the Piece class and calling the addPiece method on the puzzle instance. + // Call the solve method on the puzzle instance to solve the puzzle. + // Here's the implementation of the solve method: + + solve() { + // Create a queue of unassembled pieces + let queue = this.pieces.slice(); + + // Place a piece in the top-left cell of the puzzle + let currentPiece = queue.shift(); + this.grid[0][0] = currentPiece; + + // Repeat the following steps until the queue is empty or there are no more fitting pieces + while (queue.length > 0) { + let fits = false; + + // Iterate over the neighbors of the current piece + for (let i = 0; i < this.n; i++) { + for (let j = 0; j < this.n; j++) { + if (this.grid[i][j] === currentPiece) { + // Check the north, east, south, and west neighbors + if (i > 0 && this.grid[i - 1][j] === null) { + let nextPiece = this.fitsWith(currentPiece, "north"); + if (nextPiece) { + this.grid[i - 1][j] = nextPiece; + currentPiece = nextPiece; + queue.splice(queue.indexOf(nextPiece), 1); + fits = true; + break; + } + } + if (j < this.n - 1 && this.grid[i][j + 1] === null) { + let nextPiece = this.fitsWith(currentPiece, "east"); + if (nextPiece) { + this.grid[i][j + 1] = nextPiece; + currentPiece = nextPiece; + queue.splice(queue.indexOf(nextPiece), 1); + fits = true; + break; + } + } + if (i < this.n - 1 && this.grid[i + 1][j] === null) { + let nextPiece = this.fitsWith(currentPiece, "south"); + if (nextPiece) { + this.grid[i + 1][j] = nextPiece; + currentPiece = nextPiece; + queue.splice(queue.indexOf(nextPiece), 1); + fits = true; + break; + } + } + if (j > 0 && this.grid[i][j - 1] === null) { + let nextPiece = this.fitsWith(currentPiece, "west"); + if (nextPiece) { + this.grid[i][j - 1] = nextPiece; + currentPiece = nextPiece; + queue.splice(queue.indexOf(nextPiece), 1); + fits = true; + break; + } + } + } + if (fits) { + break; + } + } + if (!fits) { + // If no fitting piece was found, pick a piece from the queue and try again + currentPiece = queue.shift(); + // Find the first empty cell in the grid and place the piece there + for (let i = 0; i < this.n; i++) { + for (let j = 0; j < this.n; j++) { + if (this.grid[i][j] === null) { + this.grid[i][j] = currentPiece; + break; + } + } + } + } + } + } + + } +} + +/* +This algorithm continues to find fitting pieces for the current piece and places them in the grid until there are no more pieces left in the queue. If no fitting piece is found, it picks a new piece from the queue and continues the process until the entire puzzle is solved. + +*/ + + +// Define a fitsWith method +function fitsWith(edge1, edge2) { + if (edge1.type === "top" && edge2.type === "bottom") { + return edge1.color === edge2.color; + } + if (edge1.type === "left" && edge2.type === "right") { + return edge1.color === edge2.color; + } + return false; + } + + // Define some puzzle pieces + const pieces = [ + new Piece([ + new Edge("top", "red"), + new Edge("right", "blue"), + new Edge("bottom", "green"), + new Edge("left", "yellow") + ]), + new Piece([ + new Edge("top", "yellow"), + new Edge("right", "red"), + new Edge("bottom", "blue"), + new Edge("left", "green") + ]), + new Piece([ + new Edge("top", "green"), + new Edge("right", "yellow"), + new Edge("bottom", "red"), + new Edge("left", "blue") + ]), + new Piece([ + new Edge("top", "blue"), + new Edge("right", "green"), + new Edge("bottom", "yellow"), + new Edge("left", "red") + ]), + // Add more pieces here... + ]; + + // Create a new puzzle + const puzzle = new Puzzle(4, pieces, fitsWith); + + // Place the first piece in the top-left corner of the grid +puzzle.grid[0][0] = pieces[0]; + + + // Solve the puzzle + puzzle.solve(); + + // Print the solved puzzle + for (const row of puzzle.grid) { + console.log(row); + } + \ No newline at end of file