Learn to Code via Tutorials on Repl.it

Posts
Pinned
โ–ฒ
3
LLC GOLANG: Web apps & structs (Videos 5+6)
## Hi everyone! This week, we'll focus on: * [Creating a simple web app](https://www.youtube.com/watch?v=-QmdZ7821wA) * [Structs](https://www.youtube.com/watch?v=3fsvqo9pQyg) **Weekly Quiz:** Quiz yourself on last week's concepts [here](https://forms.gle/CAn1mx8j4R5j74y39 ). This week's quiz is self-grading, so there's... ๐Ÿฅ๐Ÿฅ๐Ÿฅ no due date! If you completed last week's quiz, you should have received your scores tonight, Tuesday, May 14th. **Next week's quiz** By Sunday, 5/19, please make sure you post your new quiz questions below. Please only include items covered in videos 1-6. 'Til next week, friends!
4
posted by katyadee (429) 7 days ago
โ–ฒ
18
๐ŸŒš๐Ÿ•ถ How to Enable Repl.it Site-Wide Dark Theme ๐Ÿ•ถ๐ŸŒš
# Repl.it Site-Wide Dark Theme Do you like not being blinded while browsing Repl.it? Well me neither! ![Repl talk on dark theme](https://storage.googleapis.com/replit/images/1557091294976_160fda0e32057fb2f3a93d971d4a4203.pn) *** First, you might not have the editor dark theme enabled, so make sure you enable that. 1. Click the settings button at the left of the editor screen. ![Settings Button](https://storage.googleapis.com/replit/images/1557091461609_7a585f76190494f3bc741389062781a0.pn) 2. Find the theme dropdown, and select *dark* ![theme dark](https://storage.googleapis.com/replit/images/1557091792258_8f89ba2a4630090419013d3220ddbd0d.pn) *** Now that you have the editor dark theme enabled, we will enable the site-wide dark theme. 1. Download Tampermonkey for [Chrome](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo) or [Firefox](https://addons.mozilla.org/en-US/firefox/addon/tampermonkey/) 2. Choose a theme from [the list of themes](https://www.darktheme.tk/themes) or [create your own](https://www.darktheme.tk/custom) 3. Click the `install` button. 4. Upvote and post a comment on this tutorial. 5. Profit!
18
posted by mat1 (2027) 17 days ago
โ–ฒ
9
BOOKMARKLETS!
# What is a bookmarklet? A bookmarklet is similar to an extension, but is used by clicking a bookmark. According to wikipedia: > A bookmarklet is a bookmark stored in a web browser that contains JavaScript commands that add new features to the browser. Bookmarklets are unobtrusive JavaScripts stored as the URL of a bookmark in a web browser or as a hyperlink on a web page. Bookmarklets are usually JavaScript programs. Regardless of whether bookmarklet utilities are stored as bookmarks or hyperlinks, they add one-click functions to a browser or web page. When clicked, a bookmarklet performs one of a wide variety of operations, such as running a search query or extracting data from a table. For example, clicking on a bookmarklet after selecting text on a webpage could run an Internet search on the selected text and display a search engine results page. # Create a bookmarklet Creating a bookmarklet is easy. (If you do know how to create a bookmark. If not read [Creating A Bookmark](https://www.computerhope.com/issues/ch000858.htm) ) Let's create a simple example: First, create a bookmark. As for the title of the bookmark, name it โ€œHello Worldโ€. Instead of keeping the url of the page as the bookmark type `javascript:alert(โ€˜Hello World!โ€™)`. There! Click save or whatever it is in your search engine. And click the bookmark. You should have an alert message saying โ€œHello World!โ€ appear! To run js in a bookmark, you need to have the `javascript:` prefix before it. You can only type one line so make sure to use your semicolons! In addition, you **can not use double quotes**. The search engine saves the bookmark in code that looks something like this: ```html <a href="javascript:alert(โ€˜Hello World!โ€™)">Hello World</a> ``` If you use double quotes it looks like: ```html <a href="javascript:alert(โ€œHello World!โ€)โ€>Hello World</a> ``` And causes an error. If you have multiple lines, create an anonymous function: `javascript:(function(){ var x=prompt(โ€˜Hi say something:โ€™); alert(โ€˜You said: โ€™ + x); })()` Notice there are NO double quotes. Let's go over some examples: Google Search: `javascript:(function(){window.open('https://www.google.com/search?q='+prompt('Google Search:', '').split(' ').join('+'), '', 'width=800,height=500,left=10,top=10,scrollbar=yes');})();` The above example opens up a new window with a search query of your input! Feel free to copy any of these or the ones listed below. Calculator: `javascript:(function(){var evl,expr=prompt('Formula...','');with(Math)try{evl=parseFloat(eval(expr));if(isNaN(evl)){throw Error('Not a number!');}prompt('Result of '+expr+':',evl)}catch(evl){alert(evl);}})();` @JSer โ€˜s Rolling Sky: (Thanks for creating such an awesome game!) `javascript:window.open('https://Rolling-Sky--jser.repl.co', '', 'top=15,left=15,scrollbar=yes,width=500,height=600')` **Thank you for reading! Please upvote and comment your own bookmarklets. Iโ€™ll add a community creations section! I hope i get a content creator tag for this ๐Ÿ˜€ **
24
posted by PYer (1848) 18 days ago
โ–ฒ
10
(Python) Quine-McCluskey Algorithm
# (Python) Quine-McCluskey Algorithm ## What is it? The Quine-McCluskey Algorithm is an algorithm developed by Willard Quine in the late 1950s which was then improved upon by Edward McCluskey. The purpose of this algorithm is to take the results of a logical expression or a boolean algebraic expression and simplify it to it's simplest form. ## Examples * `(p ^ q ^ r) v (p ^ q ^ ~r) v (p ^ ~q ^ ~r)` simplifies to `p ^ (q v ~r)` * `a or (a and b)` simplifies to `a` ## Requirements * Basic Knowledge of Python * Power Sets * Recursion ___ ## Quine-McCluskey Algorithm Now first, in order to best explain the Quine-McCluskey Algorithm, we are going to set up an example of a modified truth table that will show you the values that will be used for this example. ### Grouping Let's say we have a logical expression that evaluates per the function *f(a, b, c, d) =* ฮฃ *m(0, 4, 5, 7, 8, 11, 12, 15)* Now what this means is that whenever the binary equivalents of the variables make the decimal value equal to any of these values, the expression is evaluating to true: | a | b | c | d | bits | decimal | |:-:|:-:|:-:|:-:|:----:|:-------:| | 0 | 0 | 0 | 0 | `0000` | 0 | | 0 | 1 | 0 | 0 | `0100` | 4 | | 0 | 1 | 0 | 1 | `0101` | 5 | | 0 | 1 | 1 | 1 | `0111` | 7 | | 1 | 0 | 0 | 0 | `1000` | 8 | | 1 | 0 | 1 | 1 | `1011` | 11 | | 1 | 1 | 0 | 0 | `1100` | 12 | | 1 | 1 | 1 | 1 | `1111` | 15 | Now we group the bits by however many 1's there are in the binary value. Don't worry about the `used` column just yet. I will explain that a few steps down: | # of 1's | decimal | a | b | c | d | used | |:--------:|:-------:|:-:|:-:|:-:|:-:|:----:| | 0 | 0 | 0 | 0 | 0 | 0 | yes | | 1 | 4 | 0 | 1 | 0 | 0 | yes | | | 8 | 1 | 0 | 0 | 0 | yes | | 2 | 5 | 0 | 1 | 0 | 1 | yes | | | 12 | 1 | 1 | 0 | 0 | yes | | 3 | 7 | 0 | 1 | 1 | 1 | yes | | | 11 | 1 | 0 | 1 | 1 | yes | | 4 | 15 | 1 | 1 | 1 | 1 | yes | Now, each of these values becomes a minterm. What a minterm is is just something that holds information about where a decimal value, or values, evaluates to true and what binary value it holds. When we combine them, we only want to look for where there is a 1-bit difference in 2 minterms. The reason we do that is because we want to remove the bits that don't matter. For example, let's say we compare minterms 0 and 4. We see that there is only a 1-bit difference between them at the `b` variable. To put this into logical expression terms, this is really what we're doing: | Expression | Action | |:----------:|:------:| | `(~a ^ ~b ^ ~c ^ ~d) v (~a ^ b ^ ~c ^ ~d)` | Given | | `(~a ^ ~c ^ ~d) ^ (~b v b)` | Distributive Law | | `(~a ^ ~c ^ ~d) ^ t` | Identity Law | | `(~a ^ ~c ^ ~d)` | Tautology | Now, as you can see above, we were able to take out a common factor of `(~a ^ ~c ^ ~d)` and leave behind `(~b v b)`. In logic, `(~b v b)` will always be true no matter the value of `b`. This is the reason we want to compare minterms that have only a 1-bit difference. ### Comparing After we compare each term in adjacent groups with one another, we get another table that looks like the following table. There is an extra column to keep track of whether or not we used the minterm specified when we try combining the minterms. Since we used all of the minterms in the earlier table, we know that we don't have to remember to use any of them. If we don't use a minterm, then that minterm must be one of the prime implicants, which is what is used to generate the simplified logical expression: | groups | minterm | a | b | c | d | used | |:------:|:-------:|:-:|:-:|:-:|:-:|:----:| | 0-1 | m(0, 4) | 0 | - | 0 | 0 | yes | | | m(0, 8) | - | 0 | 0 | 0 | yes | | 1-2 | m(4, 5) | 0 | 1 | 0 | - | no | | | m(4, 12) | - | 1 | 0 | 0 | yes | | | m(8, 12) | 1 | - | 0 | 0 | yes | | 2-3 | m(5, 7) | 0 | 1 | - | 1 | no | | 3-4 | m(7, 15) | - | 1 | 1 | 1 | no | | | m(11, 15) | 1 | - | 1 | 1 | no | Now that we've compared every term in adjacent groups with one another, we can move onto doing the same step again which will get us with 2 values. ### Comparing (continued) | groups | minterm | a | b | c | d | used | |:------:|:-------:|:-:|:-:|:-:|:-:|:----:| | 0-1-1-2 | m(0, 4, 8, 12) | - | - | 0 | 0 | no | | | m(0, 8, 4, 12) | - | - | 0 | 0 | no | Now as you can see, these 2 minterms are actually the same exact minterm. Just because the order of the numbers is different doesn't make them any different in reality. Therefore, the order of the values in the minterms doesn't actually matter when combining them. However, we must make sure that minterms `m(0, 4)`, `m(0, 8)`, `m(4, 12)`, and `m(8, 12)` are used which helps us simplify the expression. ### Prime Implicant Table From the minterms that aren't used, we create a table with the variables on the left and the values from the function at the beginning on the right. When we go through the unused minterms, we put `X`'s in the columns that the minterm holds values for. For example `m(0, 4, 8, 12)` should have `X`'s in columns 0, 4, 8, and 12. That part is pretty self-explanatory. | a | b | c | d | 0 | 4 | 5 | 7 | 8 | 11 | 12 | 15 | |:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:--:|:--:|:--:| | | | ~c| ~d| X | X | | | X | | X | | | ~a| b | ~c| | | X | X | | | | | | | ~a| b | | d | | | X | X | | | | | | | b | c | d | | | | X | | | | X | | a | | c | d | | | | | | X | | X | Once we have this table setup, we want to look for what is known as the essential prime implicants which are prime implicants that need to exist in order for the expression to evaluate to true at the values specified earlier. To find these essential prime implicants, we look for the numbers who have only 1 `X` in the entire column. In our case, those columns are 0, 8, 11, and 12. Once we find those essential prime implicants, we go to the row that contains that `X` and add it to our final expression. When we cover an expression from a row, we then ignore all the `X`'s that exist in the rest of the column. For example, since we see that 0, 8, and 12 are essential values, we add `(~c ^ ~d)` to the final expression and cross out all the columns that minterm covers. The reason we have `(~c ^ ~d)` as the expression for this minterm is because the binary equivalent is `--00`. Wherever there is a hyphen (`-`), we do not put the variable that corresponds to it. Whenever there is a `0`, we put a NOT (`~`) operator in front of the variable that corresponds to it. Whenever there is a `1`, we just put the variable itself. Expression: `(~c ^ ~d)` | a | b | c | d | 0 | 4 | 5 | 7 | 8 | 11 | 12 | 15 | |:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:--:|:--:|:--:| | | | ~c| ~d| ~~X~~ | ~~X~~ | | | ~~X~~ | | ~~X~~ | | | ~a| b | ~c| | | ~~X~~ | X | | | | | | | ~a| b | | d | | | X | X | | | | | | | b | c | d | | | | X | | | | X | | a | | c | d | | | | | | X | | X | Now we have another essential value at column 11 so we need to add `(a ^ c ^ d)` to the final expression. Expression: `(~c ^ ~d) v (a ^ c ^ d)` | a | b | c | d | 0 | 4 | 5 | 7 | 8 | 11 | 12 | 15 | |:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:--:|:--:|:--:| | | | ~~~c~~| ~~~d~~| ~~X~~ | ~~X~~ | | | ~~X~~ | | ~~X~~ | | | ~a| b | ~c| | | ~~X~~ | X | | | | | | | ~a| b | | d | | | X | X | | | | | | | b | c | d | | | | X | | | | ~~X~~ | | ~~a~~ | | ~~c~~ | ~~d~~ | | | | | | ~~X~~ | | ~~X~~ | Since we do not have any more essential prime implicants, we want to find which implicant(s) will create the simplest expression and covers the most values. In this case, we can see that `m(5, 7)` will cover the other 2 remaining columns: Expression: `(~c ^ ~d) v (a ^ c ^ d) v (~a ^ b ^ d)` | a | b | c | d | 0 | 4 | 5 | 7 | 8 | 11 | 12 | 15 | |:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:--:|:--:|:--:| | | | ~~~c~~| ~~~d~~| ~~X~~ | ~~X~~ | | | ~~X~~ | | ~~X~~ | | | ~a| b | ~c| | | ~~X~~ | ~~X~~ | | | | | | | ~~~a~~| ~~b~~ | | ~~d~~ | | | ~~X~~ | ~~X~~ | | | | | | | b | c | d | | | | ~~X~~ | | | | ~~X~~ | | ~~a~~ | | ~~c~~ | ~~d~~ | | | | | | ~~X~~ | | ~~X~~ | ### Final Expression Now, since we have covered every value in the prime implicant chart, the final expression is `(~c ^ ~d) v (a ^ c ^ d) v (~a ^ b ^ d)`. To put that into perspective, the original expression was `(~a ^ ~b ^ ~c ^ ~d) v (~a ^ b ^ ~c ^ ~d) v (~a ^ b ^ ~c ^ d) v (~a ^ b ^ c ^ d) v (a ^ ~b ^ ~c ^ ~d) v (a ^ ~b ^ c ^ d) v (a ^ b ^ ~c ^ ~d) v (a ^ b ^ c ^ d)`. Now let's move onto the code that actually does all of this. ___ ## Quine-McCluskey Algorithm in Code For this algorithm, I've created only 2 classes that do all of the hard work: * The `Minterm` class, which holds the values and the binary value of the minterm * The `QuineMcCluskey` class which actually solves for the simplified form of an expression ### `Minterm` class The `Minterm` class is actually quite simple and doesn't hold much at all. First we have the basic built-in methods: ```py class Minterm: def __init__(self, values, value): self._values = values self._value = value self._used = False self._values.sort() def __str__(self): values = ", ".join([str(value) for value in self._values]) return f"m({values}) = {self._value}" def __eq__(self, minterm): if type(minterm) != Minterm: return False return ( self._value == minterm._value and self._values == minterm._values ) ``` The `__str__` method is there to print out a specific minterm nicely in the form of `m(0, 4, 8, 12) = --00` Next, we have some basic getters and setters that are used in the `QuineMcCluskey` portion of the code: ```py def get_values(self): """Returns all the implicants that this minterm covers. """ return self._values def get_value(self): """Returns the bit values ('-010', '1010', etc.) for this minterm. """ return self._value def use(self): """Keeps track of when this minterm is "used" in a comparison. """ self._used = True def used(self): """Returns whether or not this minterm was used. """ return self._used ``` These are all both documented and pretty self-explanatory so I don't think I need to really go over them much. This next (and last) portion of code for the `Minterm` class is used when we combine minterms in the algorithm: ```py def combine(self, minterm): """Combines this minterm with the specified minterm if possible. """ # Check if this minterm is the same as the one trying to be combined with if self._value == minterm._value or self._values == minterm._values: return None # Keep track of the amount of difference between the value of the minterm # and also keep track of the resulting string diff = 0 result = "" # Iterate through all the bit values for char in range(len(self._value)): # Check if this minterm and the combined minterm have a bit difference if self._value[char] != minterm._value[char]: diff += 1 result += "-" # There is no difference else: result += self._value[char] # The difference is greater than 1, these minterms cannot be combined if diff > 1: return None return Minterm(self._values + minterm._values, result) ``` Now as you can see, this code will return a new `Minterm` object if 2 minterms can be combined with one another. For example, what this does is take a minterm, say `m(0, 4) = 0-00`, and another minterm, say `m(8, 12) = 1-00`, and it will combine them together which then becomes `m(0, 4, 8, 12) = --00`. That is really all that needs to be done for the `Minterm` class. Now let's move on to the `QuineMcCluskey` class which has all the meat of the code. ## `QuineMcCluskey` class The `QuineMcCluskey` class has the majority of the functions that create an initial group, combine minterms from adjacent groups, solves the function, and then generates the function into a human-readable format. First, we need the basic constructor and a function that gets the binary equivalent of a decimal value: ```py class QM: """A class to handle processing the Quine-McCluskey Algorithm. """ def __init__(self, variables, values): self._variables = variables self._values = values def __get_bits(self, value): """Returns the binary digit for the specified value. """ # Pad the result with extra 0's at the beginning to match how many variables # there are being used return bin(value)[2:].rjust(len(self._variables), "0") ``` The reason we need the `__get_bits` function is to be able to get the binary equivalent of the values where the function evaluates to true. For example, 4 is `0100`, 5 is `0101`, and 7 is `0111` in our example. It's important to pad extra 0's to the beginning of the value to match that of the number of variables in the expression. #### The Initial Group Before beginning the process of getting a list of unused prime implicants, we need to create an initial group where each binary value is matched up with how many 1's the binary value has. ```py def __initial_group(self): """Creates the initial grouping for the bits from the values given to the Quine-McCluskey Algorithm """ # Keep track of groups by 2-dimensional list groups = [] for count in range(len(self._variables) + 1): groups.append([]) # Iterate through values for value in self._values: # Count number of 1's in value's bit equivalent count = self.__get_bits(value).count("1") # Add count to proper group groups[count].append(Minterm([value], self.__get_bits(value))) return groups ``` In essence, what this function does is create the groups of minterms based off of how many 1's there are in the binary values for the decimal values. In the case of our function from earlier, the list would look something like this: ```py groups = [ ['m(0) = 0000'], # 0 1's ['m(4) = 0100', 'm(8) = 1000'], # 1 1's ['m(5) = 0101', 'm(12) = 1100'], # 2 1's ['m(7) = 0111', 'm(11) = 1011'], # 3 1's ['m(15) = 1111'] # 4 1's ] ``` #### Prime Implicants The next step is to get all the prime implicants that could possibly cover the expression. Like [mentioned earlier](#comparing) in the explanation of the Quine-McCluskey Algorithm, to get the prime implicants, we must compare every term in one group with every term in an adjacent group. That is what the following code does: ```py def __get_prime_implicants(self, groups = None): """Recursively gets the prime implicants for the expression. """ # Get initial group if group is None if groups == None: groups = self.__initial_group() # If there is only 1 group, return all the minterms in it if len(groups) == 1: return groups[0] # Try comparing the rest else: unused = [] comparisons = range(len(groups) - 1) new_groups = [[] for c in comparisons] for compare in comparisons: group1 = groups[compare] group2 = groups[compare + 1] # Compare every term in group1 with every term in group2 for term1 in group1: for term2 in group2: # Try combining it term3 = term1.combine(term2) # Only add it to the new group if term3 is not None # term3 will only be None if term1 and term2 could not # be combined if term3 != None: term1.use() term2.use() if term3 not in new_groups[compare]: new_groups[compare].append(term3) # Get list of all unused minterms for group in groups: for term in group: if not term.used() and term not in unused: unused.append(term) # Add recursive call for term in self.__get_prime_implicants(new_groups): if not term.used() and term not in unused: unused.append(term) return unused ``` The first `if` statement is pretty simple to comprehend. All it's checking for is whether or not a parameter is given, which is used in the recursive call, and setting it to be the initial group if it is not given. The next `if` statement is the base case of this recursive function. If there is only one group left, then only the prime implicants in that function will cover the expression given. The `else` statement handles everything else about getting prime implicants. First, we set up which minterms are unused in the comparisons. Then we want to only compare groups that are adjacent to one another. So if there are 5 groups, we only want to compare group 0 and 1, 1 and 2, 2 and 3, and 3 and 4. That's only 4 comparisons. Finally, we want to keep track of these new groups once we compare minterms. When we loop through the comparisons, we only go from the first group to the second to last group or else we would have an `IndexError` when the `group2 = groups[compare + 1]` line of code came up. Once we loop through each minterm in each group, we try to combine the 2 minterms. If the 2 minterms cannot be combined, nothing will happen. However, if the 2 minterms *can* be combined, we want to keep track of using the minterm. Then, we make sure that the resulting minterm does not already exist in the new group that it belongs to. Once we finish with comparing minterms, we want to keep track of which minterms were not used, if there were any. Then we make the recursive call which uses the new list of groups to compare every minterm again. Each time the `__get_prime_implicants` function is run, it returns a list of unused minterms. At the end of the recursive call, we get a total list of all the minterms which become the prime implicants. #### Power Set A power set, for those who don't understand what it is, is just a set of combinations of an existing set. For example, let's take a set to be `{1, 2, 3}`. The power set would be, `{{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}}`. The reason we need to understand what a power set is is because after the essential prime implicants are found (which will be explained right after this section), the power set function will determine which remaining implicants cover the remainder of the expression and which set has the fewest implicants. ```py def __power_set(self, values, prime_implicants): """Creates a power set of all valid prime implicants that covers the rest of an expression. This is used after the essential prime implicants have been found. """ # Get the power set of all the prime_implicants prime_implicants = list(prime_implicants) power_set = [] # Iterate through decimal values from 1 to 2 ** size - 1 for i in range(1, 2 ** len(prime_implicants)): current_set = [] # Get the binary value of the decimal value bin_value = bin(i)[2:].rjust(len(prime_implicants), "0") # Find which indexes have 1 in the bin_value string for index in range(len(bin_value)): if bin_value[index] == "1": current_set.append(prime_implicants[index]) power_set.append(current_set) # Remove all subsets that do not cover the rest of the implicants new_power_set = [] for subset in power_set: # Get all the values the set covers temp_values = [] for implicant in subset: for value in implicant.get_values(): if value not in temp_values and value in values: temp_values.append(value) temp_values.sort() # Check if this subset covers the rest of the values if temp_values == values: if len(subset) < len(minSet): minSet = subset return minSet ``` There are a few things that go on in this function. First, the initial power set is created from the prime implicants given through the parameter. After that is done, we then iterate over each set to determine if the set contains minterms that cover the rest of the expression. When the smallest subset is found, a variable, `minSet`, is updated to keep track of the smallest set so that at the end, the smallest set is returned which includes the final prime implicant, or implicants, that cover the rest of the expression. #### Solving Now let's get on to actually *solving* the expression. ```py def __solve(self): """Solves for the expression returning the minimal amount of prime implicants needed to cover the expression. """ # Get the prime implicants prime_implicants = self.__get_prime_implicants(self.__initial_group()) # Keep track of values with only 1 implicant # These are the essential prime implicants essential_prime_implicants = [] values_used = [False] * len(self._values) for i in range(len(self._values)): value = self._values[i] uses = 0 last = None for minterm in prime_implicants: if value in minterm.get_values(): uses += 1 last = minterm if uses == 1 and last not in essential_prime_implicants: for v in last.get_values(): values_used[self._values.index(v)] = True essential_prime_implicants.append(last) # Check if all values were used if values_used.count(False) == 0: return essential_prime_implicants # Keep track of prime implicants that cover as many values as possible # with as few variables as possible prime_implicants = [prime_implicant for prime_implicant in prime_implicants if prime_implicant not in essential_prime_implicants] # Check if there is only one implicant left (very rare but just in case) if len(prime_implicants) == 1: return essential_prime_implicants + prime_implicants # Create a power set from the remaining prime implicants and check which # combination of prime implicants gets the simplest form return essential_prime_implicants + self.__power_set([ self._values[index] for index in range(len(self._values)) if not values_used[index] ], prime_implicants) ``` The basic function of the `solve` function is to: 1. Get a list of prime implicants ```py # Get the prime implicants prime_implicants = self.__get_prime_implicants(self.__initial_group()) ``` 2. Find the essential prime implicants ```py # Keep track of values with only 1 implicant # These are the essential prime implicants essential_prime_implicants = [] values_used = [False] * len(self._values) for i in range(len(self._values)): value = self._values[i] uses = 0 last = None for minterm in prime_implicants: if value in minterm.get_values(): uses += 1 last = minterm if uses == 1 and last not in essential_prime_implicants: for v in last.get_values(): values_used[self._values.index(v)] = True essential_prime_implicants.append(last) # Check if all values were used if values_used.count(False) == 0: return essential_prime_implicants ``` The final `if` statement in this block of code will determine if all the essential prime implicants are the only prime implicants needed to cover the expression. 3. Use the `__power_set` function to find the final prime implicant(s) that cover the expression and return it along with the essential prime implicants ```py # Keep track of prime implicants that cover as many values as possible prime_implicants = [prime_implicant for prime_implicant in prime_implicants if prime_implicant not in essential_prime_implicants] # Check if there is only one implicant left (very rare, if not impossible, but just in case) if len(prime_implicants) == 1: return essential_prime_implicants + prime_implicants # Create a power set from the remaining prime implicants and check which # combination of prime implicants gets the simplest form return essential_prime_implicants + self.__power_set([ self._values[index] for index in range(len(self._values)) if not values_used[index] ], prime_implicants) ``` The purpose of reassigning the `prime_implicants` list is to remove all the prime implicants that are in that list that are *also* an essential prime implicant. #### Getting the Expression The final part of this algorithm is to actually return an expression that is readable to the human eye. ```py # Get the prime implicants and variables prime_implicants = self.__solve() # Check if there are no prime_implicants; Always False if len(prime_implicants) == 0: return "0" if len(prime_implicants) == 1: if prime_implicants[0].get_value().count("-") == len(self._variables): return "1" result = "" # Iterate through prime implicants for j in range(len(prime_implicants)): implicant = prime_implicants[j] # Iterate through all bits in the implicants value for i in range(len(implicant.get_value())): if implicant.get_value()[i] == "0": result += "NOT " if implicant.get_value()[i] != "-": result += self._variables[i] if implicant.get_value().count("-", i + 1) < len(implicant.get_value()) - i - 1 and implicant.get_value()[i] != "-": result += " AND " if j < len(prime_implicants) - 1: result += " OR " return result ``` The basis of the `get_function` function is to find the prime implicants from the `__solve` function, iterate through the prime implicants and their binary values, and then create proper variables (with/without a NOT operator). If there are no prime implicants received after the `__solve` function is called, then the expression is always false. Therefore, a `0` is returned. If there is only 1 prime implicant that has a binary value of all hyphens (`-`), then the expression will always be true no matter what. #### Conclusion To conclude this tutorial, I went over the basics of the Quine-McCluskey Algorithm, how to do it by hand, and how to adapt it to code. If you want to see the simplifier in action, you can go to https://repl.it/@FellowHashbrown/Quine-McCluskey-Python. I also wrote it in [Java](https://repl.it/@FellowHashbrown/Quine-McCluskey-Java) and [Node.js](https://repl.it/@FellowHashbrown/Quine-McCluskey-Nodejs) If you have any suggestions or see any issues, please let me know that way I can fix it! If you find any bugs in adaptation of the Quine-McCluskey Algorithm, *definitely* let me know either by leaving a comment, pinging me in Repl.it's Discord Server, or pinging me in my own [Discord Server](https://discord.gg/W8yVrHt)
2
posted by FellowHashbrown (37) 13 days ago
โ–ฒ
17
LLC - Java
# Language learning club - Java ### Introduction Thanks to the [repl.it](https://repl.it) team (especially @amasad and @katyadee), we now have a language learning club about which you can learn more [here](<https://repl.it/talk/announcements/UPDATE-AS-OF-41519-Language-Learning-Club/12870>). We recently had a voice session for [GoLang](https://repl.it/languages/go) and it was pretty dull and I didn't want that to happen again. So I decided to contribute to the people learning Java myself. There is going to be a session over voice chat on the repl.it discord server at 06:00 PM CST on Mondays. You can join the discord server by [clicking here](https://repl.it/discord). ------ ### For Beginners Now that all the info has been shared, here are some resources you can use to get started with Java: - For book lovers: - - [Java: A Beginner's Guide](https://books.google.co.in/books/about/Java_A_Beginner_s_Guide_Sixth_Edition_IN.html?id=MaUiAwAAQBAJ&source=kp_book_description&redir_esc=y) - [Effective Java](https://books.google.co.in/books/about/Effective_Java.html?id=BIpDDwAAQBAJ&source=kp_book_description&redir_esc=y) For YouTube video lovers: - - [Java tutorial for beginners video series](https://www.youtube.com/watch?v=r59xYe3Vyks&list=PLS1QulWo1RIbfTjQvTdj8Y6yyq4R7g-Al) - [Another Java tutorial for beginners (9 hour video)](https://www.youtube.com/watch?v=grEKMHGYyns) ------ ### GUI Development with Java For people who have learned the basics of Java, here are a few YouTube videos that you can watch to learn GUI development with Java. For people who like to read: - - [Java Swing Tutorial](https://www.javatpoint.com/java-swing) - [Swing Tutorialspoint](https://www.tutorialspoint.com/swing) For people who like videos: - - [Complete Java Swing tutorial](https://www.youtube.com/watch?v=WRwPVZ4jmNY) - [Java Swing tutorial video series](https://www.youtube.com/watch?v=jUEOWVjnIR8&list=RDQMm8C0LW_jS50&start_radio=1) ------ ### Android App development For people who even know about Swing. Java is the most used language for mobile apps development in [Android Studio](https://developer.android.com/studio). [Click here to learn about Android App development](https://developer.android.com/studio/intro). Here you'll find that there is a new alternative to Java - `Kotlin`. And it also seems like a sweet choice. You can compare the differences between Java and Kotlin [here](https://hackr.io/blog/kotlin-vs-java). ------ ### Some code examples ***Note:*** *In all the examples the file was named as `Main.java` which is the default in [repl.it](https://repl.it). Also, the following examples use the simplest ways possible, these programs could've been made much smaller (except for the first one).* **Hello World** ```java /* This program is basically the boilerplate for the language*/ class Main { public static void main(String[] args) { System.out.println("Hello world!"); } } ``` ------ **Hello <name>** ```java // Importing the scanner class for taking input import java.util.Scanner; class Main { public static void main(String[] args) { // Declaring the variables String name; Scanner in = new Scanner(System.in); // Getting the name System.out.println("What's your name?"); name = in.nextLine(); // Printing the name System.out.println("\nHello, " + name); } } ``` ------ **Factorial** ```java // Importing the Scanner class for taking input import java.util.Scanner; class Main { public static void main(String[] args) { // Declaring the variables int n, factorial = 1; Scanner in = new Scanner(System.in); // Getting a number from the user. System.out.print("Please enter a number: "); n = in.nextInt(); // Calculating the factorial using a simple for loop for(int i = 1; i <= n; i++) { factorial = factorial * i; } // Showing the calculated factorial System.out.println("\nThe factorial of " + n + " is " + factorial); } } ``` ------ That's all for now. Visit the above links and learn more for yourself! :P
4
posted by TheDrone7 (398) 25 days ago
โ–ฒ
56
๐Ÿš€ A Starter Guide to Pygame ๐Ÿ“€
# ๐Ÿš€ A Starter Guide to Pygame ๐Ÿ“€ Pygame is an open-source library for making graphical applications with Python. Learn more about it on the official [website](https://pygame.org). This tutorial is intended to help you setup a very basic Pygame interface. It's for Python beginners or people who want to quickly bootstrap a Pygame project. Find more about Repl.it's GFX public beta announcement [here](https://repl.it/talk/announcements/Replit-GFX-Public-Beta-Build-Games-and-GUI-Apps/11545). So let's get started! We're going to be building a simple screen saver. The final result will look like the following ![programProgress4](https://i.imgur.com/dEileMP.gif) ## Starting out When creating a new project, be sure to select "PyGame" when creating a project. ![image](https://storage.googleapis.com/replit/images/1552705106070_4aa0e807cd3fb5197a7251222d74d724.pn) Now we're ready to start writing some code! ## Painting the Screen Red ๐ŸŽจ First, we're importing Pygame and initializing all the imported pygame modules with [`pygame.init()`](https://www.pygame.org/docs/ref/pygame.html#pygame.init). Second, we're declaring `width` and `height` variables that represent the size of the screen. Third, we're setting `backgroundColor` to a tuple of 3 elements that represent the RGB numbers. Fourth, `screen` is a display Surface, or an initialized window or screen for display with the [`set_mode()`](https://www.pygame.org/docs/ref/display.html#pygame.display.set_mode) method. Lastly, in the infinite loop, we're filling the screen to the `backGroundColor` and updatiang the display Surface to the screen. In other words [`pygame.display.flip()`](https://www.pygame.org/docs/ref/display.html#pygame.display.flip) "refreshes" the screen with changes you made to the grahpics. ```python import pygame pygame.init() width, height = 800, 600 backgroundColor = 255, 0, 0 screen = pygame.display.set_mode((width, height)) while True: screen.fill(backgroundColor) pygame.display.flip() ``` So, we get a red background! ![programProgress1](https://storage.googleapis.com/replit/images/1552448696584_73e029d5335f2d2a06c92a180e7103be.pn) ## Adding the DVD Right before you while loop, import an image of your DVD. Feel free to use the same image I used, in the repl below. ```python dvdLogo = pygame.image.load("dvd-logo-white.png") ``` Then, create a rectangle from the Surface, or from the image you just loaded with [`get_rect()`](https://www.pygame.org/docs/ref/surface.html?highlight=get_rect#pygame.Surface.get_rect) ```python dvdLogoRect = dvdLogo.get_rect() ``` Now, inside of the `while` loop (after filling the background color), "map" the imported image to the `dvdLogoRect` rectangle using the [`blit()`](https://www.pygame.org/docs/ref/surface.html?highlight=blit#pygame.Surface.blit) method. That way, the image stays inside of the invisible `dvdLogoRect` rectangle. ```python screen.blit(dvdLogo, dvdLogoRect) ``` Now, we get a DVD! ![programProgress2](https://storage.googleapis.com/replit/images/1552449702561_27872d2c7a30d4d9dbb53d3c908851d9.pn) ## Moving the DVD Logo To move the DVD logo, simply use `move()` by a speed: ```python dvdLogoRect = dvdLogoRect.move(dvdLogoSpeed) ``` Make sure you also declare and initialie dvdLogoSpeed at the top of the file. `dvdLogoSpeed[0]` represents the speed in the `x` direction. ```python dvdLogoSpeed = [1, 1] ``` Finally, I added a `time.sleep(10 / 1000)` so the logo moves slower. So my code ended up looking like ![programProgress3](https://i.imgur.com/dsh8TYo.gif) The DVD logo *will* move off the screen because there is no bouncing. To implement a check for bouncing, add the following: ```python if dvdLogoRect.left < 0 or dvdLogoRect.right > width: dvdLogoSpeed[0] = -dvdLogoSpeed[0] if dvdLogoRect.top < 0 or dvdLogoRect.bottom > height: dvdLogoSpeed[1] = -dvdLogoSpeed[1] ``` The `.left` and `.right` properties don't seem to be [documented](https://www.pygame.org/docs/ref/rect.html?highlight=rect%20left), but it's implied that `.left` measures the distance from the left part of the `dvdLogoRect` Rect (rectangle) to the left part of the `screen.` And so on and so fourth for `.right`, `.top`, and `.bottom`. Here is the final result ![programProgress4](https://i.imgur.com/dEileMP.gif) Now let me know when the logo hits the corner!
27
posted by eankeen (455) 2 months ago
โ–ฒ
32
How I solved the Secret Announcement
# A Detailed Solution to Secret Announcement ### Background: You are most likely busy creating a game for the game jam and you probably know that an announcement came 2 weeks before the jam as a secret message using [steganography](https://en.wikipedia.org/wiki/Steganography) I was one of those chaps who actually solved the secret, but didn't do anything. The challenge can be found [here](https://repl.it/@timmy_i_chen/secret-announcement?ref=newsletter). There was a solution, but that was not very explanatory.This post will explain how ~I~ solved the announcement. This post assumes basic knowledge of the binary system. *** The first thing I did after seeing the newsletter was to read up on steganography.I found this on wikipedia: >Concealing messages within the lowest bits of noisy images or sound files Interesting... ## Reverse Engineering: Then, I looked at the code.Apart from imports and loops to go through all pixels,this was the crux of the code: ```py secret_red = secret_pix[0] >> shift_amt secret_green = secret_pix[1] >> shift_amt secret_blue = secret_pix[2] >> shift_amt public_red = public_pix[0] & all_except_LSB_mask public_green = public_pix[1] & all_except_LSB_mask public_blue = public_pix[2] & all_except_LSB_mask final = ( secret_red + public_red, secret_green + public_green, secret_blue + public_blue ) ``` `>>` and `&` are [binary operators](https://en.wikipedia.org/wiki/Bitwise_operation).shift_amt was 7 and all_except_LSB_mask was 254 What does the >> operator do? It shifts the bits towards towards right.For example: `11100010101 >> 6` outputs `11100` i.e. the last 6 bits are removed. In our case, all the 8 bit data(because 255 is the maximum in RGB color format and 255 is 8 bits) is shifted by 7 bits so that would leave only the highest bit as one or zero. This would also imply that anything greater than 127.5 (255 / 2) would leave 1 while anything lesser would leave zero. `10101010 >> 7 == 1` `01010000 >> 7 == 0` So that's our secret pixel Then, we see the `&` operator with all_except_LSB_mask as 254.The & operator is called bitwise and. Basically, it returns one only if both expressions are one.Like `1&1 == 1` `1&0 == 0` `0&0 == 0` An important property of the & operator is that `something & all 1s = something` another one is that `something & 0 = 0` `10100100`&`11111111`==`10100100` 254 in binary is `11111110` So,all the bits except the last one would remain intact `10011011 & 11111110 ==10011010` So,this would turn all public pixels into even numbers as the last bit is 2**0=1 and if it is absent, the number must be even. The final pixel is secret_pix + public_pix.We know that public pix is either 0 or 1.Since the last bit of public pix is always zero,The last bit of final pixel must reflect the secret image. So here's my code: ```py from PIL import Image public=Image.open('out.png').convert('RGB') secret=Image.new('RGB',(600,600)) for x in range(600): for y in range(600): secret.putpixel((x,y),tuple((i%2)*255 for i in public.getpixel((x,y)))) secret.save('secret.png') ``` All the juicy stuff is in one line:`(i%2)*255 for i in public.getpixel((x,y)` What this does is: + take the public pixel + compute modulo two (returns 1 if odd and 0 if even) + multiply that by 255 because 00000001 or 00000000 show no visible difference but 11111111 and 00000000 do + put this in the secret image, pixel by pixel And Heres my output: ![secret](https://storage.googleapis.com/replit/images/1553919764220_1470a455120ad93feec70c9423124f04.pn) waow indeed
12
posted by Lord_Poseidon (105) 2 months ago
โ–ฒ
25
Learning Web Development w/ Python Part 1
# Learning Web Development with Python and Django ## Part 1 *If you already know a bit about web development, then check out [Gareth Dwyer's Tutorial](https://repl.it/talk/learn/Tutorial-Building-a-Django-web-application/6660). This tutorial is intended for beginners, and takes things a bit more slowly.* ## Welcome! In this tutorial, I'm going to be teaching you how you can use the `Django` web framework to make your own web apps with Python. ### Prerequisites For this tutorial, you should have a decent understanding of Python. Knowing some `HTML` and `CSS` helps. ## The Client and the Server Before we can start coding our own web app, we need to know a little of how the internet actually works - clients and servers. **Servers** Servers are basically the computers that 'run the websites'. Each website has its own server (in reality, large websites have lots of servers). Each server has its own **domain name**, e.g. www.google.com or www.repl.it. **Clients** Clients are computers that connect to servers - i.e. people who visit the website. ### How do Clients connect to Servers? This depends largely on what **protocol** is being used. The most common protocols are `http` (hyper-text transfer protocol) and `https` (secure hyper-text transfer protocol). On a very basic level, what happens is: * The client sends out a message saying "I want to see this page on this website, my address is xxxxx". * The message arrives at the server. * The server checks which page to send and then sends it back in the form of `html` (and often other filetypes, but we will be focusing on html here). * The browser of the client interprets the html to give a visual output. ### How does this apply to Django? When we use Django, we're basically writing our own server. Django takes care of all the sending and stuff, all we have to do is add our pages, and put them in a place Django can find them. ------------------------------------------------------------------------------------------ By now, you'll be itching to write some code, so lets get started! When you create a Django project on repl, there is already some code in there, so I have made a [basic template](https://repl.it/@ArchieMaclean/Basic-Template) which has the bare minimum. Open the template, and click the `fork` button at the top to make your own copy. ![image](https://storage.googleapis.com/replit/images/1554625804315_2a5ed0a55c14c016feacd6dc438d3b20.pn) You can now rename it to `hello-world` (or something else if you prefer). ## Creating your very first app Before we make any changes, you can click the square icon in the top right of the view panel: ![image](https://storage.googleapis.com/replit/images/1554625969590_1b80aeda3f1db062a5e7916c97db3ae3.pn) This will open the page in a new tab so you can see the fullscreen version of it. You should get a page like this: ![image](https://storage.googleapis.com/replit/images/1554626030130_fdf8263732fa1645061a5e309c29154f.pn) This is just the standard Django page, which appears when you haven't written any code yet. ### Creating our first web page When you type in a URL (such as https://ww.repl.it/languages/python) on a browser, there are three parts: * **Protocol** - almost always `http` or `https`. * **Domain name** - looks like `www.repl.it/`. * **Page name** - looks like `languages/python`, and is after the domain name. With our project, we don't need to worry about the domain, because `repl` creates one for us to use (in the form `<repl-name>--<username>.repl.co`). However, we will need to think about our page names. #### URLs and Views There are 2 parts to displaying a page on Django - the URL, and the `view`. The `view` is what the client will see when they visit the page. ##### Writing our view For this first project, we will be using **function-based views**. This means that each view is a Python `function`. Navigate to the `views.py` file, and add the following code: ```python from django.http import HttpResponse def homePageView(request): html = "Hello, World!" return HttpResponse(html) ``` So, what does this code do? `Line 1` imports HttpResponse , which we will need in order to return the html in the correct format. On `Lines 3-5` we create our view. * `Line 3` - this is our function, called `homePageView`, because it will be the homepage of our website. It takes `request` as an argument - for more advanced projects, you will use `request` in your function, but we don't need to worry about it right now. `request` is a request **object**, that carries information about the request for the page. * `Line 4` - this is the html for the website. This is extremely simple hmtl - it doesn't have any tags, all it has is the text `"Hello, World!"`. * `Line 5` - this is where we return the html, in a form Django can understand (`HttpResponse`) If we run this code, we get...nothing! The reason for this is that Django doesn't know what to do with the view. ##### Adding the URL (Page name) We need to tell Django where the view should be displayed. Navigate to the `urls.py` file, and add the following: ```python from .views import homePageView ``` Then change `urlpatterns` to: ```python urlpatterns = [ url(r'^admin/', admin.site.urls), url('',homePageView,name="home"), ] ``` Before we analyse the code, go to your website (in the other tab), and refresh. You'll see we got we wanted! ![image](https://storage.googleapis.com/replit/images/1554627432054_c0f2284207576ce83123b494a7735ee8.pn) So how did this happen? Let's look at the code. ```python from .views import homePageView ``` This imports our `homePageView` function from the `view.py` file. The period `.` at the start tells Django to open it from the current directory (`main`). This is needed because the code will be run from somewhere else, so Django could get confused and try to import it from a different folder. In `urlpatterns` we added ```python url('',homePageView,name="home"), ``` (Note that `''` is 2 single-quotes, not 1 double quote) This tells Django to treat it as a url. There are 3 arguments given: * The first (`''`) is the page name, which I described earlier. If it was something like `about/aboutme` then the page would be located at https://domain.name/about/aboutme (replacing `domain.name` with the domain name, obviously). However, it is just `''` so the view will be located at just https://domain.name/. * The second is our view that we created in `views.py` and imported earlier. * The third is the *name* we give our page. It is not essential, but will come in useful later when we want to keep track of all the pages. ------------------------------------------------------------------------------------- ### Congratulations! You've made your first web page with Django! It may seem a bit convoluted right now, but this format is very helpful when we make bigger web applications and have many files. #### That concludes Part 1 In [Part 2](https://repl.it/talk/learn/Learning-Web-Development-with-Python-Part-2/12884), we will be looking at the more powerful `class-based views`, as well as multiple pages in out project. Please upvote if you found this tutorial helpful, it supports me and lets me know that you want more! If you have any questions, post in the comments and I (or someone else) will answer them.
2
posted by ArchieMaclean (432) 2 months ago
โ–ฒ
9
๐Ÿ”ต Blogging on Replit with Hexo
# ๐Ÿ”ต Blogging on Replit with Hexo ![hexo logo](https://storage.googleapis.com/replit/images/1556732510266_05cd68a7026409853570708f1fb896a4.pn) If you've ever wanted to create a blog, you might have heard of static site generators like [Jekyll](https://jekyllrb.com), [Hugo](https://gohugo.io), and [Hexo](https://hexo.io). In a nutshell, they transform any blog posts you've written in [markdown](https://guides.github.com/pdfs/markdown-cheatsheet-online.pdf) to a complete website. I'll show you how to get started with Hexo on replit. It's super simple. If you just want to fork a working example, see the repl below and follow the "*After forking*" steps. But if you want to follow along and create it yourself, follow the "*preliminary steps*" ๐Ÿ˜‰. *You may have to fork the project if replit doesn't update files properly*. ### Prerequisites - Beginner experience with `npm` / `nodeJS` - Beginner experience with [markdown](https://guides.github.com/pdfs/markdown-cheatsheet-online.pdf) syntax ## Preliminary Steps ### Installing Hexo First, create a NodeJS repl and install the `hexo` package. ![image](https://storage.googleapis.com/replit/images/1556645287196_0ac926adaf2bae5becfecba3550c71e2.pn) After adding Hexo, make sure you click `run` so the `npm` dependencies download. ## Initializing a Hexo Project Open the terminal with Ctrl + Shft + P (or F1) (make sure the file editor window is selected while doing this). Then, make sure you have the Hexo package by typing ```bash ./node_modules/.bin/hexo ``` You should see something like this ๐Ÿ‘‡ ![image](https://storage.googleapis.com/replit/images/1556700126856_0a605a84489fa04e4cab5373daa75920.pn) On replit, we cannot install global `npm` dependencies. Because of this, we have to type `./node_modules/.bin/hexo` instead of `hexo` whenever we want to do some Hexo command. Once you know you have Hexo properly installed, initialize a Hexo project. I called it `public`, but it really doesn't matter what you call it. ```bash ./node_modules/.bin/hexo init public ``` Now, wait until the generated folders show up in the file tree. If the files never generate, you may want to consider forking my repl (which is down below), which has all the necessary files. ![image](https://storage.googleapis.com/replit/images/1556697810866_b03db9c8cfa185ed1c6fca707255bfb4.pn) Now, move all of the folders inside of `public` to the parent directory. Lastly, delete the `public` folder. ### Editing the Hexo Configuration Before, you start, you gotta change a few things in the configuration file. ![image](https://storage.googleapis.com/replit/images/1556721243012_3142b70dbb9f030036a56dc5a897adac.pn) In your `_config.yml` edit the`url` and parameter. Be sure to change the `url` to the url that shows up in the website preview area (denoted by red arrow). ### Starting the Hexo Server Starting the Hexo server enables you to preview your website as you're editing it. To start it, just type the following in the shell ```bash ./node_modules/.bin/hexo server ``` It should look something like this ๐Ÿ‘‡ ![image](https://storage.googleapis.com/replit/images/1556698479604_369ccb7534ac41eed5500c8cdc7b7e28.pn) But you may notice one large problem with this method. If someone visits you're repl, they'll have to type `./node_modules/.bin/hexo server` just to see your blog. We can fix this by making our `index.js` file automatically invoke the command`./node_modules/.bin/hexo server` in the shell. That way, when the user clicks "start", they'll see your blog ๐Ÿ˜„ To do this, put the following in your `index.js` ```js // Starts Hexo Development Server let spawn = require('child_process').spawn; let run = (cmd, args) => { child = spawn(cmd, args); child.stdout.on('data', data => process.stdout.write(data.toString())); child.on('close', code => console.log(`Child process exited with code ${code}.`)); }; run('./node_modules/.bin/hexo', ['server']); ``` Basically, this code creates a function called `run` with the arguments `cmd` and `args`. In this `run` function, a child process is spawned. Think of this child process as some process that's running a command (ex. `./node_modules/.bin/hexo server`). Whenever the process has received some `data` it logs it to the console. When the process `close`s, it logs that event to the console also. Now, after clicking on "run", your development server will start ๐Ÿ˜„. Be sure to refresh the site every time you want to make changes! Now read "*Using Hexo*" for more information. ## After Forking After you've forked my repl, you've basically almost done. Now, just change the `url` parameter in the `_config.yml` file so it matches yours. ![noimage](https://storage.googleapis.com/replit/images/1556721243012_3142b70dbb9f030036a56dc5a897adac.pn) Now you can start writing a blog! Hit "run" to start your blog and refresh the page every time you want your changes to show! Now read [Using Hexo](## Using Hexo) for more information. ## Using Hexo There are a few commands you'll want to know when editing or updating your blog. ### Starting the development server ```bash ./node_modules/.bin/hexo server ``` This starts the development server. If you followed this tutorial, you shouldn't have to type it in via the command line interface. Also, whenever you refresh the page, the website will automatically update. This is because replit automatically saves your files after you finish typing. ### Creating a new page ``` ./node_modules/.bin/hexo new <layout> <title> ``` For example, you can create a new post with the following ```bash ./node_modules/.bin/hexo new post "My Hexo Post" ``` However, sometimes, the posts you create within the shell won't pop up in the replit file viewer. As a workaround (for example), I 1. Create a post using the shell with `./node_modules/.bin/hexo new post "Sample Post"`. Then, I output the contents of the file with `cat ~/source/_posts/Sample-Post.md` 2. Create the actual markdown file inside of `source/_posts/` 3. Copy the output of what you got in step 1, and paste it in the text editor You can see the steps laid out below ๐Ÿ‘‡ ![image](https://storage.googleapis.com/replit/images/1556757274199_6681ff8df87b7eea71a21a0dcaae83ad.pn) If you want to learn more, check out the official Hexo [docs](https://hexo.io/docs). ### See the repl here ๐Ÿ‘‡ https://repl.it/@eankeen/hexo-blog I hope this tutorial helped you out ๐Ÿ™‚
7
posted by eankeen (455) 20 days ago
โ–ฒ
22
๐Ÿ‘พ๐ŸŽ‰ Announcing Python Play (beta) & a pong game tutorial
# [Python Play](https://github.com/replit/play) is the easiest way to get started coding games and graphics projects. @amasad and the repl.it team asked me to help them make an easy way for new programmers to start making games and graphics projects. As a result, we made [Python Play](https://github.com/replit/play), a code library for Python loosely based on [Scratch](https://scratch.mit.edu). For more information about Python Play, you can [read the documentation here](https://github.com/replit/play). This is a tutorial showing how to use Python Play to make a game. To follow along with the tutorial, you can go to **[this repl](https://repl.it/@glench/Blank-Python-Play-template)** and add code line-by-line. The game we'll be making is a pong game: ![screenshot](https://storage.googleapis.com/replit/images/1553634467413_16e2bdb28bc2c079db661594c57296e8.gi) ## How to make a pong game with Python Play To make this game, first we need a box. Copying and pasting the code below will put a box on the screen: ```python import play # this should always be the first line in your program box = play.new_box(color='black', x=0, y=0, width=30, height=120) play.start_program() # this should always be the last line in your program ``` After you've copied that code, click the "Run" button. You should see a tall black box in the middle of the screen. If you change any of the stuff after `new_box`, it will change what the box looks like and where it shows up on the screen. Change `x=0` to `x=100` and the box moves over to the right: ```python box = play.new_box(color='black', x=350, y=0, width=30, height=120) ``` (Click the Run button after every code change you make. Also make sure you still have the `import play` and `play.start_program()` lines of code in your program.) Changing `x` changes the horizontal position and changing `y` changes the vertical position of the box. You can try playing with these numbers to see how they work. Don't forget you can do negative numbers i.e. `x=-100` (note the minus symbol in front). Okay cool, a box is on the screen and we can change where it is. But how do we get it to do stuff? Change your code to look like this: ```python box = play.new_box(color='black', x=350, y=0, width=30, height=120) @play.when_key_pressed('up') async def do(key): box.y += 10 ``` Then try pressing the 'up' arrow on your keyboard. The box moves upward now! The code above is saying "when the up arrow key is pressed, add `10` to the box's `y` position". Adding to the box's `y` position moves the box up on the screen. Can you guess how we could get the box to move down when the down arrow key is pressed? Here's the full code for how you might do that: ```python box = play.new_box(color='black', x=350, y=0, width=30, height=120) @play.when_key_pressed('up') async def do(key): box.y += 10 @play.when_key_pressed('down') async def do(key): box.y -= 10 ``` (Remember that your program should still start with `import play` and end with `play.start_program()`.) So now the box moves up and down on the screen when we press the arrow keys. ### Adding a ball Now we need a ball. Add this line below the `new_box` line: ```python ball = play.new_box(color='dark red', x=0, y=0, width=20, height=20) ``` Now there's a ball but it's not moving. To get it moving, here's the full code to put in your program: ```python ball = play.new_box(color='dark red', x=0, y=0, width=20, height=20) ball.dx = 2 ball.dy = -1 # make the ball move @play.repeat_forever async def do(): ball.x += ball.dx ball.y += ball.dy ``` This makes the ball move by changing its `x` and `y` position (repeating forever) by the horizontal speed `dx` and the vertical speed `dy`. `ball.dx` and `ball.dy` are two variables we're making up to store the horizontal speed and vertical speed of the ball. The starting horizontal speed (`dx`) is 2 (to the right) and the vertical speed is -1 (down). But the ball doesn't bounce off the paddle, it just goes right through. To fix that, we have to detect when the ball is right next to the paddle and reverse its direction. Add this code to your program: ```python # make the ball bounce off the player's paddle @play.repeat_forever async def do(): if (ball.right >= box.left) and (ball.top >= box.bottom) and (ball.bottom <= box.top) and (ball.left < box.left): ball.dx = -2 ``` Now the ball bounces off the paddle! The code above checks three conditions which are best shown visually: ![if-statement](https://storage.googleapis.com/replit/images/1553634499339_d4182f199889cace97d4b9282f77f84f.pn) If the ball is anywhere over the red line in the grey areas, then the condition written below it becomes `True`. If all three conditions are `True` at the same time, that means the ball hit the paddle and its speed should be reversed (-4) so it goes the other way. (`<=` means "less than or equal" and `>=` means "greater than or equal"). Here's the whole program at this point: ```python import play box = play.new_box(color='black', x=350, y=0, width=30, height=120) ball = play.new_box(color='dark red', x=0, y=0, width=20, height=20) ball.dx = 2 ball.dy = -1 @play.when_key_pressed('up') async def do(key): box.y += 10 @play.when_key_pressed('down') async def do(key): box.y -= 10 @play.repeat_forever async def do(): ball.x += ball.dx ball.y += ball.dy # make the ball bounce off the player's paddle @play.repeat_forever async def do(): if (ball.right >= box.left) and (ball.top >= box.bottom) and (ball.bottom <= box.top) and (ball.left < box.left): ball.dx = -2 play.start_program() ``` ### Adding a computer player There should be another player. Let's create another box! Add this code near where you put the code starting with `box = play.new_box`: ```python other_box = play.new_box(color='black', x=-350, y=0, width=30, height=120) other_box.dy = 3 ``` We're making the box have a vertical speed of 2 when it moves, but we haven't made it move yet. To make the computer player follow the ball, we can add this code to our program: ```python # make the computer player follow the ball @play.repeat_forever async def do(): if ball.x < 0 and abs(ball.y-other_box.y) > other_box.dy: if other_box.y < ball.y: other_box.y += other_box.dy elif other_box.y > ball.y: other_box.y -= other_box.dy ``` Now when the ball is on the left side of the screen, the computer player will move toward the ball! We add to the box's `y` if the box is below the ball, otherwise we subtract from the box's `y` if it's above the ball. But oops, the ball doesn't bounce off the computer player's paddle (`other_box`). Let's make it do that by adding this code: ```python # make the ball bounce off the computer player's paddle @play.repeat_forever async def do(): if (ball.left <= other_box.right) and (ball.top >= other_box.bottom) and (ball.bottom <= other_box.top) and (ball.right > other_box.right): other_box.dy = play.random_number(1, 4) ball.dx = 2 ``` This code works just like the collision code from above but in reverse for the left paddle. Also when the ball hits the paddle we change the paddle's speed to a random number between 1 and 4 so the paddle will move either slower or faster. But oops again, now if we get the ball to bounce off the computer player's paddle, it doesn't bounce off the walls. To make the ball bounce off the walls, we add this code that checks that the ball is lower than the top of the screen and higher than the bottom of the screen: ```python # make ball bounce off bottom and top walls @play.repeat_forever async def do(): if ball.bottom <= play.screen.bottom: ball.dy = 1 elif ball.top >= play.screen.top: ball.dy = -1 ``` If the ball hits either the top or the bottom of the screen, the code above will reverse its speed so it bounces. And that's it! A simple pong game in about 50 lines of code! ## The final code Here's all the code in the tutorial in one place: ```python import play box = play.new_box(color='black', x=350, y=0, width=30, height=120) other_box = play.new_box(color='black', x=-350, y=0, width=30, height=120) other_box.dy = 3 ball = play.new_box(color='dark red', x=0, y=0, width=20, height=20) ball.dx = 2 ball.dy = -1 @play.when_key_pressed('up') async def do(key): box.y += 10 @play.when_key_pressed('down') async def do(key): box.y -= 10 # make the ball move @play.repeat_forever async def do(): ball.x += ball.dx ball.y += ball.dy # make the ball bounce off the player's paddle @play.repeat_forever async def do(): if (ball.right >= box.left) and (ball.top >= box.bottom) and (ball.bottom <= box.top) and (ball.left < box.left): ball.dx = -2 # make the computer player follow the ball @play.repeat_forever async def do(): if ball.x < 0 and abs(ball.y-other_box.y) > other_box.dy: if other_box.y < ball.y: other_box.y += other_box.dy elif other_box.y > ball.y: other_box.y -= other_box.dy # make the ball bounce off the computer player's paddle @play.repeat_forever async def do(): if (ball.left <= other_box.right) and (ball.top >= other_box.bottom) and (ball.bottom <= other_box.top) and (ball.right > other_box.right): other_box.dy = play.random_number(1, 4) ball.dx = 2 # make ball bounce off bottom and top walls @play.repeat_forever async def do(): if ball.bottom <= play.screen.bottom: ball.dy = 1 elif ball.top >= play.screen.top: ball.dy = -1 play.start_program() ``` And here's a [link to a repl with the code above](https://repl.it/@glench/Python-Play-pong-game-demo). ## More Challenges This game is pretty simple. Can you think of other things to add to make it more fun? Here are some suggestions for things to try: - Can you make the paddles change colors when the ball hits them? - How would you keep track of and show scores in the game? (Hint: look up the `play.new_text()` function.) - Did you find any glitches in the game? How would you try to fix those glitches? - How would you make the ball change speed differently depending on where it hits on the paddle? - Could you add multiple balls to the game? What else would you add to make the game more fun? # Python Play Thanks for reading this tutorial! If you make anything with Python Play, please post it in the comments! Python Play is currently in beta, which means some things may not work quite right. If you find a problem (usually called a "bug"), please send us a link to the repl where you found that bug. To find out more about all the things you can do with Python Play, [read the documentation here](https://github.com/replit/play)! Look for more Python Play features coming soon! Try it out and let us know what you think!
10
posted by glench (29) 2 months ago
โ–ฒ
10
Learning Web Development w/ Python Part 3
# Learning Web Development with Python and Django ## Part 3 _Thank you to @timmy_i_chen and @masfrost for sorting out the repl.it issue!_ ## Welcome! In [Part 1](https://repl.it/talk/learn/Learning-Web-Development-with-Python-Part-1/12880) and [Part 2](https://repl.it/talk/learn/Learning-Web-Development-with-Python-Part-2/12884) we learned how to use views and templates to create some basic pages on our web app. In the rest of the series, we will be creating our own **Web Forum app**, that allows users to post questions and other users to answer them. In this tutorial we will first cover how to split our large app into smaller apps, and then we will set up an external database for storing information. ## A New Basic Template In the previous parts, I have given you a basic Django template to start work with. However, this template is fairly limiting because it does not allow access to the **command line**. From now on, we will be using another template, which you can find [here](https://repl.it/@ArchieMaclean/Django-Template). This also fixes some other bugs that mean that normal Django repls cannot use external databases. Fork the repl, rename it to something like `Web Forum`, and let's begin! ### Running the repl Before, when using Django, we just had to click the `run` button in order to run. Now, we are presented with a prompt. To run the server, just press enter without typing anything, and you should get our familiar startup screen: ![image](https://storage.googleapis.com/replit/images/1555498000104_903f1cd023156a462a54072b37c458e5.pn) ----------------------------------------------------------------------------- Now we're ready to start. ## Apps So far, when creating our (very basic) websites, all of our files have been in the one folder - `main`. However, when you are running a large or complicated website, this can get very confusing and hard to work with. To fix this, Django has a built-in `startapp` function, that maks separating your code into separate **apps** very easy. For example, an online shop may have an app for: * Users - deals with logging on, password reset, e.t.c. * Shopping Cart - deals with adding/removing products from the cart. * Products - deals with displaying/updating products. The only problem is that `startapp` doesn't work with repl.it. ### DIY startapp Fortunately, all the `startapp` command does is create some folders and write a minimal amount of code, so we can do the same fairly quickly. We are creating a web forum, so let's create an app called 'Posts'. * Create a folder (at the top level, i.e. outside the `main` folder) called `Posts` * Within `Posts`, create empty files for each of the following: * `__init__.py` (2 underscores on either side of the `init`) * `admin.py` * `apps.py` * `models.py` * `tests.py` * `views.py` * Next, create a folder called `migrations` * Within `migrations`, add a file called `__init__.py` (2 underscores on either side of the `init`) The sidebar on your project should now look like this: ![image](https://storage.googleapis.com/replit/images/1555499982569_153f8c618224ad0dd3c3f3fb5958e3e4.pn) (Or similar with the light theme) Now we need to add just a little bit of code. To `apps.py` add the following code: ```python from django.apps import AppConfig class PostsAppConfig(AppConfig): name = 'Posts' ``` You don't really need to know how this code works - basically all it does is create a configuration class to allow the app to be used by Django. ### Updating settings.py After you have created the app, you need to update the `settings.py` file in order for Django to be able to find the app. To do this, go to `settings.py` and change the `INSTALLED_APPS` list. ```python INSTALLED_APPS = [ # stuff 'Posts.apps.PostsAppConfig', 'main', ] ``` This links to the code that we put in `apps.py` above. ------------------------------------------------------------------------------- ## Pages within Apps Now we have made our app! Let's make a home page within the app. #### Template First, we create folder called templates, then add a file called `base.html` into that folder. This will be our base template. Add the following `html` to `base.html`: ```html <!DOCTYPE html> <html> <head> <title>{% block title %}{% endblock title %}</title> </head> <body> <nav> This will be the navbar. </nav> <div id="content"> {% block content %} {% endblock content %} </div> </body> </html> ``` You should be familiar with most of this - the only bits I haven't covered before are: * `nav` - this is a `html` navigation bar element. * `div` - this is a `html` element that surrounds a distinct area in the `html`. These will be needed because we will be using `CSS` later to apply styles to different sections of the page. Next, create a file called `home.html`, and the following `html`: ```html {% extends 'base.html' %} {% block title %}Home{% endblock title %} {% block content %} <h1>Home</h1> <p>Welcome to the home page!</p> {% endblock content %} ``` You should be comfortable with this - if you don't understand the `{% %}` tags, then look back at [Part 2](https://repl.it/talk/learn/Learning-Web-Development-with-Python-Part-2/12884#extending-templates). #### View Now we need to create our view. In `Posts/views.py`, add the following code: ```python from django.views.generic import TemplateView class HomePageView(TemplateView): template_name='home.html' ``` This is just a basic class-based view that will display the template that we created above. #### URL Finally, we need to map a URL to our view. This is slightly more complicated because our page is within the `Posts` app, but `urls.py` is in `main`. How do we solve this? The answer is that we create another `urls.py` file **within** `Posts`, then redirect the `main` `urls.py` to this file. Sounds complicated? It is actually quite simple - let's do it. Within `Posts`, create a file called `urls.py`, and add the following code: ```python from django.urls import path from .views import HomePageView urlpatterns = [ path('', HomePageView.as_view(), name='home'), ] ``` This is fairly simple to understand: the URL `''` (i.e. no URL) gives the home page - so if the domain was https://example.domain.com, then the home page would be located at https://example.domain.com/. Next, in `main/urls.py`, change the file to this: ```python from django.urls import path, include # include has been added from django.contrib import admin urlpatterns = [ path('admin/', admin.site.urls), path('',include('Posts.urls')), # this has also been added ] ``` What does this do? We are importing the `include` function - this is used for redirecting to another file. So the new line we added just tells Django to check the `Posts.urls` file (that we created above). What about the first `''`? This can be confusing, but for example, if we changed the line to ```python path('hello/',include('Posts.urls')), ``` Then **all the URLs** in our `Posts/urls.py` file would be located at https://example.domain.com/hello/... . We will use this later - all of our `user` URLs will be located at https://example.domain.com/accounts/... If you run the program now (by running the repl and pressing `enter` without typing anything in), you will see that our home page is where it should be! ![image](https://storage.googleapis.com/replit/images/1555501691887_aebdae492bf467920b247e67ae20f2cf.pn) ### `url` vs `path` You may have noticed that the last time we used Django URLs, we have a list of `url`s - like this: ```python urlpatterns = [ url('',blah), url('about',blah), ] ``` whereas now we are using `path` instead. `path` is the new version of `url`. `path` is better because it doesn't use regex which can be confusing for beginners, and it also makes writing some URLs easier and makes them more readable - especially for database-driven pages. ------------------------------------------------------------------------ ## Databases Databases are a way of storing data in a way that can be accessed easily, encrypted easily and changed easily. Django usually uses `sqlite3` databases by default - in fact, if you look in your file list at the side, you will see Django has automatically created a file called `db.sqlite3`. However, repl.it doesn't support databases - if you refresh your page, all your data is lost. For this reason, we are going to use an external database. ### Setting up our Database Now we are going to set up our external database. We will be using `postgresql`, because it is widely used and we can use it for free. We will be using [ElephantSQL](https://www.elephantsql.com/) to host our database. First, create an account [here](https://customer.elephantsql.com/signup). Once you have done that, you should be faced with the following page: ![image](https://storage.googleapis.com/replit/images/1555502220876_8e9039bc14be5edf7f4cd7523863a099.pn) Click on `Create a new Instance` and follow through all the instructions. You can just use a **Tiny Turtle** instance because it is free. You will be asked to select a region - just pick somewhere near you. Once you've done that, you will be redirected back to the `instances` page. Click on the instance that you just created and you should get a page like this: ![image](https://storage.googleapis.com/replit/images/1555502596418_3854b044d269fb4ea87076774beee774.pn) (I've just greyed out the password so you aren't tempted to use my database and corrupt everything.) Now that the database host is ready, we can set up the database on Django! Go to `settings.py` and you will see a list called `DATABASES`. Change the list to look like this: ```python DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'Default Database', 'USER': 'User', 'PASSWORD': 'Password', 'HOST': 'Server', 'PORT': '' } } ``` Swap the text for the correct data that was given for the instance. For the server, you don't need the bit in brackets - so for my database, I can just set the server to `manny.db.elephantsql.com`. If you run this now, you get a long error: ![image](https://storage.googleapis.com/replit/images/1555503061679_80bc3dffb5aa84b1a8a5ca0b47d5cc01.pn) This is because Django was expecting there to be some default tables in the database. To fix this, instead of pressing enter at the command line, type the following: ```bash > python manage.py migrate ``` This applies the changes to the database that Django wants there to be. And that's the database set up! If you run the server now (by just pressing `enter`), then it runs correctly and our home page is displayed! ## Conclusion Now that we have set up our database, we're ready to create some database-driven web pages! In [Part 4](https://repl.it/talk/learn/Learning-Web-Development-with-Python-Part-4/13396) we will learn how to use databases with Django. Please upvote if you found this tutorial helpful, it supports me and lets me know that you want more! If you have any questions, post in the comments and I (or someone else) will answer them.
12
posted by ArchieMaclean (432) 1 month ago
โ–ฒ
113
Making a Phaser Game with HTML5 and JavaScript
# Making a Phaser Game with HTML5 and JavaScript Hi guys! Everybody likes to make games, right? And everybody has their own way of doing it. In this tutorial I wanted to share a very simple, yet effective way to make games in your browser! It should be easy enough for most people with javascript knowledge to follow along and, if you want to investigate further, there are endless possibilities out there! ![image](https://storage.googleapis.com/replit/images/1539468462288_75406edb94f04ca097cc5b4705ccbc85.pn) ### Phaser As Phaser describes itself it is a fast, free and fun open source framework for Canvas and WebGL powered browser games. And it really is! It is super simple to use and is quite easy to set up. No super extensive javascript knowledge is necessary and the process of making games is fun and rewarding. It also comes with tons of extra features that you may need in some more complicated games so while it caters to starters as well, it also does not lack depth if you want to look further. Anything from image editing to complex game mechanic mathematics is possible. ##### Sites to use The official Phaser website is [here](https://phaser.io). Additionally, because we are going to use Phaser 3, the latest release, the examples on the site will most probably not work for v3. If you want some examples of v3 features the link is [here](https://labs.phaser.io/). You should not need the examples during this tutorial but if you want to learn further that is where you start. Google works as well but be careful about which version is being discussed. Version 3 is relatively new and v2 has loads more documentation and examples and tutorials on it. However, I would recommend learning v3 because it is generally better in many ways and the knowledge will last you longer and it will be more current. #### Prerequisites (what you need before doing this tutorial) The pre-requisites are: * A basic understanding of HTML, CSS and Javascript. * Knowledge in Javascript about the `this` keyword. * Some time and patience. * 3 rolls of duct tape. * Lots of cardboard * Creativity ### Let's Get Started! The repl.it project that I will be using for this tutorial is [here](https://repl.it/@kaldisberzins/Phaser-Tutorial) and the website for it if you just wanna play the game is [here](https://phaser-tutorial.kaldisberzins.repl.co/). If you ever get stumped on a step that I take in this tutorial just check the repl and see how the code looks in it. If all else fails a bit of copy-paste will solve your issues. Make a new HTML/CSS/JS repl and follow along... So, first of all we need to include the Phaser script into our website. The only piece of HTML in this tutorial will be the following:`<script src="//cdn.jsdelivr.net/npm/[email protected]/dist/phaser.min.js"></script>`Just paste this into your project's HTML file right above your script tag that links to `script.js`. The order is important and if you get it wrong nothing will work. If your project is not working you should definitely have a look at the order of your scripts. The Phaser script should be first. With that out of the way, let's get into making our game! The first bit of code is a standard template that is in most simple Phaser games (more advanced ones may use a slightly different structure but the idea is the same). The code looks like this: ```javascript let config = { type: Phaser.AUTO, width: 800, height: 500, physics: { default: 'arcade', arcade: { debug: false } }, scene: { preload: preload, create: create, update: update } }; const game = new Phaser.Game(config); function preload(){ } function create(){ } function update(){ } ``` While this may look alien to you, don't stress. To follow along this tutorial you don't need to understand what everything does exactly. The main things you should pay attention to are: * The three functions at the bottom `preload`, `create` and `update`. These we will fill in with the game's code. * The `width` and `height` properties. You can set these to anything you like, I did not make it `window.innerWidth` and `window.innerHeight` because scaling can quickly become messy. It is easier to make it a fixed width for everybody. So now if you run your repl you should see a black square in your browser window. Success! If you do not, make sure you have the Phaser script in the right place and that you have the code in your `script.js` exactly like above. You should also get a message in the console, something like: ```%c %c %c %c %c Phaser v3.14.0 (WebGL | Web Audio) %c https://phaser.io background: #ff0000 background: #ffff00 background: #00ff00 background: #00ffff color: #ffffff; background: #000000 background: #fff``` This may look awful in the repl.it console but if you open it in a new tab and check the console it should be a colorful banner. ### Loading Assets The `preload` function that we are going to use for this section is where you load your assets. If you want some images or audio (Phaser does that as well) in your game you first have to load it here. This way you are loading all the required assets immediately and you can use them throughout the game. I have made some assets for this tutorial so that you do not need to find or make some yourself. Go [here](https://drive.google.com/drive/folders/1TzRicUBL8V0T_9fPMaNCL6M0UEV51irQ?usp=sharing) and click download like so to get the files: ![image](https://storage.googleapis.com/replit/images/1539468612344_eeb16f0a94e74fa401749d11f7b89333.pn) If you get the files in a `.zip` folder just unzip them and drop them into your repl. Once you have them in your repl we have to load them into our game. The following code in the `preload` function will do the trick: ```javascript this.load.atlas("player", "spritesheet.png", "sprites.json"); this.load.image("platform", "platform.png"); this.load.image("spike", "spike.png"); this.load.image("coin", "coin.png"); ``` The first parameter in all of the functions is the "key" for the image. This key you would use when you need to add the image into the game. You can put it as whatever you want but make sure it is descriptive of the image in some way. I suggest you keep them the same as mine so that later code in my tutorial works for you. The second parameter is the path to the image. Because I put the assets in the same folder as the html and js files the path is just the name of the image. If you put your assets in another folder the file path string would look like `"folder_name/file_name.png"`. You may also have noticed that the first command is a bit different. It loads an __atlas__ and not an image. An atlas is a collection of images put together to make a larger image accompanied by a file that states where all the smaller images are. If you open the file `sprites.json` in the assets I gave you you should see that it contains a bunch of named objects that have x, y, width and height properties among others. Each object is an image inside the larger image. In this tutorial we will use the atlas for the player animations. All of the frames for the player (in our case only three) are in the `spritesheet.png` file. The third parameter for the atlas is the path to the `.json` file which we looked at already. If you now run the current code the screen should remain black and no errors should be in the console. If you see a web audio warning that is fine, it does not mean anything important. It's just chrome messing with you. ### Adding Objects to Our Game The `create` function is where the building of our game happens. It is run right after `preload` and is run only once. If you want to add an object to the game, this is where you do it. If you want to repeatedly create some object. Make a function (read below) that creates the object and run that as may times as you like. So we now have loaded some images but we need to have something happen on the screen. Let's add a function in the `create` function that will spawn our player in. Add this code to the `create`function: ```javascript this.spawnPlayer = ()=>{ this.player = this.physics.add.sprite(400, 250, "player", "sprite_0"); } this.spawnPlayer(); ``` I put this in a seperate function so that we can spawn the player multiple times. We are saving the player to __`this`__ which is the Phaser game object so that we can access it from anywhere. The function itself creates a sprite (image/object) that is in the Phaser physics system. The parameters are: 1. X position 2. Y position 3. Image key 4. (optional) If the image is an atlas, which frame in the atlas. There may be a few more parameters but those are not important for this tutorial. The way we find out which frame is which in the atlas is by looking at the `sprites.json` file. Find an object and look at its x and y properties. For example `sprite_2` has the following object: ```javascript "sprite_2":{"frame":{"x":0,"y":0,"w":48,"h":64}... ``` We can see that the x and y coordinates of the frame are `0, 0`. This means that it will be in the top left corner. If you look at the top left corner of the `spritesheet.png` image you will see which frame is `sprite_2`. Try changing the last parameter in the add function to be `sprite_2`. You will see that it has changed. ##### Adding a Background If the only background color we could have would be black Phaser would look really bad. Luckily enough, Phaser has an easy way to add a background to our game. Just add this code to the top of your `create` function above the `spawnPlayer` function: ```javascript this.cameras.main.setBackgroundColor('#ffffff'); ``` This sets the background color for our main camera to white. If you have not used hex color codes before don't worry about it, just know that `#ffffff` is white. The only problem with that is that now we can't see where our canvas window starts and ends. We can fix this with a little CSS: ```css canvas{ border: 1px solid black; } ``` Now if you run your code it should look something like this: ![image](https://storage.googleapis.com/replit/images/1539468654218_bf2de4d9dc55069fde105a14f6c9818a.pn) You can see we have our little character in the middle of the screen. The background is now white. You may have noticed that the character is not offset to a side even though we put in the coordinates for the center of the screen. This is because Phaser draws images from their center. This makes it easier to center images. Another simple thing we can add to the game is a camera that follows the player. This is quite easy to do in Phaser: ```javascript this.spawnPlayer = ()=>{ this.player = this.physics.add.sprite(400, 250, "player", "sprite_0"); this.cameras.main.startFollow(this.player); }; this.spawnPlayer(); ``` The function should be quite self-explanatory and if you run it you should see no change for now. As long as you do not get any errors you are fine. ### Adding Platforms Before we start I wanted to show you the most basic way to add an image to the game. The method used above has a very specific use case (only for sprites). Here is a more general use way of doing it: ```javascript // This goes beneath the spawnPlayer function call this.platform = this.add.image(404, 302, "platform"); ``` This is good for some simple use cases like for example a logo image in your title screen. However it has its shortcomings. Imagine you want to create a map of these platforms. You would have to add `platform1` `platform2` and so on... It would be a nightmare. Let's not get started on collisions. So by now you can see why we are not going to use this to add our platforms. Instead we will have a group. Defining a new group is easy. Remove the above code and add this instead. ```javascript this.platforms = this.physics.add.staticGroup(); ``` Currently we are just defining a new static (non-moving) group and assigning it to the variable `this.platforms`. If you run this now the platform image will disappear. That is because we need to add some platforms to the group. This can be done simply like this: ```javascript //Below the spawnPlayer function this.platforms = this.physics.add.staticGroup(); this.platforms.create(404, 302, "platform"); ``` There we go! Now we have our platform back! But what is the benefit? In a moment when we deal with collisions you will see why. For now we will leave the platforms and get back to them later. ### Keyboard Inputs As you have probably gathered by now, Phaser has made its own version of everything you may need when developing games. Keyboard inputs are no exception. Phaser even supports many ways to do keyboard inputs. We are going to do the shortest and simplest. We are going to have a bunch of variables, one for each key. And we will check each frame if any of the keys are pressed and set velocities accordingly. The code for the keyboard variables in the `create` function looks like this: ```javascript this.key_W = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W); this.key_A = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A); this.key_D = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D); ``` You do not need to understand this, just get the idea of what is happening. When a player presses a key the variable associated with that key will have `isDown` set to `true`. This makes adding keybinds really easy. Now for the rest of this section we are using the `update` function. `update` is your game loop. This function is run very fast repeatedly all throughout your game. This is where you would handle things like movement and other stuff you would want to check every frame. If you would be coding your own physics this would be where you do it. In the `update` function now let's check if the W key is pressed: ```javascript if(this.key_W.isDown){ this.player.setVelocityY(-50); }else{ this.player.setVelocityY(0); } ``` Instead of incrementing or decrementing the Y property of the player we set its velocity. We do this because it sets a velocity within Phaser which has some benefits. First of all Phaser object velocities take into account the frame rate. If every frame you increase the position X of a player, the higher the frame rate the faster the player moves. However, Phaser counteracts this. We do not need to know how, just that no matter the frame rate the player will always move at the same speed. The value we put into `setVelocityY` is the amount of pixels we want it to move in one second. If you run this now you will see that is you press the W key your character will move up. Success! Now let's add keybinds for A and D. This is only a few more lines of code: ```javascript if(this.key_A.isDown){ this.player.setVelocityX(-50); }else if(this.key_D.isDown){ this.player.setVelocityX(50); }else{ this.player.setVelocityX(0); } ``` We have this in an if/else if statement because we don't want to head left and right at the same time. We can only go in one direction or the other. And that's it! We now have linked up our keyboard keys to our Phaser game! Now it's time to deal with physics. ### Game Physics Phaser also has its own physics engine. In fact it has three but we will only use the most basic one for this tutorial. Just simple square and square collisions. Before we can do collisions, how about we add some gravity. We only need it on the player so it would look like this: ```javascript this.spawnPlayer = ()=>{ this.player = this.physics.add.sprite(400, 250, "player", "sprite_0"); this.player.body.setGravityY(800); this.cameras.main.startFollow(this.player); }; ``` Now if you run your game you will see that the player drops. But he is dropping very slowly. Why so? This is because each frame we are setting his velocity to 0 if the W key is not pressed. Previously that was needed so that he would not just fly away but now we need to remove that bit: ```javascript //In the update function if(this.key_W.isDown){ this.player.setVelocityY(-50); }/*else{ this.player.setVelocityY(0); } NO LONGER NEEDED*/ ``` Now if you run it the player falls a bit faster. You can still fly with W but we will change that in a second. #### Collisions Now that we have gotten gravity mostly out of the way let's make the player collide with the platform that we have. We can do this with one simple line of code. Add this to your `spawnPlayer` function: ```javascript this.physics.add.collider(this.player, this.platforms); ``` That's it. Just one line of code does everything. But if you run this now it will not work. The player will fall right through. And this is actually for a really stupid reason. We are running this code before we add the platforms. All you have to do is move the `spawnPlayer` function __call__ (not the function itself) below where we add the platforms. And Viola! We have the player not falling through the platform. There are some small problems that we should address before moving on. First of all, When we press W we can fly endlessly. That defeats the point of the game. To prevent this all we need to do is to only let us jump when we are on the ground. This is easy to do: ```javascript if(this.key_W.isDown && this.player.body.touching.down)... ``` When the key W is down and the player's body is touching a platform with its bottom it will jump. If you run this now you will see that the player now makes many little jumps if you press W. To make the jumps larger we have to increase the `setVelocitY`: ```javascript if(this.key_W.isDown && this.player.body.touching.down){ this.player.setVelocityY(-550); } ``` And also while we are at it we can make the left/right movement a bit faster: ```javascript if(this.key_A.isDown){ this.player.setVelocityX(-150); }else if(this.key_D.isDown){ this.player.setVelocityX(150); }else{ this.player.setVelocityX(0); } ``` So there we have it! A running and jumping player! Now let's give him a map to run around in. #### Map Building Phaser supports multiple ways to build a map (of course). However, I have decided that it would be better to cook up our own map builder that would work off of a string. Spaces would indicate that at that position there is no platform, 1 would mean that there is, 2 that this is a spawn point for the player and a dot(.) would mean that this is the end of a row. The map I designed looks something like this: ```javascript //At the top of your js file const map = '11111111111111111111111111.'+ '1 1.'+ '1 1.'+ '1 2 1 1 1 1 1.'+ '1 1 1 1 1 1.'+ '1 1.'+ '1 1.'+ '1 1 1 1 1 1.'+ '1 1 1 1 1 1.'+ '1 1.'+ '1 1.'+ '1 1 1 1 1 1.'+ '1 1 1 1 1 1.'+ '1 1.'+ '1 1.'+ '11111111111111111111111111'; ``` You can see that it is a box that is riddled with platforms. How do we turn this into a map? The parser for this that I made is only a few lines of code: ```javascript //Goes instead of the previous platform adding code this.platforms = this.physics.add.staticGroup(); let mapArr = map.split('.'); let drawX = 0; let drawY = 0; mapArr.forEach(row=>{ drawX = 0; for(let i = 0; i<row.length; i++){ if(row.charAt(i)==='1'){ this.platforms.create(drawX, drawY, "platform"); }else if(row.charAt(i)==='2'){ if(row.charAt(i+1)==='1'){ this.spawnPlayer(drawX-4, drawY-12); }else if(row.charAt(i-1)==='1'){ this.spawnPlayer(drawX+4, drawY-12); }else{ this.spawnPlayer(drawX, drawY-12); } } drawX+=40; } drawY+=40; }); ``` First we split the string that we have into an array of rows using the . that says that a row ends at that point. Then we loop through each row and at each row we loop through each character in the row. If the character is a 1, we add a platform at that place. If the character is 2 we spawn the player. I have a bit more code there that checks if there is a platform to the left or right and that nudges the character to a side just so that the player does not spawn in a platform. Also, you may have noticed that we are calling `spawnPlayer` here with some parameters. These are just x and y coordinates of where to spawn. To make that work we just have to edit the `spawnPlayer` function like so: ```javascript this.spawnPlayer = (x, y)=>{ this.player = this.physics.add.sprite(x, y, "player", "sprite_0"); this.player.body.setGravityY(800); this.cameras.main.startFollow(this.player); }; ``` Now if you run this you should get a map inside of which the player can run around. You can mess around with the map string if you want and design your own map. I would love to see what you come up with in the comments! ### Player Animations A while ago, I mentioned that we would use the atlas for player animations. Now is the time! We have three frames in our atlas and we have only used one. It's time to use the other two. Phaser has its own animation manager (by now you get the idea - Phaser === everything) that makes it super simple to do animations. First we have to set up our animations: ```javascript // At the bottom of the create function this.anims.create({ key:"walk", frames:[{key:"player", frame:"sprite_2"}, {key:"player", frame:"sprite_1"}], frameRate:10, repeat:-1 }); this.anims.create({ key:"stand", frames:[{key:"player", frame:"sprite_0"}], frameRate:1 }); ``` This creates an animation for our player that we can play when we want. The array `frames` is what Phaser will loop though and play. `frameRate` is quite self explanatory - the amount of frames that are played each second. `repeat` with the value -1 will make the animation loop again and again. Not specifying `repeat` will just make it run once. The key is the string that we can use to reference to the animation later. Just the same way as with images. Now let's run the animations when we walk right or left: ```javascript //In the update function if(this.key_A.isDown){ this.player.setVelocityX(-200); this.player.anims.play("walk", true); }else if(this.key_D.isDown){ this.player.setVelocityX(200); this.player.anims.play("walk", true); }else{ this.player.anims.play("stand", true); this.player.setVelocityX(0); } ``` The `true` parameter is just whether if there is already an animation running, should Phaser continue it? If you set this to false you will see that it will just freeze on a frame. That is because every frame it is checking if a key is pressed and then playing the animation. It will start again every frame making it look like it is frozen. Now if you run this you will see that we have a running animation with the legs moving and the hat bobbing up and down. There is only one more problem with the sprite. The player does not flip when he runs to the left. This is an easy fix: ```javascript //In the update function if(this.key_A.isDown){ this.player.setVelocityX(-200); this.player.anims.play("walk", true); this.player.flipX = true; }else if(this.key_D.isDown){ this.player.setVelocityX(200); this.player.anims.play("walk", true); this.player.flipX = false; }else{ this.player.anims.play("stand", true); this.player.setVelocityX(0); } ``` There we go! Now we have a map, player animations, keybinds, physics and most of all - a weird blob of a character who has a hat that flaps in the breeze! ### The Final Step - Spikes and Coins Now let's add some spikes that the player has to dodge and some coins that the player can collect. First, let's add a score counter in the top of the screen that displays our score: ```javascript this.spawnPlayer = (x, y)=>{ this.player = this.physics.add.sprite(x, y, "player", "sprite_0"); this.player.body.setGravityY(800); this.physics.add.collider(this.player, this.platforms); this.cameras.main.startFollow(this.player); //====================================== this.player.score = 0; this.scoreText = this.add.text(0, 0, "Score: "+this.player.score, { fill:"#000000", fontSize:"20px", fontFamily:"Arial Black" }).setScrollFactor(0).setDepth(200); }; ``` `setScrollFactor(0)` will make sure that when our camera moves, the text does not. This way it will always be in the same position in the top-left of the screen. Text is drawn from its top-left (don't ask me why it is one way for one thing and another for another) so drawing it at `0, 0` will put in the top-left corner. `setDepth(200)` will make sure the text always appears on top. We also make a variable for the score of the player that can be increased when we collect a coin. #### Coins Time to make an incentive to run and jump around. Coins will be a `c` in our map string. So, the map would now look like this: ```javascript const map = '11111111111111111111111111.'+ '1 c 1.'+ '1 c c c 1.'+ '1 2 1 1 c 1 c 1 1.'+ '1 1 1 1 1 1.'+ '1 1.'+ '1 c c 1.'+ '1 c 1 1 c 1 c 1 1.'+ '1 1 1 1 1 1.'+ '1 1.'+ '1 c c c 1.'+ '1 1 c 1 c 1 1 1.'+ '1 1 1 1 1 1.'+ '1 1.'+ '1 c c c c 1.'+ '11111111111111111111111111'; ``` Now to make this work we have to add an option of what to do if the current character is a `c` in our map parser. I added something like this: ```javascript this.platforms = this.physics.add.staticGroup(); //================================== this.coins = this.physics.add.group(); //================================= let mapArr = map.split('.'); let drawX = 0; let drawY = 0; mapArr.forEach(row=>{ drawX = 0; for(let i = 0; i<row.length; i++){ if(row.charAt(i)==='1'){ this.platforms.create(drawX, drawY, "platform"); }else if(row.charAt(i)==='2'){ if(row.charAt(i+1)==='1'){ this.spawnPlayer(drawX-4, drawY-12); }else if(row.charAt(i-1)==='1'){ this.spawnPlayer(drawX+4, drawY-12); }else{ this.spawnPlayer(drawX, drawY-12); } //================================= }else if(row.charAt(i)==='c'){ this.coins.create(drawX, drawY+10, "coin"); } //================================= drawX+=40; } drawY+=40; }); ``` If you run this you will see that a bunch of little coins appear. But we can't collect them! This is fairly easy to add: ```javascript // Add this after the map parsing code this.physics.add.overlap(this.player, this.coins, this.collectCoin, null, this); ``` This function will check if there is an overlap between two objects. The two objects are the first two parameters. If there is an overlap, it will run the function that is passed in with the third parameter. `null` is just there for reasons and `this` is just passing on the `this` value to the function. We now need to make a function `collectCoin` that will run if there is an overlap: ```javascript this.collectCoin = (player, coin)=>{ player.score+=10; this.scoreText.setText("Score: "+ this.player.score); coin.destroy(); }; ``` If you run this you will see that you can now collect coins and increase your score. Success! There is only one more step before we are done. #### Spikes Time to add some difficulty to the game. We are going to have spikes that if you step on they will clear your score and respawn you. Let's first add them to our map as an `s`: ```javascript const map = '11111111111111111111111111.'+ '1 c 1.'+ '1 c c s c 1.'+ '1 2 1 s 1 c 1 c 1 1.'+ '1 1 1 1 1 1.'+ '1 1.'+ '1 c c s s 1.'+ '1 c 1 s 1 c 1 c 1 1.'+ '1 1 1 1 1 1.'+ '1 1.'+ '1 c s c c 1.'+ '1 s 1 c 1 c 1 s 1 1.'+ '1 1 1 1 1 1.'+ '1 1.'+ '1 c c c c 1.'+ '11111111111111111111111111'; ``` And now we can render them into our game: ```javascript this.platforms = this.physics.add.staticGroup(); this.coins = this.physics.add.group(); //================================== this.spikes = this.physics.add.group(); //================================== let mapArr = map.split('.'); let drawX = 0; let drawY = 0; mapArr.forEach(row=>{ drawX = 0; for(let i = 0; i<row.length; i++){ if(row.charAt(i)==='1'){ this.platforms.create(drawX, drawY, "platform"); }else if(row.charAt(i)==='2'){ if(row.charAt(i+1)==='1'){ this.spawnPlayer(drawX-4, drawY-12); }else if(row.charAt(i-1)==='1'){ this.spawnPlayer(drawX+4, drawY-12); }else{ this.spawnPlayer(drawX, drawY-12); } }else if(row.charAt(i)==='c'){ this.coins.create(drawX, drawY+10, "coin"); //================================== }else if(row.charAt(i)==='s'){ this.spikes.create(drawX, drawY+10, "spike"); } //================================== drawX+=40; } drawY+=40; }); ``` Let's do what we did last time - add an overlap detector between the player and the spikes. The code is pretty much the same: ```javascript //Next to the other overlap checker for the coins this.physics.add.overlap(this.player, this.spikes, this.die, null, this); ``` And now we have to make a function `die` that will be run when the player hits the spike. All we will do is stop the game and display text saying **YOU DIED**: ```javascript this.die = ()=>{ this.physics.pause(); let deathText = this.add.text(0, 0, "YOU DIED", { color:"#d53636", fontFamily:"Arial Black", fontSize:"50px" }).setScrollFactor(0); Phaser.Display.Align.In.Center(deathText, this.add.zone(400, 250, 800, 500)); } ``` `this.physics.pause` is what stops the game. The text adding should be pretty self explanatory. The bit that may be confusing is the line after that. This is the code I used to center the text. It accepts two arguments - the object to center and the zone in which to center it in. `this.add.zone` in turn accepts four arguments - the x, y, width and height of the zone. The x and y are in the center of the screen and the width is the width of the screen and the same for the height. When you run this code and jump on a spike you will see that it shows some big red text saying __YOU DIED__. And there we have it! Our completed game! Make sure to celebrate by wrapping __lots__ of duct tape around some cardboard. That was what the duct tape and cardboard were for. Nothing, really :). ## Final Word Thank you for sticking to the end of this monster of a tutorial. I hope you are proud of what you have made. If you liked this tutorial, please show support by voting for it. If you have any questions, suggestions or if you found a typo don't hesitate to post it in the comments! Also, if you put a spin on the game or make a cool map that be sure to share it! I would love to see what you guys can make out of this :). If you are too lazy to scroll up, the link to the repl that I made is [here](https://phaser-tutorial.kaldisberzins.repl.co/). Also, if you would like me to make some follow up tutorials outside of the competition about some more advanced features like scenes and (multiplayer?) then be sure to leave a comment. If enough people want it I will be sure to make some more tutorials. ## __EDIT__ I made an additional demo that delves into some more complicated concepts but it looks a lot better (I stole some sprites off the internet). It is just some uncommented code that you can play around with and try and see if you can make anything out of it. If you want to check it out you can find it [here](https://repl.it/@kaldisberzins/Phaser-Demo). Just wanna play it? Go [here](https://phaser-demo--kaldisberzins.repl.co/). Also, thank you guys for all the support in the comments! So heartwarming to see that many people like it. [email protected]_
20
posted by kaldisberzins (230) 7 months ago
โ–ฒ
10
๐ŸŽ Using Git with Repl.it: A Short Guide
# ๐ŸŽ Using Git with Repl.it: A Short Guide I stumbled upon [this](https://repl.it/talk/ask/SOLVED-Is-it-possible-to-use-git/12937) post, which described a method to access Git commands from within your repl. Using a Version Control System (VCS) like Git is incredibly useful, and even more so when augmented with GitHub. In the post, the accepted answer recommended using the `os` Python module and accessing system commands from there. ```python import os os.system('git clone https://github.com/EanKeen/Sigag') os.chdir('./Sigag') os.system('git status') ``` I created a little [repl](<https://repl.it/@eankeen/git-test>) that demonstrates this. Make sure you delete the `Sigag` directory before starting the program (although it's not a strict requirement). After the clone has finished, I'm able to leave the repl, reopen the repl, and have the Git repository still there. However, there is a much easier way to use Git commands. In most repls, you're able to enter the shell. Press `F1`, and type `shell`. Note that with some keyboards, you may need to press `Fn`+`F1`. (You can also press Ctrl+Shift+p - thanks @ArchieMaclean!) ![image](https://storage.googleapis.com/replit/images/1555799479365_3012213c48d096ade2cc9a6df8d2b65f.pn) Now, you can just clone it the usual way. ```sh git clone https://github.com/EanKeen/Sigag cd ./Sigag git status ``` ![image](https://storage.googleapis.com/replit/images/1555799638232_3678f7f131d11b2360c2ec6f985b64c5.pn) Once the clone has finished, you should see the `Sigag` directory in your file tree! However, the output of `ls` and your file tree may be different sometimes. For example, I would type `ls` into the shell, and it will show `Sigag` as a directory. However, my file tree would only show `main.py`. To fix this, simply refresh the page. It may seem a bit convoluted getting this to work, but easier methods of using git will be introduced at a later date, according to the post below. The screenshot below was taken on the publish date of this guide. ![image](https://storage.googleapis.com/replit/images/1555798032505_53c3d59b4d5fd13df72a14aa25640bc5.pn) I hope this was helpful ๐Ÿ˜„. Let me know if this helped you!
3
posted by eankeen (455) 1 month ago
โ–ฒ
5
Using Custom Compiler Switches
Firefox: using right-click ![Firefox](https://storage.googleapis.com/replit/images/1557433217299_2f6f25210d17a60ffdca09b3eaab19a6.gi) Chrome: using ctrl+shift+p ![Chrome](https://storage.googleapis.com/replit/images/1557433236992_e79dc30aad1d4dbba28b73bfa06aef95.gi) Then, you can apply this knowledge to any language you want! Good luck, have fun! Supposedly, F1 also takes you to the command palette, but the two shown above should be enough.
2
posted by a5rocks (448) 13 days ago
โ–ฒ
21
Make your first Pygame ๐ŸŽฎ
## Make games the easy way, and forget about the setup ๐Ÿ˜Œ ![](https://tiresome-aunt.surge.sh/ezgif-9aa456d6-a2de-4d54-a2b3-6828c507544d.com-video-to-gif_(1).gif) [Demo + Code](https://repl.it/@jajoosam/paddleBasket) โฏ๏ธ ๐Ÿ‘จโ€๐Ÿ’ป I've heard coding in python is quite delightful! And I agreed once I made my first python app that didn't just run on the terminal - a game made with [Pygame](https://www.pygame.org/). You'd usually have to spend a while getting set up, installing Pygame, dependencies and then have to spend time compiling an executable before sharing your game. But with [replit's new GFX system](https://repl.it/talk/announcements/Replit-GFX-Public-Beta-Build-Games-and-GUI-Apps/11545) - there's absolutely no need for that โœŒ๏ธ This is a tutorial to get started with Pygame, and make a simple game within 30 minutes! ## ๐Ÿ› ๏ธ Getting our environment running Head over to [repl.it](http://repl.it) and once you're logged in, hit `new repl โ†’ Pygame` to create the repl where we're going to be making our game. ![](https://tiresome-aunt.surge.sh/-7158aee6-09d3-41ef-a559-42f5cb010b22untitled) That's it ๐Ÿ˜‰ ## ๐ŸŽฒ Understanding the game Before we start coding, let's understand what we're making ๐Ÿ› ๏ธ Our game concept is pretty straightforward - there's a paddle - a simple rectangle that moves left or right in the screen, attempting to catch balls falling from the top of the screen. A higher score is more number of balls caught โšพ ## ๐Ÿ‘จโ€๐Ÿ’ป Initializing pygame You can go right ahead and paste this code in your repl! ```python # adding libraries we're going to use import pygame from random import randint pygame.init() # initializing variables to account for the number of balls caught, and total dropped score = 0 total = 0 myfont = pygame.font.SysFont('monospace', 50) # creating a font to write the score in # Making dictionaries with settings for everything. display = { "width": 800, "height": 600 } paddle = { "width": 200, "height": 20, "x": 300, "y": 580, "velocity": 10 } ball = { "radius": 15, "y": 30, "x": randint(0, display["width"]), "velocity": 20 } # creating a window, and launching our game win = pygame.display.set_mode((display["width"], display["height"])) # 800 width, 600 height ``` I've added comments to explain what each line does ๐Ÿ˜„ Make sure to paste in the dictionaries too, they'll be super useful soon! ## ๐Ÿ‘พ The paddle Our paddle is going to be just a little rectangle that moves when we hit the arrow keys. Before we can start making it, we need to create the main loop. Pygame will run the code inside this loop continuously, to update the screen based on inputs. Paste all this in! ```python while True: pygame.time.delay(100) win.fill((255, 255, 255)) for event in pygame.event.get(): if event.type == pygame.QUIT: break keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: paddle["x"] -= paddle["velocity"] if keys[pygame.K_RIGHT]: paddle["x"] += paddle["velocity"] pygame.draw.rect(win, (255, 0, 0), (paddle["x"], paddle["y"], paddle["width"], paddle["height"])) pygame.display.update() ``` โ€‹ ```python pygame.quit() ``` Don't worry, I'm not just going to leave you like that xD Let's break this up into smaller blocks to explain what everything does! Let's talk about everything inside the while loop, which will run forever - since `True` will always remain `True` ๐Ÿ˜ฎ ```python pygame.time.delay(100) win.fill((255, 255, 255)) ``` We're adding the delay so that the loop doesn't run too often, and there's some gap between each cycle - keeping our repl from crashing. `100` is delay in milliseconds, causing the loop to run 10 times a second. `win.fill()` takes a color in `RGB` as it's argument - and `255, 255, 255` represents white, filling our window with white before we draw anything onto it ๐Ÿ–Œ๏ธ ```python for event in pygame.event.get(): if event.type == pygame.QUIT: break ``` This piece of code goes over all events that pygame gives us, and breaks the loop if Pygame has been quit. When the loop breaks, we go to the line which says `pygame.quit()`- you know what that does ๐Ÿ˜› ```python keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: paddle["x"] -= paddle["velocity"] if keys[pygame.K_RIGHT]: paddle["x"] += paddle["velocity"] ``` To get this - lets first clear out our understanding about the coordinate grid - it doesn't start at the center in pygame! In fact, the top left corner is `0, 0` and `x` increases as you go right, while `y` increases as you move down. This block of code gets all currently pressed keys, and checks whether the left or right keys are pressed. If they are, it changes the `x` coordinates of the paddle - reducing if โฌ…๏ธ is pressed, and increasing if โžก๏ธ is pressed by the velocity we set in the `paddle` dictionary. Try changing the `velocity` to see what happens ๐Ÿค” ```python pygame.draw.rect(win, (255, 0, 0), (paddle["x"], paddle["y"], paddle["width"], paddle["height"])) pygame.display.update() ``` This is where we actually draw our paddle to the screen - in the window called `win`, red in color (`255, 0, 0` RGB) - at `paddle[x]` on the x axis, and `paddle[y]` on the y axis. We've also set the width and height in the `paddle` dictionary, feel free to mess around with it! Finally, `pygame.display.update()` updates the entire screen with what we've drawn in this cycle of the loop! Try running the code, and hitting the left and right arrow keys! You should see a little rectangle moving around ๐Ÿ‘‡ ![](https://tiresome-aunt.surge.sh/CleanShot_2019-03-13_at_19-ac9eb692-26e2-421e-b279-84978459c836.38.32.gif) ## โšฝ Generating falling circles Let's bring up the `ball` dictionary up again ๐Ÿ‘‡ ```python ball = { "radius": 15, "y": 30, "x": randint(0, display["width"]), "velocity": 20 } ``` What does the `"x"` line do? We're selecting a random x co-ordinate between `0` and `display["width"]` (currently 800) - using the `randint` function we imported right at the start of our code. Add this inside your while loop, right before you draw the paddle to the screen: ```python ball["y"] += ball["velocity"] pygame.draw.circle(win, (0, 0, 255), (ball["x"], ball["y"]), ball["radius"]) ``` We're increasing the y co-ordinate of the ball by its `velocity` and drawing the ball again in every cycle of the loop. ## ๐Ÿ† When do you actually score a point, though? The final part of our game would be checking if the ball hits the paddle when it's at the bottom of the screen. Collision detection is going to be essential to most of the games you're going to make in the future, so let's go over it here! ```python if ball["y"] + ball["radius"] >= paddle["y"]: if ball["x"] > paddle["x"] and ball["x"] < paddle["x"] + paddle["width"]: score += 1 total += 1 ball["y"] = 0 ball["x"] = randint(0, display["width"]) ``` First up, we're learning if the ball has hit the level of the paddle - by checking if the ball's radius + it's position on the y axis is equal to the position of the paddle. ```python if ball["x"] > paddle["x"] and ball["x"] < paddle["x"] + paddle["width"] ``` With this long condition, we're testing if - The ball's position on the X axis is greater than the paddle's position on the X axis AND - The ball's position on the X axis is lesser than the sum of the paddle's position on the X axis and its width If this condition is true, it means that the ball has landed on the paddle, and we increase the score ๐Ÿ™Œ Maybe this image helps a bit ๐Ÿคž ![](https://tiresome-aunt.surge.sh/-98fcc7ff-0ac4-4a09-8d46-2e06394d73b8untitled) After this, regardless of whether a point has beens scored or not, we add one to the total number of balls landed - and reset the ball's position, setting the ball's y co-ordinate to 0, and generate a random position for the X axis. Lastly, we're going to write the score on the screen ๐Ÿ… ```python textsurface = myfont.render("score: {0}/{1}".format(score, total), False, (0, 0, 0)) win.blit(textsurface, (10, 10)) ``` We create a new [surface](https://www.pygame.org/docs/ref/surface.html) where we write the text using python's [format](https://www.programiz.com/python-programming/methods/string/format) function, replacing `{0}` with the socre, and `{1}` with the total. We're writing this in black (`0, 0, 0` RGB). `win.blit(textsurface, (10, 10))` merges the text with the main window, at co-ordinates `10, 10`. And that's the game - the full thing ๐Ÿคฏ ## ๐Ÿ”ฎ Things to try - Changing the contents of the dictionary and seeing what happens โ“ - Make multiple balls fall at the same time ๐Ÿ”ด ๐Ÿ”ต โšซ - Make the paddle move up and down too ๐Ÿš€ - Adding poison balls - the game stops when your paddle hits one ๐Ÿ˜ต Be sure to put down any questions or improvements down in the comments ๐Ÿ’ฌ And here's all the code for you to go over again - I highly recommend going through this to help you understand the flow of the program, and the sequencing of everything if you were even a little confused by this guide ๐Ÿ˜… https://repl.it/@jajoosam/paddleBasket
2
posted by jajoosam (471) 2 months ago
โ–ฒ
13
Julia Fractals in JavaScript
***Originally written for [Hack Club](https://hackclub.com), a global network of high-school hackers and coding clubs.*** Fractals. You've seen them. They're beautiful: ![File:Mandelbrot sequence new.gif](https://upload.wikimedia.org/wikipedia/commons/a/a4/Mandelbrot_sequence_new.gif) What kind of crazy black magic lets computers draw these things?? It must be likeโ€ฆ really complicated. WRONG. Fractal renderers are _ridiculously_ simpleโ€”and to prove it, you're going to write one. [**Click here to get started.**](https://repl.it/@polytrope/julia-fractals-starter) _You should start with this simple HTML document:_ ```html <!DOCTYPE html> <html> <head> <title>Julia Fractals</title> </head> <style> body { background: black; color: white; } canvas { border: 1px solid white; } </style> <body> <h2></h2> <canvas></canvas> </body> <!-- Import math.js --> <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/5.6.0/math.min.js"></script> <script> // The HTML elements we are using var header = document.querySelector('h2') var canvas = document.querySelector('canvas') var ctx = canvas.getContext('2d') // The size of our canvas var width = 200 var height = 200 // Set the size of our canvas canvas.width = width canvas.height = height // The XY coordinates of the mouse over the canvas var mouseX = 0 var mouseY = 0 </script> </html> ``` ## The Complex Plane Fractals arise from basic arithmetic with **complex numbers**. Despite their name, complex numbers are actually quite simple; instead of a number _line_, complex numbers exist on a _plane_. Complex numbers are usually written `x+y*i`. So `2+4i` is at the point (2, 4). ![Mousing around the complex plane](https://storage.googleapis.com/replit/images/1554408244144_33a071bc40ed05d44d33eda2e246dd90.gi) `i` is the square root of -1 (so `i*i=-1`). We can't find a value for `i` on the "real" number line, because `x*x` is _never_ negative. For a long time, mathematicians just ignored square roots of negative numbersโ€”just like they used to ignore negative numbers. _They aren't "real" numbers, so what good are they?_ Then somebody thought to put `i` on its own separate, _vertical_ number line. The **Complex Plane** was bornโ€”you won't believe what happened next. ### From Pixels to Points Each _pixel_ on our canvas corresponds to a _point_ on the complex plane. We need a function to convert XY pixels to complex points. Complex numbers aren't "built in" for most programming languages. We'll use a library called math.js to work with them in JavaScript. To create a new complex number with math.js, we simply write `math.complex(x, y)` Add a function called `pixelToPoint` to the end of your script: ```javascript // the rest of your script... // Turn XY pixel coordinates into a point on the complex plane function pixelToPoint(x, y) { // Map percentage of total width/height to a value from -1 to +1 var zx = (x/width)*2-1 var zy = 1-(y/height)*2 // Create a complex number based on our new XY values return math.complex(zx, zy) } ``` This takes the X and Y coordinates for a pixel, divides each to get that pixel's percentage of the overall width/height, and maps that percentage to a value from -1 to +1. The result is a point between `-1-1i` and `1+1i`. Note how `zx` is `(x/width)*2-1`, but `zy` is `1-(y/height)*2`. `zy` is flippedโ€”this is just because on a webpage, pixel coordinates go top-to-bottom (and we want our complex plane to be bottom-to-top). Now let's use that function to pick out a point on the plane with the mouse. Later on we'll need a point called `constant` for our fractal equation, so let's use that. Add a complex number called `constant` to the top of your script, just before `pixelToPoint` and just after `mouseX`/`mouseY`: ```javascript // mouseX/mouseY + the rest of your script... // The point we use for C in our Julia Set equation var constant = math.complex(0.28, 0.01) // pixelToPoint + the rest of your script... ``` Now let's hook up the mouse to the canvas. Add two new functions called `update` and `move` to the end of your script. `move` will fire every time the mouse moves to a new point on the canvas, and `update` will change the header to show that point. We'll also add an event listener to the canvas to trigger `move`: ```javascript // pixelToPoint + the rest of your script... // Update the elements that need to change function update() { header.innerHTML = constant.toString() } // What to do when the mouse moves over the canvas function move(event) { // Get the mouse's XY coordinates on canvas mouseX = event.clientX-canvas.offsetLeft mouseY = event.clientY-canvas.offsetTop // Turn mouse coordinates into a point on the complex plane constant = pixelToPoint(mouseX, mouseY) // Round that point off to the nearest 0.01 constant.re = math.round(constant.re*100)/100 constant.im = math.round(constant.im*100)/100 // Update everything! update() } // Trigger move every time the mouse moves over canvas canvas.addEventListener('pointermove', move) ``` Note that we're rounding `constant` to the nearest 0.01: ```javascript constant.re = math.round(constant.re*100)/100 constant.im = math.round(constant.im*100)/100 ``` This just looks a little neater. `constant.re` is the "real" part of the numberโ€”the X value. `constant.im` is the "imaginary" partโ€”the Y value. Now if you run the page and mouse over the canvas, you should see `constant` updating in the header! ![Selecting points on the complex plane](https://storage.googleapis.com/replit/images/1554408364480_1d35dceddec7e5915d6eb7af1dd4a71a.gi) Your whole script should look like [this](https://repl.it/@polytrope/julia-fractals-complex-plane): ```html <script> // The HTML elements we are using var header = document.querySelector('h2') var canvas = document.querySelector('canvas') var ctx = canvas.getContext('2d') // The size of our canvas var width = 200 var height = 200 // Set the size of our canvas canvas.width = width canvas.height = height // The XY coordinates of the mouse over the canvas var mouseX = 0 var mouseY = 0 // The point we use for C in our Julia Set equation var constant = math.complex(0.28, 0.01) // Turn XY pixel coordinates into a point on the complex plane function pixelToPoint(x, y) { // Map percentage of total width/height to a value from -1 to +1 var zx = (x/width)*2-1 var zy = 1-(y/height)*2 // Create a complex number based on our new XY values return math.complex(zx, zy) } // Update the elements that need to change function update() { header.innerHTML = constant.toString() } // What to do when the mouse moves over the canvas function move(event) { // Get the mouse's XY coordinates on canvas mouseX = event.clientX-canvas.offsetLeft mouseY = event.clientY-canvas.offsetTop // Turn mouse coordinates into a point on the complex plane constant = pixelToPoint(mouseX, mouseY) // Round that point off to the nearest 0.01 constant.re = math.round(constant.re*100)/100 constant.im = math.round(constant.im*100)/100 // Update everything! update() } // Trigger move every time the mouse moves over canvas canvas.addEventListener('pointermove', move) </script> ``` ## Drawing Pixels Let's draw some colors on our canvas. Every _pixel_ maps to a _point_, and every _point_ maps to a _color_. Let's make it so that every time we change `constant` we draw in a color for that pixel. To do this, we need a new function called `pointToColor`. This function will turn any point into an RGB color, simply by using the "real" (X) value `point.re` for Red and the "imaginary" (Y) value `point.im` for green: ```javascript // constant + the rest of your script... // Turn a point on the complex plane into a color function pointToColor(point) { var red = point.re*255 var green = point.im*255 return `rgb(${red}, ${green}, 0)` } // pixelToPoint + the rest of your script... ``` We will also need two more functions, called `drawPixel` and `draw`. `drawPixel` will draw a given color at a given pixel. `draw` will ```javascript // pixelToPoint + the rest of your script... // Draw a single pixel on our canvas function drawPixel(x, y, color) { ctx.fillStyle = color ctx.fillRect(x, y, 1, 1) } // Redraw our canvas function draw() { // Turn the point under the mouse into a color var color = pointToColor(constant) // Draw over the pixel under the mouse with that color drawPixel(mouseX, mouseY, color) } // update + the rest of your script... ``` Let's quickly look at `drawPixel`. This is how basic drawing works with canvas. First you set properties like `fillStyle` on the "drawing context" (usually labelled `ctx`). Then you trigger a drawing operation like `fillRect` to draw shapes onto the canvasโ€”in this case, a single 1x1 rectangle. Finally, we need to add `draw()` to `update` so that our canvas will redraw anytime we call `update`: ```javascript // draw + the rest of your script... // Update the elements that need to change function update() { header.innerHTML = constant.toString() draw() } // move + the rest of your script... ``` Now if you run the page, you should see little colored pixels show up as you mouse over the plane: ![Drawing in pixels on the complex plane](https://storage.googleapis.com/replit/images/1554408436658_ab92846587460e292ecc1c12bd469d5a.gi) Your script should now look like [this](https://repl.it/@polytrope/julia-fractals-drawing-pixels): ```html <script> // The HTML elements we are using var header = document.querySelector('h2') var canvas = document.querySelector('canvas') var ctx = canvas.getContext('2d') // The size of our canvas var width = 200 var height = 200 // Set the size of our canvas canvas.width = width canvas.height = height // The XY coordinates of the mouse over the canvas var mouseX = 0 var mouseY = 0 // The point we use for C in our Julia Set equation var constant = math.complex(0.28, 0.01) // Turn a point on the complex plane into a color function pointToColor(point) { var red = point.re*255 var green = point.im*255 return `rgb(${red}, ${green}, 0)` } // Turn XY pixel coordinates into a point on the complex plane function pixelToPoint(x, y) { // Map percentage of total width/height to a value from -1 to +1 var zx = (x/width)*2-1 var zy = 1-(y/height)*2 // Create a complex number based on our new XY values return math.complex(zx, zy) } // Draw a single pixel on our canvas function drawPixel(x, y, color) { ctx.fillStyle = color ctx.fillRect(x, y, 1, 1) } // Redraw our canvas function draw() { // Turn the point under the mouse into a color var color = pointToColor(constant) // Draw over the pixel under the mouse with that color drawPixel(mouseX, mouseY, color) } // Update the elements that need to change function update() { header.innerHTML = constant.toString() draw() } // What to do when the mouse moves over the canvas function move(event) { // Get the mouse's XY coordinates on canvas mouseX = event.clientX-canvas.offsetLeft mouseY = event.clientY-canvas.offsetTop // Turn mouse coordinates into a point on the complex plane constant = pixelToPoint(mouseX, mouseY) // Round that point off to the nearest 0.01 constant.re = math.round(constant.re*100)/100 constant.im = math.round(constant.im*100)/100 // Update everything! update() } // Trigger move every time the mouse moves over canvas canvas.addEventListener('pointermove', move) </script> ``` ## Drawing the Plane We don't just want to draw one pixel at a timeโ€”we want the whole plane at once. Let's modify our `draw` function so it fills in _every_ pixel: ```javascript // drawPixel + the rest of your script // Redraw our canvas function draw() { // Loop over every column of pixels for (var y = 0; y < height; y++) { // Loop over every row of pixels for (var x = 0; x < width; x++) { // Turn this pixel into a point in the complex plane var point = pixelToPoint(x, y) // Turn that point into a color var color = pointToColor(point) // Draw over this pixel with that color drawPixel(x, y, color) } } } // update + the rest of your script... ``` This new `draw` function is actually pretty simple. It uses two loopsโ€”one for X and one for Yโ€”to go over every pixel in our canvas. Then it gets the complex plane point for that pixel. Then it gets the color for that point. Then it draws that color at that pixel. If you run the page, you should see the same field of red/green pixelsโ€”only now they are all filled in! ![The full plane, filled in](https://storage.googleapis.com/replit/images/1554408579988_3395add24c7bc35f64073bb512c34a3e.pn) The only problem is that the page waits for the mouse to move before drawing the canvas. Let's fix that with a call to `update` at the end of our script, just after we add the event listener: ```javascript // addEventListener + the rest of your script... // Update everything! update() ``` ### Simple Complex Arithmetic Let's make a few more changes to our `pointToColor` function, just to understand what's going on. First, try adding `point = point.sub(constant)` To the top of `pointToColor`: ```javascript // constant + the rest of your script... // Turn a point on the complex plane into a color function pointToColor(point) { point = point.sub(constant) var red = point.re*255 var green = point.im*255 return `rgb(${red}, ${green}, 0)` } // pixelToPoint + the rest of your script... ``` This means we _subtract_ `constant` from our `point` before we turn it into a color. Since complex numbers aren't built into JavaScript, we can't use `+-*/`โ€”math.js has us use `.add()` `.sub()` `.mul()` `.div()` instead. What does it mean to add/subtract a complex number? Well, it's pretty much the same as adding regular numbers: 1+2i + 1+2i = 2+4i. However, there is a better, more _geometric_ way to think about this: we are using one point to _move_ another point _around the plane_: ![Adding points on the Complex Plane](https://storage.googleapis.com/replit/images/1554408625002_632c18d5e84faad25763a8a65a69275b.gi) And if you run the page, this is exactly what you should seeโ€”when we _subtract_ the mouse position from each point before turning it into a color, the entire plane will move with the mouse: ![Moving the complex plane with the mouse](https://storage.googleapis.com/replit/images/1554408698991_86513310aed2338a8dfd986d129abcbe.gi) What a convenient geometric representation! As it turns out, you can _multiply_ complex numbers too. Amazingly, this also has a simple geometric interpretation: _rotation_ and _scaling_: ![Multiplying points on the Complex Plane](https://storage.googleapis.com/replit/images/1554408735283_46d80839958d9124cc447011b9324908.gi) Try changing this line: `point = point.sub(constant)` to this: `point = point.div(constant)` This will _divide_ each point on the plane by `constant` before turning it into a color. And if you run the page, you should see the plane rotate and scale with the mouse: ![Rotating and scaling the complex plane](https://storage.googleapis.com/replit/images/1554408766533_9e05ae48eca48152992e059b836bb474.gi) This way of thinking about complex numbersโ€”where add/subtract moves a point, and multiply/divide rotates and scales itโ€”is _incredibly_ powerful. Let's make one more change, to show off an important function called `math.abs`. The **Absolute Value** of a complex number is its "length"โ€”the distance from that point on the complex plane to 0+0i. Try changing your `pointToColor` function like so: ```javascript // constant + the rest of your script... // Turn a point on the complex plane into a color function pointToColor(point) { point = point.div(constant) var red = point.re*255 var green = point.im*255 var blue = math.abs(point)*255 return `rgb(${red}, ${green}, ${blue})` } // pixelToPoint + the rest of your script... ``` Now we have a `blue` value for our color, which shows `math.abs(point)`. If you run the page, it should look like this: ![Moving colors on the complex plane](https://storage.googleapis.com/replit/images/1554408807050_58ef5f105aee612c70997455d7bb8cac.gi) Think about the colors you seeโ€”why _these_ colors? Why is the blue in a circle? Why is one corner white? Your script should now look like [this](https://repl.it/@polytrope/julia-fractals-drawing-plane): ```html <script> // The HTML elements we are using var header = document.querySelector('h2') var canvas = document.querySelector('canvas') var ctx = canvas.getContext('2d') // The size of our canvas var width = 200 var height = 200 // Set the size of our canvas canvas.width = width canvas.height = height // The XY coordinates of the mouse over the canvas var mouseX = 0 var mouseY = 0 // The point we use for C in our Julia Set equation var constant = math.complex(0.28, 0.01) // Turn a point on the complex plane into a color function pointToColor(point) { point = point.sub(constant) var red = point.re*255 var green = point.im*255 var blue = math.abs(point)*255 return `rgb(${red}, ${green}, ${blue})` } // Turn XY pixel coordinates into a point on the complex plane function pixelToPoint(x, y) { // Map percentage of total width/height to a value from -1 to +1 var zx = (x/width)*2-1 var zy = 1-(y/height)*2 // Create a complex number based on our new XY values return math.complex(zx, zy) } // Draw a single pixel on our canvas function drawPixel(x, y, color) { ctx.fillStyle = color ctx.fillRect(x, y, 1, 1) } // Redraw our canvas function draw() { // Loop over every column of pixels for (var y = 0; y < height; y++) { // Loop over every row of pixels for (var x = 0; x < width; x++) { // Turn this pixel into a point in the complex plane var point = pixelToPoint(x, y) // Turn that point into a color var color = pointToColor(point) // Draw over this pixel with that color drawPixel(x, y, color) } } } // Update the elements that need to change function update() { header.innerHTML = constant.toString() draw() } // What to do when the mouse moves over the canvas function move(event) { // Get the mouse's XY coordinates on canvas mouseX = event.clientX-canvas.offsetLeft mouseY = event.clientY-canvas.offsetTop // Turn mouse coordinates into a point on the complex plane constant = pixelToPoint(mouseX, mouseY) // Round that point off to the nearest 0.01 constant.re = math.round(constant.re*100)/100 constant.im = math.round(constant.im*100)/100 // Update everything! update() } // Trigger move every time the mouse moves over canvas canvas.addEventListener('pointermove', move) // Update everything! update() </script> ``` ## The Julia Set Now for the main eventโ€”rendering a fractal. We're going to render the Julia Set. This fractal is defined by a very simple function: ![The equation that defines the Julia Set](https://storage.googleapis.com/replit/images/1554408840000_0c2499280c0116ec8a46201ca570e0ed.pn) We need to use this equation to generate a color for each point on the complex plane. However, this function doesn't give you a color directlyโ€”it defines a _process_ that you can apply to each point: 1. _Multiply_ that point by itself 2. _Add_ your `constant` value C 3. Repeat 1. Multiply this _new_ point by itself 2. Add your `constant` value C 3. Repeat 1. Multiply _this_ new point by itself 2. Add your `constant` value C 3. Repeatโ€ฆ You can apply this process _infinitely_ for any point. For most points, the number will just keep getting bigger and bigger and bigger. When this happens, we say the number **Escapes**. Any point with an absolute value of at least 2 will _always_ get bigger and bigger forever. So if `math.abs(z) >= 2`, we _know_ that `z` escapes. But for some numbers in that little circle around the originโ€”where `math.abs(z) < 2`โ€”something peculiar happens. Each time we apply this process, the point will moveโ€ฆ but it will never _escape_. It may just bounce around _forever_, rotating and moving around the origin without ever "escaping" it. To get a color from each point, we apply this process a bunch of times to see if that point escapes. We stop when `math.abs(z) > 2`, or when we hit some maximum number of iterations (we'll set a max of 64). Add a new value called `maxIterations` just below `constant`, and a new function called `julia` just after that: ```javascript // constant + the rest of your script... // The maximum number of times we iterate a point to see if it escapes var maxIterations = 64 // Apply the Julia Set formula to see if point z "escapes" function julia(z, i = 0) { // Apply the Julia Set formula: z*z+constant z = z.mul(z) z = z.add(constant) // Has our point escaped, or hit the iteration limit? if (math.abs(z) > 2 || i == maxIterations) // If so, return number of iterations return i else // If not, iterate again! return julia(z, i+1) } // pointToColor + the rest of your script... ``` Now we have a function `julia` which tells us how many iterations of the Julia Set equation it takes for a given point to escape. We need to turn that number of iterations into a color. We'll use a simple grayscale color scheme, where black is 0 iterations and white is our `maxIterations` value. Change your `pointToColor` function like so: ```javascript // julia + the rest of your script... // Turn a point on the complex plane into a color function pointToColor(point) { // How many iterations on this point before it escapes? var iterations = julia(point) // What percentage of our limit is that? var percentage = iterations/maxIterations var red = percentage*255 var green = percentage*255 var blue = percentage*255 // Create a color from that percentage return `rgb(${red}, ${green}, ${blue})` } // pixelToPoint + the rest of your script... ``` Now if your run your page, you should see a grayscale Julia fractal that morphs as your move the mouse: ![A grayscale render of the Julia Set](https://storage.googleapis.com/replit/images/1554408869865_d5d0e292cd1a4c157492aa8f1853cc6f.gi) Your whole script should now look like [this](https://repl.it/@polytrope/julia-fractals-julia-set): ```html <script> // The HTML elements we are using var header = document.querySelector('h2') var canvas = document.querySelector('canvas') var ctx = canvas.getContext('2d') // The size of our canvas var width = 200 var height = 200 // Set the size of our canvas canvas.width = width canvas.height = height // The XY coordinates of the mouse over the canvas var mouseX = 0 var mouseY = 0 // The point we use for C in our Julia Set equation var constant = math.complex(0.28, 0.01) // The maximum number of times we iterate a point to see if it escapes var maxIterations = 64 // Apply the Julia Set formula to see if point z "escapes" function julia(z, i = 0) { // Apply the Julia Set formula: z*z+constant z = z.mul(z) z = z.add(constant) // Has our point escaped, or hit the iteration limit? if (math.abs(z) > 2 || i == maxIterations) // If so, return number of iterations return i else // If not, iterate again! return julia(z, i+1) } // Turn a point on the complex plane into a color function pointToColor(point) { // How many iterations on this point before it escapes? var iterations = julia(point) // What percentage of our limit is that? var percentage = iterations/maxIterations var red = percentage*255 var green = percentage*255 var blue = percentage*255 // Create a color from that percentage return `rgb(${red}, ${green}, ${blue})` } // Turn XY pixel coordinates into a point on the complex plane function pixelToPoint(x, y) { // Map percentage of total width/height to a value from -1 to +1 var zx = (x/width)*2-1 var zy = 1-(y/height)*2 // Create a complex number based on our new XY values return math.complex(zx, zy) } // Draw a single pixel on our canvas function drawPixel(x, y, color) { ctx.fillStyle = color ctx.fillRect(x, y, 1, 1) } // Redraw our canvas function draw() { // Loop over every column of pixels for (var y = 0; y < height; y++) { // Loop over every row of pixels for (var x = 0; x < width; x++) { // Turn this pixel into a point in the complex plane var point = pixelToPoint(x, y) // Turn that point into a color var color = pointToColor(point) // Draw over this pixel with that color drawPixel(x, y, color) } } } // Update the elements that need to change function update() { header.innerHTML = constant.toString() draw() } // What to do when the mouse moves over the canvas function move(event) { // Get the mouse's XY coordinates on canvas mouseX = event.clientX-canvas.offsetLeft mouseY = event.clientY-canvas.offsetTop // Turn mouse coordinates into a point on the complex plane constant = pixelToPoint(mouseX, mouseY) // Round that point off to the nearest 0.01 constant.re = math.round(constant.re*100)/100 constant.im = math.round(constant.im*100)/100 // Update everything! update() } // Trigger move every time the mouse moves over canvas canvas.addEventListener('pointermove', move) // Update everything! update() </script> ``` ## Pan Now we have a fractal, which is pretty cool. But what if we want to move around _within_ our fractal? Let's start with a "pan" operation, that moves the image up/down/left/right as we click. We'll set this up so that the first click sets our `constant` value, and every click after that pans the image. Add two new values for `clicked` and `pan` at the top, just below `maxIterations` and above `julia`: ```javascript // maxIterations + the rest of your script... // Whether we have clicked yet var clicked = false // How much we move the image var pan = math.complex(0, 0) // julia + the rest of your script... ``` Now add a new function called `click`, just after `update`: ```javascript // update + the rest of your script... function click(event) { // Ignore the first click if (!clicked) { clicked = true return } // Get the mouse's XY coordinates on canvas mouseX = event.clientX-canvas.offsetLeft mouseY = event.clientY-canvas.offsetTop // Turn mouse coordinates into a point on the complex plane pan = pixelToPoint(mouseX, mouseY) // Update everything! update() } // the rest of your script... ``` Notice that if `clicked` is false, `click` will do nothingโ€”except set `clicked` to true. Similarly, we need to change `move` so that it will do nothing if `clicked` is _true_: ```javascript // click + the rest of your script... // What to do when the mouse moves over the canvas function move(event) { // Don't move after first click if (clicked) { return } // Get the mouse's XY coordinates on canvas mouseX = event.clientX-canvas.offsetLeft mouseY = event.clientY-canvas.offsetTop // Turn mouse coordinates into a point on the complex plane constant = pixelToPoint(mouseX, mouseY) // Round that point off to the nearest 0.01 constant.re = math.round(constant.re*100)/100 constant.im = math.round(constant.im*100)/100 // Update everything! update() } ``` We also need to add a listener to trigger `click` whenever we click on the canvas. Let's put it just after our `move` function: ```javascript // move + the rest of your script... // Trigger click every time the canvas is clicked canvas.addEventListener('click', click) // the rest of your script... ``` Now when we click on the canvas, it will fix our `constant` valueโ€”and every click after that will change the `pan` value. Finally, we need to actually _use_ that `pan` value somewhere. We want `pan` to change which pixel maps to each pointโ€”so we need to change our `pixelToPoint` function so that our `pan` value is _added_ to each point: ```javascript // pointToColor + the rest of your script... // Turn XY pixel coordinates into a point on the complex plane function pixelToPoint(x, y) { // Map percentage of total width/height to a value from -1 to +1 var zx = (x/width)*2-1 var zy = 1-(y/height)*2 // Create a complex number based on our new XY values var z = math.complex(zx, zy) // Pan the camera z = z.add(pan) return z } // drawPixel + the rest of your script... ``` Now if you run the page, you should be able to set the `constant` value and pan around the image by clicking! ![Panning around the rendered fractal](https://storage.googleapis.com/replit/images/1554408921490_a3b850be4b61936cdc93c15ab4cd067a.gi) Your full script should look like [this](https://repl.it/@polytrope/julia-fractals-click-pan): ```html <script> // The HTML elements we are using var header = document.querySelector('h2') var canvas = document.querySelector('canvas') var ctx = canvas.getContext('2d') // The size of our canvas var width = 200 var height = 200 // Set the size of our canvas canvas.width = width canvas.height = height // The XY coordinates of the mouse over the canvas var mouseX = 0 var mouseY = 0 // The point we use for C in our Julia Set equation var constant = math.complex(0.28, 0.01) // The maximum number of times we iterate a point to see if it escapes var maxIterations = 64 // Whether we have clicked yet var clicked = false // How much we move the image var pan = math.complex(0, 0) // Apply the Julia Set formula to see if point z "escapes" function julia(z, i = 0) { // Apply the Julia Set formula: z*z+constant z = z.mul(z) z = z.add(constant) // Has our point escaped, or hit the iteration limit? if (math.abs(z) > 2 || i == maxIterations) // If so, return number of iterations return i else // If not, iterate again! return julia(z, i+1) } // Turn a point on the complex plane into a color function pointToColor(point) { // How many iterations on this point before it escapes? var iterations = julia(point) // What percentage of our limit is that? var percentage = iterations/maxIterations var red = percentage*255 var green = percentage*255 var blue = percentage*255 // Create a color from that percentage return `rgb(${red}, ${green}, ${blue})` } // Turn XY pixel coordinates into a point on the complex plane function pixelToPoint(x, y) { // Map percentage of total width/height to a value from -1 to +1 var zx = (x/width)*2-1 var zy = 1-(y/height)*2 // Create a complex number based on our new XY values var z = math.complex(zx, zy) // Pan the camera z = z.add(pan) return z } // Draw a single pixel on our canvas function drawPixel(x, y, color) { ctx.fillStyle = color ctx.fillRect(x, y, 1, 1) } // Redraw our canvas function draw() { // Loop over every column of pixels for (var y = 0; y < height; y++) { // Loop over every row of pixels for (var x = 0; x < width; x++) { // Turn this pixel into a point in the complex plane var point = pixelToPoint(x, y) // Turn that point into a color var color = pointToColor(point) // Draw over this pixel with that color drawPixel(x, y, color) } } } // Update the elements that need to change function update() { header.innerHTML = constant.toString() draw() } function click(event) { // Ignore the first click if (!clicked) { clicked = true return } // Get the mouse's XY coordinates on canvas mouseX = event.clientX-canvas.offsetLeft mouseY = event.clientY-canvas.offsetTop // Turn mouse coordinates into a point on the complex plane pan = pixelToPoint(mouseX, mouseY) // Update everything! update() } // What to do when the mouse moves over the canvas function move(event) { // Don't move after first click if (clicked) { return } // Get the mouse's XY coordinates on canvas mouseX = event.clientX-canvas.offsetLeft mouseY = event.clientY-canvas.offsetTop // Turn mouse coordinates into a point on the complex plane constant = pixelToPoint(mouseX, mouseY) // Round that point off to the nearest 0.01 constant.re = math.round(constant.re*100)/100 constant.im = math.round(constant.im*100)/100 // Update everything! update() } // Trigger click every time the canvas is clicked canvas.addEventListener('click', click) // Trigger move every time the mouse moves over canvas canvas.addEventListener('pointermove', move) // Update everything! update() </script> ``` ## Zoom Almost done hereโ€ฆ all we need now is a zoom feature. Add a new variable for `zoom`, just after `pan`: ```javascript // pan + the rest of your script... // How much we zoom the image var zoom = 1 // julia + the rest of your script... ``` Let's make it so every click _doubles_ the zoom value. We just need to add one new line to our `click` function for `zoom *= 2`: ```javascript // update + the rest of your script... // What to do when the mouse clicks the canvas function click(event) { // Ignore the first click if (!clicked) { clicked = true return } // Get the mouse's XY coordinates on canvas mouseX = event.clientX-canvas.offsetLeft mouseY = event.clientY-canvas.offsetTop // Turn mouse coordinates into a point on the complex plane pan = pixelToPoint(mouseX, mouseY) // Zoom in twice as far zoom *= 2 // Update everything! update() } // move + the rest of your script... ``` Now we need to change our `pixelToPoint` function to use that `zoom` value. Like `pan`, this is pretty simpleโ€”we just need to _divide_ each point by `zoom`, just before we add `pan`: ```javascript // pointToColor + the rest of your script... // Turn XY pixel coordinates into a point on the complex plane function pixelToPoint(x, y) { // Map percentage of total width/height to a value from -1 to +1 var zx = (x/width)*2-1 var zy = 1-(y/height)*2 // Create a complex number based on our new XY values var z = math.complex(zx, zy) // Zoom the camera z = z.div(zoom) // Pan the camera z = z.add(pan) return z } // drawPixel + the rest of your script... ``` Finally, let's make one last change to our `update` function so that it will tell us how far we have zoomed in: ```javascript // draw + the rest of your script... // Update the elements that need to change function update() { header.innerHTML = constant.toString() + " at " + zoom + "X" draw() } // click + the rest of your script... ``` Now if you run the page, you should be able to zoom in on the image with every click! ![Zooming in on the Julia Set](https://storage.googleapis.com/replit/images/1554409105068_8d1427fc76f2fce738f17a9328036a71.gi) Your final script should look like [this](https://repl.it/@polytrope/julia-fractals-click-zoom): ```html <script> // The HTML elements we are using var header = document.querySelector('h2') var canvas = document.querySelector('canvas') var ctx = canvas.getContext('2d') // The size of our canvas var width = 200 var height = 200 // Set the size of our canvas canvas.width = width canvas.height = height // The XY coordinates of the mouse over the canvas var mouseX = 0 var mouseY = 0 // The point we use for C in our Julia Set equation var constant = math.complex(0.28, 0.01) // The maximum number of times we iterate a point to see if it escapes var maxIterations = 64 // Whether we have clicked yet var clicked = false // How much we move the image var pan = math.complex(0, 0) // How much we zoom the image var zoom = 1 // Apply the Julia Set formula to see if point z "escapes" function julia(z, i = 0) { // Apply the Julia Set formula: z*z+constant z = z.mul(z) z = z.add(constant) // Has our point escaped, or hit the iteration limit? if (math.abs(z) > 2 || i == maxIterations) // If so, return number of iterations return i else // If not, iterate again! return julia(z, i+1) } // Turn a point on the complex plane into a color function pointToColor(point) { // How many iterations on this point before it escapes? var iterations = julia(point) // What percentage of our limit is that? var percentage = iterations/maxIterations var red = percentage*255 var green = percentage*255 var blue = percentage*255 // Create a color from that percentage return `rgb(${red}, ${green}, ${blue})` } // Turn XY pixel coordinates into a point on the complex plane function pixelToPoint(x, y) { // Map percentage of total width/height to a value from -1 to +1 var zx = (x/width)*2-1 var zy = 1-(y/height)*2 // Create a complex number based on our new XY values var z = math.complex(zx, zy) // Zoom the camera z = z.div(zoom) // Pan the camera z = z.add(pan) return z } // Draw a single pixel on our canvas function drawPixel(x, y, color) { ctx.fillStyle = color ctx.fillRect(x, y, 1, 1) } // Redraw our canvas function draw() { // Loop over every column of pixels for (var y = 0; y < height; y++) { // Loop over every row of pixels for (var x = 0; x < width; x++) { // Turn this pixel into a point in the complex plane var point = pixelToPoint(x, y) // Turn that point into a color var color = pointToColor(point) // Draw over this pixel with that color drawPixel(x, y, color) } } } // Update the elements that need to change function update() { header.innerHTML = constant.toString() + " at " + zoom + "X" draw() } // What to do when the mouse clicks the canvas function click(event) { // Ignore the first click if (!clicked) { clicked = true return } // Get the mouse's XY coordinates on canvas mouseX = event.clientX-canvas.offsetLeft mouseY = event.clientY-canvas.offsetTop // Turn mouse coordinates into a point on the complex plane pan = pixelToPoint(mouseX, mouseY) // Zoom in twice as far zoom *= 2 // Update everything! update() } // What to do when the mouse moves over the canvas function move(event) { // Don't move after first click if (clicked) { return } // Get the mouse's XY coordinates on canvas mouseX = event.clientX-canvas.offsetLeft mouseY = event.clientY-canvas.offsetTop // Turn mouse coordinates into a point on the complex plane constant = pixelToPoint(mouseX, mouseY) // Round that point off to the nearest 0.01 constant.re = math.round(constant.re*100)/100 constant.im = math.round(constant.im*100)/100 // Update everything! update() } // Trigger click every time the canvas is clicked canvas.addEventListener('click', click) // Trigger move every time the mouse moves over canvas canvas.addEventListener('pointermove', move) // Update everything! update() </script> ``` ## Epilogue There are all kinds of fractals. You can make [fractal trees](https://hackclub.com/workshops/tree_machine): ![An animated fractal tree](https://storage.googleapis.com/replit/images/1554409134230_31b982c99a6ec62437824c0773d690e0.gi) Or how about some [3D fractals](http://www.mandelbulb.com/): ![The Mandelbulb 3D fractal](https://storage.googleapis.com/replit/images/1554409160676_105015d72a68bfef7e23ea14627fe503.jpe) You can even grow [broccoli with fractals](https://en.wikipedia.org/wiki/Romanesco_broccoli) (yes this is real broccoli that you can buy at some supermarkets): ![An image of romanesco broccoli](https://storage.googleapis.com/replit/images/1554409200197_7428d9ef5c9ccc288dd66ffc3f8f0666.jpe) But fractals are just the beginning of what you can do with complex numbers. Complex numbers are _essential_ to everything from quantum physics to guitar amplifiers. Pretty remarkable for such a simple idea. Want to learn more stuff like this? I recommend checking out [3Blue1Brown](https://www.youtube.com/watch?v=QJYmyhnaaek). ### Sources * Thanks to Simpsons Contributor on Wikimedia for the [fractal zoom gif](https://en.wikipedia.org/wiki/File:Mandelbrot_sequence_new.gif) * Thanks to Rafael Ruggiero for the [fractal tree gif](https://commons.wikimedia.org/wiki/File:Fractal_tree.gif) * Thanks to the mandelbulb.com team for the [mandelbulb image](http://www.mandelbulb.com/3d-fractal-art-mandelmorphs/) * Thanks to Jon Sullivan on Wikimedia for his [image of romanesco broccoli](https://commons.wikimedia.org/wiki/File:Fractal_Broccoli.jpg)
4
posted by polytrope (19) 2 months ago
โ–ฒ
15
6 Essential Python Libraries for Python Programming
Python is a high-level, general-purpose programming language that has become one of the leading names in the programming community. It ranges in the ability from developing simplistic applications to carrying out complex, mathematical calculations with an equal level of ease. Being one of the leading programming languages means that there is no scarcity of [great frameworks](https://hackr.io/blog/19-python-frameworks) and libraries available to toy with. A programming language library is simply a set of modules and functions that eases some specific operations using the programming language. So, here are 6 essential Python libraries for Python programming that every Python developer or aspirant must know about: # 1. **Keras** _Type_ โ€“ Neural Networks Library _Initial Release_ โ€“ March 2015 Written in Python, Keras is an open-source neural-network library. Designed especially for enabling fast experimentation with deep neural networks, Keras prioritizes for being user-friendly, extensible, and modular. In addition to providing an easier mechanism for expressing neural networks, Keras also offers some of the best features for compiling models, processing datasets, and visualizing graphs. On the backend, Keras makes use of either Theano or TensorFlow. Due to the fact that Keras creates a computation graph by using backend infrastructure and then uses it to perform operations, it is slower than other machine learning libraries. Nonetheless, all models in Keras are portable. _<span style="text-decoration:underline;">Highlights</span>_: * Easy to debug and explore as it is completely written in Python * Features several implementations of the commonly used neural network building blocks such as activation functions, layers, objectives, and optimizers * Incredible expressiveness and flexibility makes it ideal for innovative research * Offers several pre-processed datasets and pre-trained models like Inception, MNIST, ResNet, SqueezeNet, and VGG * Provides support for almost all neural networks models, including convolutional, embedding, fully connected, pooling, and recurrent. Moreover, these models can be combined to develop even more complex models * Runs smoothly on both CPU as well as GPU _<span style="text-decoration:underline;">Applications</span>_: * Already used by Netflix, Square, Uber, and Yelp * For deep learning research. Adopted by researchers at CERN and NASA * Popular among startups developing products based on deep learning # 2. **NumPy** _Type_ โ€“ Technical Computing Library _Initial Release_ โ€“ 1995 (As Numeric) 2006 (As NumPy) NumPy was created by Travis Oliphant in 2005 by incorporating features of the rival Numarray library into the Numeric library and applying extensive modifications. The free and open-source library has several contributors from all over the globe. One of the most popular machine learning libraries in Python, TensorFlow and several other libraries make use of the NumPy Python library internally in order to perform multiple operations on tensors. _<span style="text-decoration:underline;">Highlights</span>_: * Active community support * Completely free and open source * Complex matrix operations, such as [matrix multiplication](https://hackr.io/blog/numpy-matrix-multiplication) * Interactive and super easy to use * Eases complex mathematical implementations * Easy to code with digestible concepts _<span style="text-decoration:underline;">Applications</span>_: * For carrying out complex mathematical computations * For expressing images, sound waves, and other forms of binary raw streams as an array of real numbers in N-dimensional * For machine learning projects # 3. **Pillow** _Type_ โ€“ Image Processing and Manipulation Library _Initial Release_ โ€“ 1995 (As Python Imaging Library or PIL) 2011 (As Pillow) Pillow is a Python library that is almost as old as the programming language for which it was developed. In reality, Pillow is a fork for the PIL (Python Imaging Library). The free to use Python library is a must-have for opening, manipulating, and saving a diverse range of image files. Pillow has been adopted as the replacement for the original PIL in several Linux distributions, most notably Debian and Ubuntu. Nonetheless, it is available for MacOS and Windows too. _<span style="text-decoration:underline;">Highlights</span>_: * Adds text to images * Image enhancing and filtering, including blurring, brightness adjustment, contouring, and sharpening * Masking and transparency handling * Per-pixel manipulations * Provides support for a galore of image file formats, including BMP, GIF, JPEG, PNG, PPM, and TIFF. Provides support for creating new file decoders in order to expand the library of file formats accessible _<span style="text-decoration:underline;">Applications</span>_: * For image manipulation and processing # 4. **PYGLET** _Type_ โ€“ Game Development Library _Initial Release_ โ€“ April 2015 A multi-platform windowing and multimedia library for Python, PYGLET is a popular name when it comes to game development using Python. In addition to games, the library is developed for crafting visually rich applications. In addition to supporting windowing, PYGLET provides support for loading images and videos, playing sounds and music, OpenGL graphics, and user interface event handling. _<span style="text-decoration:underline;">Highlights</span>_: * Leverage multiple windows and multi-monitor desktops * Load images, sound, and video in almost all formats * No external dependencies and installation requirements * Provided under the BSD open-source license, therefore free to be used for personal as well as commercial uses * Provides support for both Python 2 and Python 3 _<span style="text-decoration:underline;">Applications</span>_: * For developing visually rich applications * For game development # 5. **Requests** _Type_ โ€“ HTTP Library _Initial Release_ โ€“ February 2011 A Python HTTP library, Requests is aimed at making HTTP requests simpler and more human-friendly. Developed by Kenneth Reitz and a few other contributors, Requests allows sending HTTP/1.1 requests without requiring human intervention. From Nike and Spotify to Amazon and Microsoft, dozens of big organizations make use of Requests internally to better deal with the HTTP. Written completely in Python, Requests is available as a free open-source library under the Apache2 License. _<span style="text-decoration:underline;">Highlights</span>_: * Automatic content decoding * Basic/digest authentication * Browser-style SSL verification * Chunked requests and connection timeouts * Provides support for .netrc and HTTP(S) proxy * Sessions with cookie persistence * Unicode response bodies _<span style="text-decoration:underline;">Applications</span>_: * Allows sending HTTP/1.1 requests using Python and add content such as headers, form data, and multipart files * For automatically adding query strings to URLs * For automatically form-encode the POST data # 6. **TensorFlow** _Type_ โ€“ Machine Learning Library _Initial Release_ โ€“ November 2015 TensorFlow is a free and open-source Python library meant to accomplish a range of dataflow and differentiable programming tasks. Although a symbolic math library, TensorFlow is one of the most widely used Python machine learning libraries. Developed by Google Brain for internal use, the library is used for both commercial and research purposes by the tech mogul. [Tensors](https://en.wikipedia.org/wiki/Tensor) are N-dimensional matrices that represent data. The TensorFlow library allows writing new algorithms involving a grand number of tensor operations. Because neural networks can be expressed as computational graphs, they can be easily implemented using the TensorFlow library as a series of operations on tensors. _<span style="text-decoration:underline;">Highlights</span>_: * Allows visualizing each and every part of the graph * Completely free and open source * Easily trainable on CPU and GPU for distributed computing * Humongous community support * Offers flexibility in its operability. Parts that are required the most can be made standalone * Supports training multiple neural networks and multiple GPUs to make efficient models on large-scale systems * Uses techniques to the likes of XLA for hastening linear algebra operations _<span style="text-decoration:underline;">Applications</span>_: * For machine learning projects * For neural networks projects * In automated image-captioning software like DeepDream * Machine learning in Google products, such as Google Photos and Google Voice Search That finishes the list of the 6 essential Python libraries for Python programming. Which libraries should/shouldn't have made it to the list? Let us know in your comments. Check out some of the [best Python tutorials](https://hackr.io/tutorials/learn-python) now!
0
posted by VijaySingh1 (20) 2 months ago
โ–ฒ
83
Build a WhatsApp bot in 30 minutes ๐Ÿ•
A few months ago, I'd started making chatbots on [Telegram](https://t.me) - I'd seen APIs for WhatsApp but they were unoffical and there was a chance for getting your number blocked ๐Ÿ“ฑ โŒ A while ago, I saw that [Twilio](https://twilio.com) had an official WhatsApp API. 30 minutes later, I made a [Wikipedia bot on WhatsApp](https://wikibot.4ty2.fun) ๐Ÿ‘‡ ![](https://wikibot.surge.sh/Untitled-b9da3f92-94c0-4f97-8afb-787110d8a9d3.png) This is a tutorial to help you make a something like this, your own chatbots on WhatsApp - these bots are immediately available to 2 billion users, and there are so many things possible ๐ŸŽ“ I can't wait to see what you make! Now, let's get started ๐Ÿƒโ€โ™‚๏ธ ## ๐Ÿ”‘ Accounts and Keys First, Sign up for [Twilio](https://www.twilio.com/try-twilio) - it's free and you won't need a credit card ๐Ÿ’ณ ![](https://wikibot.surge.sh/screely-1535885763017-fc654067-9557-4bf7-98b5-4337911ff4ba.png) Once you're done verifying your phone number, select Procuts > Programmable SMS and then continue to name your project. ![](https://wikibot.surge.sh/screely-1535885937977-c5a924ec-8cc3-4430-9345-9b5e1dc74ef3.png) Feel free to skip steps for adding teammates - you won't need that for now. You must now take note of some authentication keys you'll need for building the WhatsApp bot ๐Ÿ‘‡ ![](https://wikibot.surge.sh/screely-1535886250966-f68b6cfb-c104-4adf-80e7-4e3f9bd15b5b.png) The final step - setup your WhatsApp Sandbox [here](https://www.twilio.com/console/sms/whatsapp/sandbox) - choose any number, and join your sandbox following instructions on the page. ![](https://wikibot.surge.sh/screely-1535886798623-1dac1ba9-c362-4e49-87ab-7bbb6138e8c7.png) Aaaaaand you're done with credential setup! Don't worry, that was the toughest part of this tutorial ๐Ÿ˜› ## ๐Ÿš€ Getting Started So that we don't spend too much time on setup, I've created an environment (with repl.it!) you can use within your browser. Head over [here](https://repl.it/@jajoosam/wikibot-start), and wait for a couple of seconds to fork it. Next, open up `server.js` and put in your Account SID and Auth Token, on lines `7` and `8` ```javascript const accountSid ="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; //Account SID const authToken ="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; // Auth Token ``` You can see, this environment already has dependencies installed, and an `express` server set up. We still need to give Twilio a URL to send incoming messages to, though ๐Ÿ”— Let's go back to the [WhatsApp Sandbox](https://www.twilio.com/console/sms/whatsapp/sandbox), and put in a webhook URL for incoming messages. ![](https://wikibot.surge.sh/Untitled-3ed5263b-c6d8-492b-ba08-b4644ab502cf.png) This URL must be what you see on the preview panel of your [repl.it](http://repl.it) project + `/incoming` ![](https://wikibot.surge.sh/Untitled-1779b21f-9100-4942-b732-320dc48c5f76.png) We can now finally read messages that are sent to the bot. Add a simple `console.log()` in your webhook handler ๐Ÿ‘‡ ```javascript app.post('/incoming', (req, res) => { console.log(req.body) }); ``` When you send a message to your bot, you should be able to see something like this in your repl console ๐Ÿ‘จโ€๐Ÿ’ป ![](https://wikibot.surge.sh/Untitled-163eb09e-e6ab-4910-badb-d8aa0aa789f7.png) Building an echo bot would look something like this, using `twiml` to write a message ๐Ÿ‘‡ ```javascript app.post('/incoming', (req, res) => { const twiml = new MessagingResponse(); twiml.message(req.body.Body); res.writeHead(200, {'Content-Type': 'text/xml'}); res.end(twiml.toString()); }); ``` But, since we're actually trying to build a useful bot - let's use informative APIs! ## ๐ŸŒ Fetching Information DuckDuckGo has an amazing, free instant answer API. It takes in a query and returns back a summary from WikiPedia and more. A few examples ๐Ÿ‘‰ [WikiPedia](https://api.duckduckgo.com/?skip_disambig=1&format=json&pretty=1&q=WikiPedia), [Macbook Air](https://api.duckduckgo.com/?skip_disambig=1&format=json&pretty=1&q=MacBook%20Air), [Twilio](https://api.duckduckgo.com/?skip_disambig=1&format=json&pretty=1&q=Twilio) I spent some time creating a decent parser which usually returns information from this API. Try pasting this code in your [repl.it](http://repl.it) project, and your [console](https://dsh.re/f7477c) should have stuff about Trump in it ๐Ÿ˜› ```javascript var base = 'https://api.duckduckgo.com/?skip_disambig=1&format=json&pretty=1&q='; var query = 'Donald Trump'; request(base + query, function (error, response, body) { body = JSON.parse(body) if(body["Abstract"] == ""){ body["Abstract"]= body["RelatedTopics"][0]["Text"] } var msg = body["Heading"]+"\n\n"+body["Abstract"]; console.log(msg) }); ``` Pretty straight forward, right? ๐Ÿ˜„ ## ๐Ÿ› ๏ธ Putting it all together To make our actual bot, all we need to do is get the query from our request - which we can get as `req.body.Body` - and use `twmil` to send across the data we collected in `msg` ```javascript app.post('/incoming', (req, res) => { const twiml = new MessagingResponse(); var base = 'https://api.duckduckgo.com/?skip_disambig=1&format=json&pretty=1&q='; var query = req.body.Body; request(base + query, function (error, response, body) { body = JSON.parse(body) if(body["Abstract"] == ""){ body["Abstract"]= body["RelatedTopics"][0]["Text"] } var msg = twiml.message(body["Heading"]+"\n\n"+body["Abstract"]); res.writeHead(200, {'Content-Type': 'text/xml'}); res.end(twiml.toString()); }); }); ``` You now have a fully functionaing WhatsApp bot! Send anything you want to know about your bot ๐Ÿค– and you should see it respond super fast ๐Ÿ’ฌ โšก Adding welcome messages and a little formatting is quite simple, look at the final [repl](https://repl.it/@jajoosam/wikibot) to see how I did it ๐Ÿ‘จโ€๐Ÿ’ป ## ๐Ÿ”— Sharing the bot For others to use this bot, they'll need to join your sandbox first - and send a message just like you did earlier ๐Ÿ‘‰ `join <two-words>` You can create links with this text too - For example this link lets you join my bot ๐Ÿ‘‡ ``` https://wa.me/14155238886?text=join ultramarine-tapir ``` `14155238886` is my bot's number, while `ultramarine-tapir` is the sandbox phrase. ## โšก What's next? Now that you know how to build a bot on WhatsApp, try sending notifications to yourself, and building more useful tools! Twilio has loads of [other mediums](https://www.twilio.com/channels) to message through too! All code for my WikiBot is on [Github](https://github.com/jajoosam/wikibot)! I'm a 15 year old maker ๐Ÿ‘จโ€๐Ÿ’ป For more cool things to make and to stay update with my progress, sign up for [my newsletter ๐Ÿ“ง](https://buttondown.email/jajoosam)
14
posted by jajoosam (471) 7 months ago
โ–ฒ
72
Building AI: Neural Networks for beginners ๐Ÿ‘พ
Teaching Machine to recognize Hand-written Numbers! I am excited to share some of my experience studying machine learning with you, guys! I'm not an expert but I'll try to explain it the way I see it myself. I'm going to try to give you some intuition about how Neural Networks work, omitting most of the math to make it more understandable but, for the most curious of you, I'll leave the links to complete explanations/courses in the end. ![Predicted class_ 4](https://storage.googleapis.com/replit/images/1541033154259_e80e9609e421c89077d1b92aa1d33f36.pn) In 29 mins, you'll be able to configure an algorithm that's going to recognize the written digits in python :) ## **๐Ÿง  What is a Neural Network?** Imagine Neural Network as an old wise wizard who knows everything and can predict your future by just looking at you. ![magicbox](https://storage.googleapis.com/replit/images/1541033176006_a6af80c5d6034944a58c1fc595834691.pn) It turns out that he manages to do so in a very non-magical way: 1. Before you visited him, he trained, carefully studied everything about many thousands of people who came to see him before you. 2. He now collects some data about what you look like (your apparent age, the website you found him at, etc). 3. He then compares it to the historical data he has about people that came to see him before. 4. Finally, he gives his best guess on what kind of person you are based on the similarities. ![nn](https://storage.googleapis.com/replit/images/1541033195545_03966c8b28c6a5a6e037593ca2d5fd2f.gi) In very general terms, it is the way many machine learning algorithms work. They are often used to predict things based on the history of similar situations: Amazon suggesting the product you might like to buy, or Gmail suggesting to finish the sentence for you, or a self-driving car learning to drive. ## **๐Ÿ“™ Part 1: Import libraries** Let's start! I have put together a class that is doing all the math behind our algorithm and I'd gladly explain how it works in another tutorial or you could go through my comments and try to figure it out yourself if you know some machine learning. **For now, create a file called `NN.py` and paste this code:** ```python import numpy as np from scipy.optimize import minimize class Neural_Network(object): def configureNN(self, inputSize, hiddenSize, outputSize, W1 = np.array([0]), W2 = np.array([0]), maxiter = 20, lambd = 0.1): #parameters self.inputSize = inputSize self.outputSize = outputSize self.hiddenSize = hiddenSize #initialize weights / random by default if(not W1.any()): self.W1 = np.random.randn( self.hiddenSize, self.inputSize + 1) # weight matrix from input to hidden layer else: self.W1 = W1 if (not W2.any()): self.W2 = np.random.randn( self.outputSize, self.hiddenSize + 1) # weight matrix from hidden to output layerself.W2 = W2 else: self.W2 = W2 # maximum number of iterations for optimization algorithm self.maxiter = maxiter # regularization penalty self.lambd = lambd def addBias(self, X): #adds a column of ones to the beginning of an array if (X.ndim == 1): return np.insert(X, 0, 1) return np.concatenate((np.ones((len(X), 1)), X), axis=1) def delBias(self, X): #deletes a column from the beginning of an array if (X.ndim == 1): return np.delete(X, 0) return np.delete(X, 0, 1) def unroll(self, X1, X2): #unrolls two matrices into one vector return np.concatenate((X1.reshape(X1.size), X2.reshape(X2.size))) def sigmoid(self, s): # activation function return 1 / (1 + np.exp(-s)) def sigmoidPrime(self, s): #derivative of sigmoid return s * (1 - s) def forward(self, X): #forward propagation through our network X = self.addBias(X) self.z = np.dot( X, self.W1.T) # dot product of X (input) and first set of 3x2 weights self.z2 = self.sigmoid(self.z) # activation function self.z2 = self.addBias(self.z2) self.z3 = np.dot( self.z2, self.W2.T) # dot product of hidden layer (z2) and second set of 3x1 weights o = self.sigmoid(self.z3) # final activation function return o def backward(self, X, y, o): # backward propgate through the network self.o_delta = o - y # error in output self.z2_error = self.o_delta.dot( self.W2 ) # z2 error: how much our hidden layer weights contributed to output error self.z2_delta = np.multiply(self.z2_error, self.sigmoidPrime( self.z2)) # applying derivative of sigmoid to z2 error self.z2_delta = self.delBias(self.z2_delta) self.W1_delta += np.dot( np.array([self.z2_delta]).T, np.array([self.addBias(X)])) # adjusting first set (input --> hidden) weights self.W2_delta += np.dot( np.array([self.o_delta]).T, np.array([self.z2])) # adjusting second set (hidden --> output) weights def cost(self, nn_params, X, y): #computing how well the function does. Less = better self.W1_delta = 0 self.W2_delta = 0 m = len(X) o = self.forward(X) J = -1/m * sum(sum(y * np.log(o) + (1 - y) * np.log(1 - o))); #cost function reg = (sum(sum(np.power(self.delBias(self.W1), 2))) + sum( sum(np.power(self.delBias(self.W2), 2)))) * (self.lambd/(2*m)); #regularization: more precise J = J + reg; for i in range(m): o = self.forward(X[i]) self.backward(X[i], y[i], o) self.W1_delta = (1/m) * self.W1_delta + (self.lambd/m) * np.concatenate( (np.zeros((len(self.W1),1)), self.delBias(self.W1)), axis=1) self.W2_delta = (1/m) * self.W2_delta + (self.lambd/m) * np.concatenate( (np.zeros((len(self.W2),1)), self.delBias(self.W2)), axis=1) grad = self.unroll(self.W1_delta, self.W2_delta) return J, grad def train(self, X, y): # using optimization algorithm to find best fit W1, W2 nn_params = self.unroll(self.W1, self.W2) results = minimize(self.cost, x0=nn_params, args=(X, y), options={'disp': True, 'maxiter':self.maxiter}, method="L-BFGS-B", jac=True) self.W1 = np.reshape(results["x"][:self.hiddenSize * (self.inputSize + 1)], (self.hiddenSize, self.inputSize + 1)) self.W2 = np.reshape(results["x"][self.hiddenSize * (self.inputSize + 1):], (self.outputSize, self.hiddenSize + 1)) def saveWeights(self): #sio.savemat('myWeights.mat', mdict={'W1': self.W1, 'W2' : self.W2}) np.savetxt('data/TrainedW1.in', self.W1, delimiter=',') np.savetxt('data/TrainedW2.in', self.W2, delimiter=',') def predict(self, X): o = self.forward(X) i = np.argmax(o) o = o * 0 o[i] = 1 return o def predictClass(self, X): #printing out the number of the class, starting from 1 print("Predicted class out of", self.outputSize,"classes based on trained weights: ") print("Input: \n" + str(X)) print("Class number: " + str(np.argmax( np.round(self.forward(X)) ) + 1)) def accuracy(self, X, y): #printing out the accuracy p = 0 m = len(X) for i in range(m): if (np.all(self.predict(X[i]) == y[i])): p += 1 print('Training Set Accuracy: {:.2f}%'.format(p * 100 / m)) ``` ## **๐Ÿ“Š Part 2: Understanding Data** Cool! Now, much like the wizard who had to study all the other people who visited him before you, we need some data to study too. Before using any optimization algorithms, all the data scientists first try to *understand* the data they want to analyze. **Download files `X.in` (stores info about what people looked like - question) and `y.in`(stores info about what kind of people they were - answer) from [here](https://www.dropbox.com/sh/b04b2xb5j3ncir3/AABlau8wnzWmuyekJ8iVlmPga?dl=0) and put them into folder `data` in your repl.** * X: We are given 5,000 examples of 20x20 pixel pictures of handwritten digits from 0 to 9 (classes 1-10). Each picture's numerical representation is a single vector, which together with all the other examples forms an array `X`. * Y: We also have an array `y`. Each column represents a corresponding example (one picture) from `X`. `y` has 10 rows for classes 1-10 and the value of only the correct class' row is one, the rest is zeros. It looks similar to this: ``` [0, 0, 0, 0, 0, 0, 0, 0, 0, 1] # represents digit 0 (class 10) [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] # represents digit 1 (class 1) ...... [1, 0, 0, 0, 0, 0, 0, 0, 1, 0] # represents digit 9 (class 9) ``` Now, let's plot it! ![TrainingData](https://storage.googleapis.com/replit/images/1541033299328_0478599ab1b7884435cc3bf629b1edc1.pn) In the end, I'd want a function `displayData(displaySize, data, selected, title)`, where * `displaySize` - the numer of images shown in any one column or row of the figure, * `data` - our X array, * `selected` - an index (if displaying only one image) or vector of indices (if displaying multiple images) from X, * `title` - the title of the figure **Create a `plots` folder to save your plots to. Also, if you use repl, create some empty file in the folder so that it doesn't disappear.** **Create a `display.py` file and write the following code in there. Make sure to read the comments:** ```python import matplotlib.pyplot as plt # Displaying the data def displayData( displaySize, data, selected, title ): # setting up our plot fig=plt.figure(figsize=(8, 8)) fig.suptitle(title, fontsize=32) # configuring the number of images to display columns = displaySize rows = displaySize for i in range(columns*rows): # if we want to display multiple images, # then 'selected' is a vector. Check if it is here: if hasattr(selected, "__len__"): img = data[selected[i]] else: img = data[selected] img = img.reshape(20,20).transpose() fig.add_subplot(rows, columns, i+1) plt.imshow(img) # We could also use plt.show(), but repl # can't display it. So let's insted save it # into a file plt.savefig('plots/' + title) return None ``` Great, we are halfway there! ## **๐Ÿ’ช Part 3: Training Neural Network** Now, after we understand what our data looks like, it's time to train on it. Let's make that wizard study! It turns out that the results of the training process of the Neural Networks have to be stored in some values. These values are called *parameters* or *weights* of the Neural Network. If you were to start this project from scratch, your initial weights would be just some random numbers, however, it would take your computer forever to train to do such a complex task as recognizing digits. For this reason, I will provide you with the initial weights that are somewhat closer to the end result. **Download files `W1.in` and `W2.in` from [here](https://www.dropbox.com/sh/b04b2xb5j3ncir3/AABlau8wnzWmuyekJ8iVlmPga?dl=0) and put them into `data` folder.** We are now ready to write code to use our Neural Network library! ![training](https://storage.googleapis.com/replit/images/1541033327074_30bf734c3f1fa129d15be3285be6e453.gi) **Create a `train.py` file and write the following code in there. Make sure to read the comments:** ```python # This code trains the Neural Network. In the end, you end up # with best-fit parameters (weights W1 and W2) for the problem in folder 'data' # and can use them to predict in predict.py import numpy as np import display from NN import Neural_Network NN = Neural_Network() # Loading data X = np.loadtxt("data/X.in", comments="#", delimiter=",", unpack=False) y = np.loadtxt("data/y.in", comments="#", delimiter=",", unpack=False) W1 = np.loadtxt("data/W1.in", comments="#", delimiter=",", unpack=False) W2 = np.loadtxt("data/W2.in", comments="#", delimiter=",", unpack=False) # Display inputs sel = np.random.permutation(len(X)); sel = sel[0:100]; display.displayData(5, X, sel, 'TrainingData'); # Configuring settings of Neural Network: # # inputSize, hiddenSize, outputSize = number of elements # in input, hidden, and output layers # (optional) W1, W2 = random by default # (optional) maxiter = number of iterations you allow the # optimization algorithm. # By default, set to 20 # (optional) lambd = regularization penalty. By # default, set to 0.1 # NN.configureNN(400, 25, 10, W1 = W1, W2 = W2) # Training Neural Network on our data # This step takes 12 mins in Repl.it or 20 sec on your # computer NN.train(X, y) # Saving Weights in the file NN.saveWeights() # Checking the accuracy of Neural Network sel = np.random.permutation(5000)[1:1000] NN.accuracy(X[sel], y[sel]) ``` **Now, you have to run this code either from:** * **Repl.it** - but you would need to move code from `train.py` into `main.py`. Don't delete `train.py` just yet. It would also take approximately 12 minutes to compute. You can watch [this](https://www.youtube.com/watch?v=z-EtmaFJieY) Crash Course video while waiting :) * **Your own computer** - just run `train.py`, which takes 20 sec on my laptop to compute. If you need help installing python, watch [this](https://www.youtube.com/watch?v=LrMOrMb8-3s) tutorial. ![trained](https://storage.googleapis.com/replit/images/1541033350157_38c60efaabc74234ee72285f0e17048b.pn) ## **๐Ÿ”ฎ Part 4: Predicting!** By now, you are supposed to have your new weights (`TrainedW1.in`,`TrainedW2.in`) saved in `data` folder and the accuracy of your Neural Network should be over 90%. Let's now write a code to use the trained weights in order to predict the digits of any new image! ![giphy](https://storage.googleapis.com/replit/images/1541033387111_bcb40155cc2e8ef38749e91c207033d8.gi) **Create a `predict.py` file and write the following code in there. Make sure to read the comments:** ```python import numpy as np import display from NN import Neural_Network NN = Neural_Network() # Loading data X = np.loadtxt("data/X.in", comments="#", delimiter=",", unpack=False) y = np.loadtxt("data/y.in", comments="#", delimiter=",", unpack=False) trW1 = np.loadtxt("data/TrainedW1.in", comments="#", delimiter=",", unpack=False) trW2 = np.loadtxt("data/TrainedW2.in", comments="#", delimiter=",", unpack=False) # Configuring settings of Neural Network: NN.configureNN(400, 25, 10, W1 = trW1, W2 = trW2) # Predicting a class number of given input testNo = 3402; # any number between 0 and 4999 to test NN.predictClass(X[testNo]) # Display output display.displayData(1, X, testNo, 'Predicted class: ' + str(np.argmax(np.round(NN.forward(X[testNo]))) + 1) ) ``` **Change the value of `testNo` to any number between 0 and 4999. In order to get a digit (class) prediction on the corresponding example from array X, run the code from:** * **Repl.it** - but you would need to move code from `predict.py` into `main.py`. Don't delete `predict.py` just yet. * **Your own computer** - just run `predict.py`. Yay, you are officially a data scientist! You have successfully: 1. Analyzed the data 2. Implemented the training of your Neural Network 3. Developed a code to predict new testing examples ![congrats](https://storage.googleapis.com/replit/images/1541033425490_308fdfc015d494a8aeceae5564956f4b.gi) ## **๐Ÿš€ Acknowledgments** Hat tip to @shamdasani whose code I used as a template for Neural Network architecture and Andrew Ng from Stanford whose data I used. Plenty of things I told you are not completely correct because I rather tried to get you excited about the topic I am passionate about, not dump some math on you! If you guys seem to enjoy it, please follow through with studying machine learning because it is just an amazing experience. I encourage you to take [this free online course](https://www.coursera.org/learn/machine-learning) on it to learn the true way it works. Also, it's my first post here and I'd appreciate any feedback on it to get better. Keep me updated on your progress, ask any questions, and stay excited! โœจโœจโœจ
15
posted by ArtemLaptiev1 (71) 7 months ago
โ–ฒ
2
Simple Message Encrypter and Decrypter In Python 3
### Simple Message Encrypter and Decrypter In Python 3 Hi, in this tutorial I will be sharing a simple program that scrambles sentences so it is difficult to decipher them (it's not very secure though). *** #### Imports and Variables We will be using three imports in this program. ```py import replit import random import time ``` The `time` and `replit` imports are used to make the program more pleasant to use and the `random` import will make the message randomly scrambled. We will also be using three variables. ```py alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p','q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '@', '#', '$', '&'] key = '' path = input("Do you want to encrypt a message or decrypt a message? \n") ``` The `alphabet` list gives the program characters it can use to scramble the message. The `key` will later be used to store the information to unscramble the message. And the `path` will ask the user for what they want to do. *** #### The Program First we need to ask the user for what they want to do. Let's start with the encryption part. ```py if path == 'encrypt': message = input("Enter your message. \n") origin = message limit = len(message) ``` Next we need to make a loop that replaces characters in the message with randomly picked characters from our `alphabet` but won't mix anything up. ```py for i in range(limit): pick = random.choice(alphabet) if pick in message: print("false") else: message = message.replace(message[i], pick) alphabet.remove(pick) time.sleep(0.06) replit.clear() print(message) ``` We also need to generate a key the program can later use. We do this by comparing the old message with the new one. ```py for i in range(limit): c1 = origin[i] c2 = message[i] c3 = c1 + c2 if c3 in key: print("false") else: key = key + c3 time.sleep(0.06) replit.clear() print("Encrypted message - " + message) print("KEY - " + key) print("") ``` Now we have the part of the program that unscrambles the message. This part of the program does that by taking the odd number characters from the key and replacing them in the scrambled message with the even characters. ```py elif path == 'decrypt': pad = [] code = input("Enter the encrypted message. \n") cracker = input("Enter the key. \n") limit2 = len(cracker) limit3 = len(code) i = 0 o = 0 truemessage = '' for i in range(limit3): examine = code[i] o = 0 while o <= limit2 - 2: truevalue = cracker[o] falsevalue = cracker[o + 1] if falsevalue in examine: truemessage = truemessage + examine.replace(falsevalue, truevalue) time.sleep(0.06) replit.clear() print("Decrypted message - " + truemessage) o = o + 2 ``` *** ### I hope you liked this tutorial. Here is the full code. ```py import replit import random import time key = '' alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p','q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '@', '#', '$', '&'] path = input("Do you want to encrypt a message or decrypt a message? \n") if path == 'encrypt': #print(path[:4]) message = input("Enter your message. \n") origin = message limit = len(message) for i in range(limit): pick = random.choice(alphabet) if pick in message: print("false") else: message = message.replace(message[i], pick) alphabet.remove(pick) time.sleep(0.06) replit.clear() print(message) for i in range(limit): c1 = origin[i] c2 = message[i] c3 = c1 + c2 if c3 in key: print("false") else: key = key + c3 time.sleep(0.06) replit.clear() print("Encrypted message - " + message) print("KEY - " + key) print("Note: please ignore the spam falses if you receive them.") elif path == 'decrypt': pad = [] code = input("Enter the encrypted message. \n") cracker = input("Enter the key. \n") limit2 = len(cracker) limit3 = len(code) i = 0 o = 0 truemessage = '' for i in range(limit3): examine = code[i] o = 0 while o <= limit2 - 2: truevalue = cracker[o] falsevalue = cracker[o + 1] if falsevalue in examine: truemessage = truemessage + examine.replace(falsevalue, truevalue) time.sleep(0.06) replit.clear() print("Decrypted message - " + truemessage) o = o + 2 ```
5
posted by PythinPython (5) 7 days ago
โ–ฒ
74
A Crash Course in LOLCODE ๐Ÿฑ
# A Crash Course in LOLCODE ___ OHAI! This is a crash course in the beautiful programming language known as LOLCODE! LOLCODE is a great language, and while it is similar to many other programming languages, trying to learn it may confuse some people because of the syntax. For this tutorial, any time I say `[variable1]`, `[variable2]`, or `[variable]`, as long as I'm not talking about initializing a variable, you can put a value instead. ### Creating a new program To begin a program, you need to have the line `HAI 1.2`. This will declare that it's a LOLCODE program that's written in LOLCODE 1.2. The last line in the program must be `KTHXBYE`. ### Comments There are two different ways of doing commenting - `BTW` and `OBTW`. The differences are shown below: ```lolcode BTW This is a one-line comment. OBTW This is a multi-line comment TLDR ``` The indentation is not necessary, but it makes it easier to read. ### Variables Variables are dynamically typed in LOLCODE, so you don't have to give them a type when declared. To declare a variable, use `I HAS A [variable]`. However, if you do want to give it a type, you can use `I HAS A [variable] ITZ A [type]`. There are 4 usable types of variables: - TROOF (a boolean - `WIN` or `FAIL`, corresponding to true or false.) - NUMBR (an integer - whole numbers) - NUMBAR (a float - decimal places) - YARN (a string - text, defined by "") Variable names are case-sensitive, so INT is different from Int. You can use capital and lowercase letters, underscores, and numbers - as long as neither underscores nor numbers begin the variable name. To assign one variable to another, use `[variable 1] R [variable 2]`. ### Concatenation It's very simple to concatenate YARNS in LOLCODE - you use `SMOOSH [variables to concatenate, seperated by AN] MKAY`. It will cast any input given to it to a YARN before concatenating. See below for an example. ```lolcode I HAS A VAR1 ITZ "Hi" I HAS A VAR2 ITZ 1234 I HAS A VAR3 ITZ WIN I HAS A VAR4 ITZ SMOOSH VAR1 AN VAR2 AN VAR3 MKAY VISIBLE VAR4 BTW The output will be Hi1234WIN ``` ### Casting There are a couple different ways of casting a variable from 1 type to another. The first is `MAEK [variable] A [type]`. This will attempt to cast from whatever type the variable is to the desired type. However, this will not work if it's illogical - for instance, trying to cast letters into a NUMBR or NUMBAR. To cast a variable to a different type and save the output in a different variable, use `[variable 1] R MAEK [variable 2] A [type]`. ### Expressions There are 3 different types of expressions in LOLCODE - **Math**, **Boolean**, and **Comparison**. The basic form for all expressions is either `[expression] [variable]` or `[expression] [variable1] AN [variable2]`. #### Math In LOLCODE, you have all the typical expression types - addition, subtraction, multiplication, division, and modulus (remainder), as well as some less-common ones - min (returns the value of the smaller of 2 variables) and max (returns the value of the larger of 2 variables). If either variable is a YARN and has a decimal, it is cast to a NUMBAR for the calculation. If it doesn't have a decimal, it's cast to a NUMBR. If both variables used are NUMBRs, then integer math is performed. If one or both are NUMBARS, floating floating point math is invoked. See below for a list of math expressions: ```lolcode SUM OF [variable 1] AN [variable 2] BTW This is addition DIFF OF [variable 1] AN [variable 2] BTW This is subtraction PRODUKT OF [variable 1] AN [variable 2] BTW This is multiplication QUOSHUNT OF [variable 1] AN [variable 2] BTW This is division MOD OF [variable 1] AN [variable 2] BTW This is modulus (remainder) BIGGR OF [variable 1] AN [variable 2] BTW This returns the bigger variable's value SMALLR OF [variable 1] AN [variable 2] BTW This returns the smaller variable's value ``` #### Boolean The boolean expressions work pretty much as you would expect, comparing WINs and FAILs. You can use and, or, xor, and not. Any value passed to this is cast to a TROOF. See below for the complete list: ```lolcode BOTH OF [variable 1] AN [variable 2] BTW This is an and statement EITHER OF [variable 1] AN [variable 2] BTW This is an or statement WON OF [variable 1] AN [variable 2] BTW This is an XOR statement NOT [variable] BTW This is a not statement ALL OF [variable 1] AN ... MKAY BTW This is an infinite and statement, keep adding variable names and ANs to check more ANY OF [variable 1] AN ... MKAY BTW This is an infinite or statement, see above ``` ### Comparisons This is very similar to boolean expressions - it takes in 2 variables and checks if they're either the same or different. However, it doesn't have to be 2 TROOFS, but they do have to be the same type. "9" and 9 will NOT be recognized as the same. See below for examples ```lolcode BOTH SAEM [variable 1] AN [variable 2] BTW returns WIN if variable 1 == variable 2 DIFFRINT [variable 1] AN [variable 2] BTW returns WIN if variable 1 != variable 2 BOTH SAEM [variable 1] AN BIGGR OF [variable 1] AN [variable 2] BTW variable 1 >= variable 2 BOTH SAEM [variable 1] AN SMALLR OF [variable 1] AN [variable 2] BTW variable 1 <= variable 2 DIFFRINT [variable 1] AN BIGGR OF [variable 1] AN [variable 2] BTW variable 1 < variable 2 DIFFRINT [variable 1] AN SMALLR OF [variable 1] AN [variable 2] BTW variable 1 > variable 2 ``` ### Printing To output text, you have to use the `VISIBLE [output]` command. This can also be used with variables by using `VISIBLE [variable]`. See below for examples: ```lolcode VISIBLE "Invisible" VISIBLE INT ``` ### Input To get input from the user, you can use `GIMMEH [variable]`. For this, you MUST specify a variable because that is where the output is stored. GIMMEH stores input as a YARN, so if you want to get a NUMBR or NUMBAR you have to cast it as such. ### Conditionals Creating conditionals is fairly straightforward in LOLCODE. There are 2 basic formats - one utilizing TROOFs, and one utilizing other types of variables. To create a conditional using TROOFs, use the following: ```lolcode [expression], O RLY? YA RLY BTW This code will execute if the result of [expression] is WIN NO WAI BTW This code will execute if the result of [expression] is FAIL OIC ``` To create a conditional using other variable types is a little more involved. Basically, `OMG [value]` is the same as checking if the expression is equal to [value], and `OMGWTF` is an else. To end a statement, you must put GTFO. ```lolcode [expression], WTF? OMG 5 BTW This code will execute if the result of [expression] is 5 GTFO OMG 91 OMG 21 BTW This code will execute if the result of [expression] is 91 or 21 GTFO OMGWTF BTW This code will execute if the result of [expression] is not 5, 91, or 21 OIC ``` ### Loops Loops are a somewhat confusing beast at first, but actually aren't that hard. First, you need `IM IN YR [label for the loop - I would recommend just calling it LOOP]`. Then, if you want to increase the iterator variable have `UPPIN YR [variable]`, and if you want to decrease the iterator variable have `NERFIN YR [variable]`. Finally, if you want to go until a certain value, use `TIL [expression]`, and if you want to go while a certain expression is true, use `WILE [expression]`. To end the loop, use `IM OUTTA YR [label]`. See below for an example: ```lolcode I HAS A ITERATOR ITZ 0 IM IN YR LOOP UPPIN YR ITERATOR TIL BOTH SAEM ITERATOR AN 9 VISIBLE ITERATOR IM OUTTA YR LOOP BTW This will output 0 through 8, and then stop before printing 9. ``` ### Conclusion Aaaand that's pretty much everything I could possibly find on the internet about LOLCODE... There is documentation for functions and BUKKITs (arrays), but I couldn't get them to work and so I decided against detailing them. If you still want MOAR LOLCODE documentation, go [here](https://github.com/justinmeza/lolcode-spec/blob/master/v1.2/lolcode-spec-v1.2.md), [here](https://esolangs.org/wiki/LOLCODE), or [here](https://learnxinyminutes.com/docs/LOLCODE/). If you want a fairly simple random python with turtle spiral generator, go check out my tutorial for that [here](https://repl.it/talk/challenge/Python-Turtle-Graphics-Random-Spirals/7651). If you want a super long tutorial about how to make your own game using only python with turtle graphics, go [here](https://repl.it/talk/challenge/How-to-make-a-fairly-basic-game-using-Python-with-Turtle-Graphics/8182). If you liked this tutorial, feel free to leave an upvote. Thanks! :)
14
posted by minermaniac447 (169) 7 months ago
โ–ฒ
60
A Quick Guide to Repl.it Talk Markdown
Guys! In this quick tutorial, I'll be showing you how to make your posts pretty using Markdown styling! # Headers First we'll learn about headers. A header starts with a hash symbol `#` followed by a space: ```md # A header ``` Output: # A header Headers can be a variety of sizes. A smaller header starts with more hash symbols. The number of hash symbols can be 1 to 6: ```md #### A header with 4 hash symbols ``` Output: #### A header with 4 hash symbols Alternatively, you can also "underline" a text with `=` or `-` to produce headers ```md First header (Same as # First header) -------------- Second header (Same as ## Second header) =========== ``` ___ # Text Styles You can make *italic*, **bold** or ~~strikethrough~~ text. Put the text between a pair of `*` or `_` to make it *italic*. ```md *italic text* _also italic_ ``` Output: *italic text* _also italic_ Put two `*` or `_` on both sides of text to make it **bold**. ```md **bold text** __also bold__ ``` Output: **bold text** __also bold__ You can also do a ~~strikethrough~~ by putting two tildes (`~`) on each side: ```md ~~strikethrough~~ ``` Output: ~~strikethrough~~ It's ok to mix up those stylings: ```md **_~~bold, italic and strikethrough~~_** ``` Output: **_~~bold, italic and strikethrough~~_** ___ # Lists There's two kind of lists in Markdown: **unordered** (bulleted) and **ordered** (numbered). Since repl.it talk Markdown doesn't support ordered lists (sadly), we'll only deal with unordered lists. An unordered list item starts with either a `*`, `+` or `-` followed by a space: ```md * this + that - and stuff ``` Output: * this + that - and stuff Use indentations of 2 spaces to make sublists ```md * list item * sublist item * yet another sublist item ``` Output: * list item * sublist item * yet another sublist item ___ # Links Just paste the URL and it'll work: ```md https://repl.it ``` Output: https://repl.it If you want **custom link text**, try this: `[link text](URL)`: ```md [Repl.it](https://repl.it) ``` Output: [Repl.it](https://repl.it) ___ # Images The Markdown syntax for **images** is pretty simple: `![alt text](URL)`: ```md ![Repl.it logo](https://repl.it/public/images/icon-square.png) ``` Output: ![Repl.it logo](https://repl.it/public/images/icon-square.png) **Wait... what if my image is stored in my computer? It doesn't have a URL!** Well, repl.it provided an easy way to upload images. All you need is to click the **select files** button below to upload it. After that, you'll see the Markdown code for your image in the text box. ___ # Code And finally, code!! **Inline code** and **code blocks** are widely used in repl.it talk since repl.it talk is a platform for coders to share. Wrap a pair of **backticks** (`` ` ``) around text to make a span of code (inline code): ```md `$ node index.js` ``` Output: `$ node index.js` To indicate a block of code, put three backticks (` ``` `) at both the start and end of your code: ````md ``` This is a code block. Everything here is monospaced. ``` ```` Output: ``` This is a code block. Everything here is monospaced. ```` Additionally, repl.it supports code block syntax highlighting, which is pretty useful for emphasizing readability. Just put the language name (or its short form) after the three backticks: ````md ```js while (true) console.log("MARKDOWN IS AWESOME!!!"); ``` ```` Output: ```js while (true) console.log("MARKDOWN IS AWESOME!!!"); ``` ___ # Blockquotes To do blockquotes put a `>` before each line of the block: ```md > Timchen is the greatest and > we should praise him ``` Output: > Timchen is the greatest and > we should praise him Don't forgot to leave a blank line after each blockquote! ___ # Horzontal rules A horzontal rule (a line that separates content) can be made of either three asterisks (`*`) or underscores (`_`): ```md There's a horizontal rule below *** There's a horizontal rule above ``` Output: There's a horizontal rule below *** There's a horizontal rule above That's all what I can teach in this very tutorial. Start using Markdown to style your posts, and find more about it!
23
posted by JSer (1070) 7 months ago
โ–ฒ
9
Learning Web Development w/ Python Part 2
# Learning Web Development with Python and Django ## Part 2 ## Welcome! In [Part 1](https://repl.it/talk/learn/Learning-Web-Development-with-Python-Part-1/12880) we made our first web-page with Django using function-based views. In this tutorial, we will be learning how to use `class-based views` which are more powerful and generally a better choice for web development. We will also look at html templates and creating multiple pages. ## Class-Based Views In the last tutorial, we used function-based views to determine what the client (visitor to the page) would see. However, there are also class-based views, which I will introduce to you now. These make creating views faster, especially when using databases, which we will be doing later. Let's get started! Fork the [basic template](https://repl.it/@ArchieMaclean/Basic-Template) and rename it to `tutorial-part-2`, or something else if you want. ### Templates Before we start creating our view, we need to learn about templates. In Part 1, our html was stored as a string, ```python html = "Hello, World!" ``` This is all right for very small pages, but when you want to make larger or more complicated pages, this gets very limiting. What would be better? If we made a file containing all of our html, and then imported that and displayed it. To do this, we are going to create a folder called `templates`. This will store all of our html templates for our website. Make sure you create your `templates` folder outside of your `main` folder, or Django will not be able to find it, like this: ![image](https://storage.googleapis.com/replit/images/1554639512628_b8e7a503d9c9bad16ec1cc01b69a7e32.pn) #### Creating our first Template Within `templates`, create a file called `home.html`. Then you can write some html inside it: ```html <!DOCTYPE html> <html> <head> <title>Home</title> </head> <body> <h1>Home</h1> <p>Welcome to this website! This site was created using the web framework Django</p> </body> </html> ``` This is just some basic html. This isn't a html tutorial, but here is a quick line-by-line analysis: * `<!DOCTYPE html>` tells the browser what type of file it is (`html`) * The `<html>` and `</html>` tags surround all the html - they show where it starts and ends * The `<head>` tag is used to put data in that isn't displayed on the page. Here I've put in the page title - this is shown in your tab at the top of the screen on your browser. * The `<body>` tags surround all the html that will be shown on the screen * The `<h1>` tag stands for `heading 1` and means that it is the largest heading possible. You can also get `<h2>`, `<h3>` and so on, down to `<h6>`. * The `<p>` tag surrounds a paragraph. -------------------------------------------------------------------------- Now we've created our template, we can write our home page view. ### Creating a Home Page View Now we can create our class-based view! Navigate to `views.py` and add the following code: ```python from django.views.generic import TemplateView class HomePageView(TemplateView): template_name = 'home.html' ``` `Line 1` imports `TemplateView`, which we will need to create our view. `Lines 3-4` define our view class * On `Line 3` we create our view, called `HomePageView`. This view **inherits** from `TemplateView`. This means we can use all the code from `TemplateView` as well as some code that we add that is specific to `HomePageView`. * Here, the only thing that is specific about our home page is that it uses the template `'home.html'`, so on `Line 4` we set `template_name` equal to our template That's it! All the rest is taken care of by the `TemplateView` class, which the Django creators have written - so we don't need to worry about anything else. ### Adding the URL (Page Name) Finally, to give the view a url, we need to add it to the `urlpatterns` in `urls.py`: ```python from .views import HomePageView urlpatterns = [ url(r'^admin/', admin.site.urls), url('',HomePageView.as_view(), name='home') ] ``` This is pretty much all the same as last time (if you need a refresher, see [Part 1](https://repl.it/talk/learn/Learning-Web-Development-with-Python-Part-1/12880)). The only difference is that, for class-based views, we need to add a `.as_view()` on to the end in order for the page to display. ### ...And it Works! If you run the repl now, and open the page in a new tab, we get: ![image](https://storage.googleapis.com/replit/images/1554634538507_9cf09092536f2e87fe37965cc96655e4.pn) It worked! ------------------------------------------------------------------------------------------ ### How did Django know where to find the template? If you've been paying close attention, you may be wondering - how did Django know where to find the template? In the view we just specified it as `'home.html'`, not as `'templates/home.html'`. The answer lies in `settings.py`. If you open the file, you can see a list called `TEMPLATES`: ```python # stuff BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # more stuff TEMPLATES = [ { # stuff 'DIRS': [os.path.join(BASE_DIR, 'templates')], # more stuff }, ] ``` I have cut out the rest of the list to draw your attention to `'DIRS'`. What this code does is sets `'DIRS'` to the `templates` folder that we created. Every time we request a template, Django will look in this folder. This code was put here by repl in case you wanted to create templates. ### Making multiple pages Now we are going to add another page - an `About` page. To do this, we follow much the same process as we did for the home page. ##### Template We create a file called `about.html` in `templates`: ```html <!DOCTYPE html> <html> <head> <title>About</title> </head> <body> <h1>About</h1> <p>This is a tutorial for creating a web app with Django. Currently all we have done is made web pages</p> </body> </html> ``` ##### View Then we create a new view in `views.py`: ```python # HomePageView class AboutPageView(TemplateView): template_name = 'about.html' ``` ##### URL And finally, we add the url in `urls.py`: ```python from .views import (HomePageView, AboutPageView) urlpatterns = [ url(r'^admin/', admin.site.urls), url('about',AboutPageView.as_view(), name='about'), url('',HomePageView.as_view(), name='home'), ] ``` The only thing to note from here is that the URL is now `about`, which means that the page will be located at https://domain.name/about/. The URL for the `about` page **must** be above the URL for the `home page` because Django works through them from first to last, and because of the way it works, it matches `''` to **all** pages. However, if we put the `about` before `home`, it will check `about` first, so if the client enters https://domain.name/about, it will be matched first, and the correct page displayed. ### Extending Templates The last thing we are going to learn in this (rather long) tutorial is a very useful built-in functionality of Django that allows template extension. What do I mean by this? An example is probably the best way to show it. Create a new file in `templates` called `base.html`. This is going to be our **base template**. Add the following html to the file: ```html <!DOCTYPE html> <html> <head> <title>{% block title %}{% endblock title %}</title> </head> <body> <a href="{% url 'home' %}">Home</a> <a href="{% url 'about' %}">About</a> {% block content %} {% endblock content %} </body> </html> ``` And update your `home.html` to look like this: ```html {% extends 'base.html' %} {% block title %}Home{% endblock title %} {% block content %} <h1>Home</h1> <p>Welcome to this website! This site was created using the web framework Django</p> {% endblock content %} ``` Now, if you know anything about html, this will look very strange because it has all these `{%`s which are not normally in html. There is quite a lot going on here, so I will walk you through it. In `base.html`: * On `Lines 1-3` we have standard html * On `Line 4` we have our first strange occurrence of the `{%` and `%}`. What is happening here? This is Django's **template language** - designed for doing interesting stuff with your pages. Here we are declaring a `block`. This means that it is going to get replaced by something from another file - as you can see on `Line 1` of `home.html`, we are replacing it with the word `Home`. * On `Lines 7/8` there is also something happening. Here we are using Django's `url` function. Remember when we were defining our views, we set a name for them? ```python urlpatterns = [ url(r'^admin/', admin.site.urls), url('about',AboutPageView.as_view(), name='about'), url('',HomePageView.as_view(), name='home'), ] ``` The `url` function gets the URL of the view with that name - so `{% url 'home' %}` would get the URL of the `home` page. The `<a href="` in html defines a link, so what we are creating here is a link to the home page, and then a link to the about page. * On `Lines 10/11` we are creating a `block` called content, that will also be replaced by another file - in `home.html` we are replacing it with `<h1>Ho...Django</p>`. The `home.html` imports the `base.html` html using `{% extends 'base.html' %}`, and then replaces what bits need to be changed. If we run this, we get: ![image](https://storage.googleapis.com/replit/images/1554638219005_eeaf811555b9a9e07ef89ebe89ae3fe0.pn) It worked! The brilliant thing about these extensions is that they can apply to any pages - just update `about.html` to this: ```html {% extends 'base.html' %} {% block title %}About{% endblock title %} {% block content %} <h1>About</h1> <p>This is a tutorial for creating a web app with Django. Currently all we have done is made web pages</p> {% endblock content %} ``` And our `about` page also has the links at the top! Also, the navigation means that we don't have to type in any more URLs, we can just click the links. ----------------------------------------------------------------- ### Conclusion And that's the end of Part 2! I hope you enjoyed it. In [Part 3](https://repl.it/talk/learn/Learning-Web-Development-with-Python-Part-3/13267) we will learn how to use databases with Django, as well as look at managing larger apps by splitting them up into smaller 'applets'. Please upvote if you found this tutorial helpful, it supports me and lets me know that you want more! If you have any questions, post in the comments and I (or someone else) will answer them.
5
posted by ArchieMaclean (432) 1 month ago
โ–ฒ
32
Build your very own URL shortener ๐Ÿ”—๐Ÿš€
## Build a tiny URL shortener, using a remote database ![](https://boring-lamport-1b901a.netlify.com/2018-12-2214-5f2c1bbe-59a2-4ba7-9544-438b1ab5e1dd.39.01.gif) [Demo](https://l.4ty2.fun) โฏ๏ธ [Code](https://repl.it/@jajoosam/tyni) ๐Ÿ‘จโ€๐Ÿ’ป Setting up a URL shortener is a lot of work - either you have to pay, or spend hours setting up your own server. This is a guide to making your own URL shortener with [repl.it](http://repl.it) - using `express`, and a remote database - all on `node.js` ## ๐Ÿ› ๏ธ Getting our environment running First up, fork the [https://repl.it/@jajoosam/tyni-starter](https://repl.it/@jajoosam/tyni-starter) repl, so that you have a running project. Next, create a new file - `.env` ![](https://boring-lamport-1b901a.netlify.com/Untitled-675a864b-7c8c-487d-8ca7-595eb8af67ba.png) A `.env` file can store secrets for you, that no one else will be able to see. This is where we want to store our token for accessing the remote database. ## ๐Ÿ“ Making our database We're going to be using [jsonstore.io](http://jsonstore.io) for storing all our URLs. Head over to [jsonstore.io/get-token](https://www.jsonstore.io/get-token) - and copy the token you see - this is the secret we want to store in our `.env` file. Open up your `.env` file, and set `KEY` to your token, like this ๐Ÿ‘‡ ```bash KEY=yourTokenGoesHere ``` Remember to keep **no whitespace**, or your token might not be recognized right! When you open `index.js` you'll see that I've already initialized the database, and a small web server for you. Now let's get to making our API so we can shorten them URLs ๐Ÿš€ ## ๐Ÿ‘จโ€๐Ÿ’ป The API There are two parts to our URL shortener: 1. Storing the short link, corresponding to the long URL - in our database. 2. Redirecting visitors from the short link to the long link Both of these are super simple to implement, thanks to the `express` server we're using - we'll just be collecting `get` requests for both of the tasks. For adding links to our database, we have a special endpoint - requests to it have two parts: the long URL, and the short path. ```javascript app.get('/shorten', (req, res) => { db.write(req.query.key, {"url": req.query.url}); res.status(200); }); ``` Adding this to our code lets us correspond the short path (`key`) to the long `url`, and then we finally send a successful response. For the second task, we'll just be collecting the short path (`key`) from a request, finding the corresponding URL in our database, and then redirecting our visitor โฌ‡๏ธ ```javascript app.get('/:key', (req, res) => { db.read(req.params.key + "/url").then( (url) => { res.redirect(url); }); }); ``` That's prety much it - we have a fully functional URL shortener ๐Ÿคฏ - check it out for yourself, open a new URL which looks like this ๐Ÿ”— ``` https://tyni.jajoosam.repl.co/shorten?key=yay&url=https://dsh.re/50854 ``` Now, going to [`http://tyni.jajoosam.repl.co/yay`](http://tyni.jajoosam.repl.co/yay) will be nice to see ๐Ÿ‘‡ ![](https://boring-lamport-1b901a.netlify.com/1-8380b52f-92c2-4acc-87dc-64011c6fd502.jpg) Of course, you'll be replacing `tyni.jajoosam` in those URLs with your own repl! ## โœจ The Frontend Our URL shortener does work, but it's tedious, having to type out a huge URL before shortening it - we can make the whole process much simpler with a simple frontend. I've already created this - and gone for a neat and minimal look using [wing.css](https://github.com/kbrsh/wing) ![](https://boring-lamport-1b901a.netlify.com/Untitled-0fa3af54-ddae-46ca-abdf-4fcbcb218f8b.png) You just have to add code to send visitors to the hompage in the `static` folder ๐Ÿ  ```javascript app.get('/', (req, res) => { res.sendFile("static/index.html", {root: __dirname});; }); ``` If you browse through the `static` folder, you'll find a simple `HTML` file with a form, `CSS` to style our page, and most importantly, `JS` to send requests to our URL shortening API. The `HTML` is quite straightforward, we're asking for the long URL, and *optionally* a short path. Open up `script.js` and you'll see the `shorten()` function. Here's what the JS file does (*I've also annotated the code with comments*) ๐Ÿ‘‡ ๐Ÿ” Getting the path(`key`) and the long `url` from the form. ๐Ÿ“ Possibly generating a random 5 character hash as our path (in case there's no path entered) ๐Ÿ”— Sending a get request to our API, with our `key` and `url` as parameters ๐Ÿ–ฅ๏ธ Displaying the shortened URL on our page ## ๐ŸŒ Getting our custom domain Sure, our links are shorter - but we still don't have them on our own domain, and the `repl.co` links can be pretty long ๐Ÿ‘€ Luckily for us, the folks at [repl.it](http://repl.it) recently allowed custom domains to be used! That means this project could be something you actually use all the time ๐Ÿ˜„ Check out `dotcomboom`'s guide on [using custom domains](https://repl.it/talk/learn/How-to-use-a-custom-domain/8834), it should only take a few minutes. It also teaches you about getting free domains ๐Ÿ’ธ Be sure to put down any questions or improvements down in the comments ๐Ÿ’ฌ - and here's all the code for you to go over again ๐Ÿค– https://repl.it/@jajoosam/tyni
10
posted by jajoosam (471) 5 months ago
โ–ฒ
4
REST API Demo
This is a really simple REST API demo api (or an example if you want to fork it) # API Docs API Endpoint Prefix: `https://REST-Test-API.vandesm14.repl.co` `/api/` - Returns the status of the api `/api/echo/:param` - Returns `:param` `/api/echodbl/:param1/:param2` - Returns `:param1, :param2` `/api/echoquery/?q=*` - Returns `q` I hope this helps anyone who is interested in RESTful API's! https://repl.it/@Vandesm14/REST-Test-API
2
posted by Vandesm14 (405) 14 days ago
โ–ฒ
36
How to use a custom domain
In case you've worked with repl.it before, you may have noticed that you are given a decently long subdomain for your project, like the following: `my-little-blog--dotcomboom.repl.co` You may have wanted to change that into a shorter, more memorable domain name, like this: `mylittleblog.cf` Let's see how. ## Getting your domain This section will cover registering a domain name with Freenom. If you already have a domain, [skip this part](https://repl.it/talk/learn/How-to-use-a-custom-domain/8834#attaching-to-repl.it). ### A word on Freenom #### You don't own it Freenom hands a selection of domain names out like free candy. If you've heard of dot.tk, it's these guys. In this tutorial I'll walk you through them, but I'd also like to point out that by registering a domain name with Freenom, you are still not entitled to it. It's perfectly valid and legal for them to all of a sudden deactivate your domain and use it to make money with ads, without notification. This is just a fair warning, some people have had domains from Freenom for a long time without any issues, but anything can happen. In short, nothing could be actually free. You are borrowing Freenom's domains for your purposes, and don't own them like you would from another registrar. #### HTTPS ~~If you use Freenom, you won't be able to use HTTPS. You need to use "http://" before your domain instead. You will still be able to use your repl.co domain name if you need to use HTTPS, so make note of that.~~ **As https://repl.it/@turbio pointed out, HTTPS does work with a Freenom domain! You just need to wait a little bit of time for it to get set up.** As for "mission critical" applications, like, say, Uptime Robot or something like that, you will probably want to use your repl.co domain. ### Registering the domain You will want to make or log into a Freenom account first. Then, you will be brought to the [Client Area](https://my.freenom.com/clientarea.php). Once you're signed in, you will find "Register a New Domain" under the Services menu. ![image](https://storage.googleapis.com/replit/images/1543204601000_441af0314e3fc5e71a0139e9f766e678.pn) This will bring you to Freenom's domain search. Type in the name you want. In this example, I searched for "mylittleblog". It will give you a list of what domains they have available. ![image](https://storage.googleapis.com/replit/images/1543204667654_d8c9142df0d4f1487abdc49631a435ad.pn) Choose the one you want, then scroll down to the bottom and choose "Checkout". Don't touch the section in the middle, we'll cover that later. Choose the period you'll be using the domain, which is from 3 months to 12 months. (If memory serves, when you're going close to the due date, you are offered the opportunity to renew.) ![image](https://storage.googleapis.com/replit/images/1543204740295_ac2737cabaa59f81f9e162774f281755.pn) Check the box to agree to the Terms and Conditions (reading them is a good idea too) and complete the order. Then, go back to your client area. ## Attaching to repl.it ### Repl.it setup Go to your repl and click on the pencil icon next to the address in the preview pane. ![image](https://storage.googleapis.com/replit/images/1543205234697_4f6cbafaf7aae5af99d0c74ae423b95f.pn) Type in your domain name and if the domain is registered correctly, it will prompt you to add a `CNAME` record to your domain: ![image](https://storage.googleapis.com/replit/images/1543205288588_5e41390b98167f4e887b0de892808666.pn) Copy where the record should point to, then go to your client area at your registrar (in my case, Freenom). ### Registrar setup From [My Domains](https://my.freenom.com/clientarea.php?action=domains), go to the management page for the domain you chose. From Management Tools, choose Nameservers. Make sure it is checked to use default nameservers. ![image](https://storage.googleapis.com/replit/images/1543205432252_a191c52c1f996716d91e8266a41efd7c.pn) Then, find the area where you can add records; for Freenom, it is "Manage Freenom DNS". In the Name textbox, enter your domain name, nothing more, nothing less. Change the type to `CNAME`. Then, set the target to what repl.it asked you. Then, choose Save Changes. ![image](https://storage.googleapis.com/replit/images/1543205550116_8df6cb0139894e925b9a6fb80ea454aa.pn) ### Finish Now go back to your repl. Repl.it now should have noticed that your domain is set up correctly and now lets you click on the Link button. ![image](https://storage.googleapis.com/replit/images/1543205653984_83f953b10c6a8cbea3959c8f3709b06d.pn) You're done! Your domain should now be attached to your repl.
20
posted by dotcomboom (46) 6 months ago
โ–ฒ
15
Hosting discord.py bots with repl.it
# Hosting [discord.py](http://discordpy.readthedocs.io/en/latest/) bots on [repl.it](https://repl.it/) *This tutorial shows you how you can host your **discord.py** bots on [repl.it](https://repl.it/).* *Before you start, you should already have a working bot. Also, this really doesn't matter if you're using [discord.py async](https://discordpy.readthedocs.io/en/async/) or [discord.py rewrite](https://discordpy.readthedocs.io/en/rewrite/). Works like a charm for both!* *Just to ease things, we'll be using the end product of [this tutorial](https://repl.it/talk/learn/Discordpy-Rewrite-Tutorial-using-commands-extension/10690).* ------ ### What we'll be doing? 1. *Creating a web server.* 2. *Using [uptimerobot](https://uptimerobot.com) to ping our bot every 30 minutes.* *We do this because our repl goes offline after 1 hour of inactivity. So we keep pinging the repl every 30 minutes, to avoid it being idle for one hour.* # Step 1: The requirements.txt file. Once you have your bot ready for hosting create a new file named `requirements.txt` in the root directory of your [python repl](https://repl.it/languages/python3). Open it up, the `requirements.txt` file holds all your project dependencies. Make sure to add the appropriate package names for the packages you're already using. A sample file for basic bots are given below: - ------ ``` discord.py ``` `requirements.txt` for a discord.py rewrite bot. ------ Now that you have the basic requirements ready, add one more requirement i.e. `flask`. Making your `requirements.txt` something like: - ``` discord.py flask ``` **Note :** *I am sticking to discord.py rewrite bot, but it really doesn't matter again.* ------ [flask](http://flask.pocoo.org/) is a python module for handling [http requests](https://www.tutorialspoint.com/http/http_requests.htm). ------ # Step 2: Setting up a server Setting up a server using Flask is very easy. But to keep things simple and your bot's file clean, we'll make a server in a new file and name it `keep_alive.py` since that is what most people like to call the file that helps keep their bot alive. Open up the `keep_alive.py` file and import `Flask` also import `Thread` you can learn more about Threads [here](https://docs.python.org/3/library/threading.html). ```python from flask import Flask from threading import Thread ``` We didn't have to add threading to our requirements since it comes with python. Next, create the actual server. ```python app = Flask('') ``` Easy, isn't it? But it's not over just yet. Next, we add a route. A route is basically what handles http requests. Without a route the existence of our server does nothing. So add the following code ```python @app.route('/') def main(): return "Your bot is alive!" ``` `@app.route()` is a decorator which defines a route. `'/'` is the default route or the homepage of our server. The `main` function is called whenever a user makes a request to the `'/'` route which basically returns whatever has to displayed on the webpage, here we simply send the string `Your bot is alive` to keep things simple. Now that our server is ready, we need to make sure that it runs and http requests can be made to it. ```python def run(): app.run(host="0.0.0.0", port=8080) ``` You can basically put any 4 digit number in port which is not already in use. The defaults for python is `8080` and that's what we'll stick to. Finally, we make a function that we can call to prepare our server and allow it to be pinged. ```python def keep_alive(): server = Thread(target=run) server.start() ``` And we're basically done with our `keep_alive.py` file. ------ # Step 3: Combining the server and bot. Now that we're done making both the bot and the server, we need to combine the two. That is easy too, open up the `main.py` file ( or whatever file has the `discord_client.run(bot_token)` function in it ) and add the following line at the top: - ```python import keep_alive ``` This will import the keep_alive file in your bot's main file. Now just before starting the bot, at the bottom of the same file write the following code: - ```python keep_alive.keep_alive() ``` This will run the `keep_alive()` function that we defined in the `keep_alive.py` file earlier. And now your server is ready too! Run the bot, you should see something like this: - ![Keep Alive](https://i.imgur.com/XA3cvpK.png) Notice that small window saying `Your bot is alive!` if you see it, you successfully created the server! Only the last step remains! Before you go into the last step, make sure to copy the `repl.co` link you see in that small window's address bar. (`https://discordpy-rewrite.thedrone7.repl.co` in the picture, it will be referred to as the `server link` in the rest of the tutorial) And in case you don't see it, go through this tutorial again and make sure you didn't miss something, also if it retains, don't hesitate to comment and tell me. ------ # Step 4: Setting up [uptimerobot](https://uptimerobot.com/) First of all visit https://uptimerobot.com/ and register an account just like any other website. (It is free of course) Next, Once, you're logged in, 1. Click on the `New Monitor` button. ![Imgur](https://i.imgur.com/c8WCZab.png) 2. Next, choose the `HTTP(S)` Monitor Type. Give it a friendly name of your choice ( naming it after your bot is recommended ) Paste your `server link` in the `URL/IP` field. Set the Monitoring Interval to anything between 5 minutes to 45 minutes. ( 30 minutes is recommended) Optionally, Select yourself as one of the `"Alert Contacts To Notify"` so you are notified via e-mail whenever your bot goes offline. Finally making it look something like this: - ![Uptimerobot final monitor](https://i.imgur.com/yzRdE2K.png) 3. Click on `Create Monitor` and you're good to go! ------ Now you're bot will stay online for as long as it can. *( Repl it being just another host, won't be able to host it 24/7 so it **will** have a downtime of a few minutes within every 24 hours.)* And you're done! The final product can be [found here.](https://repl.it/@TheDrone7/discordpy-rewrite) > Please upvote if you found this useful! > > Also, comment down below if there's something you would like to share or ask. And finally, thanks for reading it!
11
posted by TheDrone7 (398) 3 months ago
โ–ฒ
11
A Slightly More Advanced ChatBot [Intermediate, Python]
# Hello Fellow Replers! Welcome to my next tutorial with a ChatBot, if you haven't seen my last tutorial, then you should [click here](https://repl.it/talk/learn/Simple-Chat-Bot-Beginner-Level-Python/11130). # How do we make our ChatBot more advanced? That is easy to answer first we need to think, how would this be possible? With connecting our ChatBot to google and find the most relevant answer to the User Input? Good idea, but no. In fact we can make even simpler, and I'm going to explain. We can use two lists! Now this is really cool, and simple. A lot of people don't know how to do this. You will after reading the rest of this tutorial. # How can we use a list to detect User Input? Well, we can't do that, but we can use it so the ChatBot can figure out how to respond to the User. Let me give you a small explanation about how this is possible. First, we have two lists: `Check` `Respond` If we assign values then they will look like this: ```python Check = ["hello", "how are you?"] Respond = ["Hi.", "I'm good.'] ``` Do you notice anything? The User Inputs and the Responses have the same List Index Value(LIV). Let me show you. If you look at list `Check` you will see the first item: `hello` this has a LIV of `0`. And if you look at list `Respond` you will see the first item: `Hi` this also has a LIV of `0`. Do you see a correlation between the two? Maybe you do, maybe you don't you will understand later in the next section. # Now to the code! Alright so we have the basic code we wrote in the last tutorial. That code was simple, and impractical. Let's simplify it. Here is the code: ```python UserInput = "" ChatBot_Name = "Ozzy" UserInput = str.lower(input(": ")) if UserInput == "hi": print(ChatBot_Name + ": Hello!") elif UserInput == "who made you?": print(ChatBot_Name + ": I was made by Christian Thone") ``` Lets first create a new file, you can do that by clicking the little paper icon on the side of you project: ![Screenshot 2019-02-26 at 8.17.57 AM](https://storage.googleapis.com/replit/images/1551187092327_54d076adc829d1b11f9b6abac92c3275.pn) Now go to the smaller paper Icon with the plus sign and click that. Now you have created a file, for the name of your file name it `client.py`. There is no specific reason for the name it just looks cool. Ok, back to the tutorial. Inside of `client.py` create the following lists: ```python User_Inputs = [] __Responses = [] ``` Now obviously we have nothing in the lists, but that is what we want right now. Hmmm? So how do we use these lists? Easy! We use what Repl.it has called ```import```. Type the following into `main.py` at the top of the script: ```python from client import User_Inputs, __Responses ``` Now we can use these lists. We need some values in these lists for anything to happen, so write the following into your lists in `client.py`: ```python # REMEMBER TO HAVE YOUR USER_INPUTS IN LOWERCASE! User_Inputs = ["hi"] __Responses = ["Hello."] ``` Okay cool, now we have some simple code for our lists, but we still cant do anything with our ChatBot yet. First, we need to tell it what to do. Go into `main.py` and type the following: ```python if UserInput in User_Inputs: index = User_Inputs.index(UserInput) print(ChatBot_Name + __Responses[index]) ``` Is the LIV thing making sense to you? If not I will explain it now, skip this if you understand it So basically I am using the LIV, to tell the ChatBot how to respond to user input. Look at this and you might understand. In the lists we have two different, items. `hi`, `hello` The easiest way to look at this is by understanding that they are in the same position just a different list. Here is a visual ['hi'] | 0 ['Hello.'] They match up with the same index that is why I can print the index of `User_Inputs`, through `__Responses`. Now here is the finished output: ![Screenshot 2019-02-26 at 8.38.51 AM](https://storage.googleapis.com/replit/images/1551188357482_f1285e9a35d77c937492742df8e7b616.pn) If you have any questions then post them in the comments. Stay tuned for "An Advanced ChatBot [Advanced, Python]", I will show you how to have your bot scan User Input for Keywords!. Keep coding, Christian Thone @ChristianThone
18
posted by ChristianThone (33) 3 months ago
โ–ฒ
47
3D graphics, a beginners mind.
# Preface In this tutorial I would like to show how 3d graphics is done today, why it's important, and how it will change the way you see 3d graphics applications. To better understand, we'll end up creating a 3d engine with Python. # Requirements I expect you to be familiar with Python, if you understand what `class` means you're probably qualified in this department. I also expect you to understand what the terms fov (field of view), vertex, mesh..etc. mean. # But 3d graphics is hard! No, it's not. This is an awesome area of programming you'll be able to show to your friends, there *will* be math(s) involved, so strap in, but it'll all be explained. If there are aspects you do not understand, simply copy my solution. # Fundamentals To start, let's go through the basic building blocks. Imagine we have a simple object, a cube. ![blender_2018-10-24_10-42-00](https://image.ibb.co/b5RdgV/blender-2018-10-24-10-42-00.png) There's more going on under the hood, this cube is made up of two things, *vertexes* and *triangles*. Vertexes are essentially points in 3d space. Look around your room, and imagine a speck of dust, a single point in 3d space. Triangles are, well just triangles, normal 2d flat triangles. However their three points are connected to specific vertexes. Let's look at the vertexes. ![blender_2018-10-24_10-43-32](https://image.ibb.co/dtgpoA/blender-2018-10-24-10-43-32.png) On the above image of a cube, you can see there are eight points, these are the points which make up the cube. In memory, these points each have a 3d coordinate: X, Y, Z axis. however when we go to *render* the cube, we map each 3d coordinate to 2d screen space. And the way we do that is surprisingly simple. Next, let's look at the triangles. ![blender_2018-10-24_10-43-33](https://image.ibb.co/fMqh8A/blender-2018-10-24-10-43-33.png) As you can see, a triangle is now connected to three of the points. Do this 12(*) times and you'll get a cube. *: A cube is made up of 6 faces, however to make a face with a triangle, you must use two triangles, so it ends up being 12 triangles. # Enough "fundamentals", more coding! Alright, now that we understand the basic structure for rendering 3d shapes. Let's get more technical. We'll be doing this in `Python (with Turtle)`. First, we import Turtle, I will assume you already know how to use Turtle and are familiar with it's functionality. In short, it's just a graphics library aimed at kids learning how to code with graphics, and making flowers and all sorts of things... Except we'll be going much further than flowers. ```python import turtle ``` Next we need to store our object data. We need to store all our vertexes and triangles. ```python VERTEXES = [(-1, -1, -1), ( 1, -1, -1), ( 1, 1, -1), (-1, 1, -1), (-1, -1, 1), ( 1, -1, 1), ( 1, 1, 1), (-1, 1, 1)] TRIANGLES = [(0, 1, 2)] ``` For now, we only have one triangle connected to the first three points. # Our basic main loop We want to simulate a normal graphics library with turtle. Our program will follow this structure: ```python # Create turtle, pointer = turtle.Turtle() # Turn off move time, makes drawing instant, turtle.tracer(0, 0) pointer.up() while True: # Clear screen, pointer.clear() # Draw, # ... # Update, turtle.update() ``` # Rendering Alright, now we need to somehow map these 3d vertex coordinates to 2d screen coordinates. To do this, let's use the *Perspective Formula*. Before we dive into the details of what exactly this formula does, let's start with an observation. Place an object in front of you, for instance a cup. As you move away, the cup shrinks; now this is all very obvious, but it is an essential property of 3d space we must consider. When we're creating a 3d engine, what we're doing is simulating this observation. When we move away from our objects, that is - the Z axis, we're essentially *converging* the X and Y axis toward zero. Look at this front-view of a cube, you can see the back vertexes are closer to the center (zero). ![blender_2018-10-24_19-01-34](https://image.ibb.co/kzOfvq/blender-2018-10-24-19-01-34.png) # So what is this "formula"? ```python f = field_of_view / z screen_x = x * f screen_y = y * f ``` Where x, y, z are vertex coordinates. We can simplify this to: ```python f = fov / z sx, sy = x * f, y * f ``` Easy right? So let's add `FOV` at the top of the file: ```python FOV = 100 ``` # Drawing the points Let's iterate through each vertex: ```python # Draw, for vertex in VERTEXES: # Get the X, Y, Z coords out of the vertex iterator, x, y, z = vertex # Perspective formula, f = FOV / z sx, sy = x * f, y * f # Move to and draw point, pointer.goto(sx, sy) pointer.dot(3) ``` What we get is: ![chrome_2018-10-24_19-45-21](https://image.ibb.co/kONUoA/chrome-2018-10-24-19-45-21.png) But where are our four other points from before? The ones behind? The issue is we're inside the cube, we need to move the camera out. # The camera Alright, I won't go into the camera in this tutorial, you can look at my repl at the bottom to see how to properly implement a 3d engine, but we're taking baby steps here. When we think of moving the camera, we think of the camera object moving, simple right? Well that's not easy to implement in a rasterized renderer. However what's easier is to move the *world* around it. Think about it, either you can move the camera, or move the world; it's the same effect. As it turns out, it's a lot easier to offset the vertex positions than somehow change the perspective formula to equate the position; it would be a whole lot more complex. So quickly solve this, let's move the camera out: ```python # Perspective formula, z += 5 f = FOV / z sx, sy = x * f, y * f ``` ![chrome_2018-10-24_19-52-05](https://image.ibb.co/ceSJgV/chrome-2018-10-24-19-52-05.png) And adjust the `FOV` to say, `400`. ![chrome_2018-10-24_19-53-04](https://image.ibb.co/i62jMV/chrome-2018-10-24-19-53-04.png) Nice! # Drawing triangles To draw triangles, consider this code. By this point you should be able to understand it: ```python # Draw, for triangle in TRIANGLES: points = [] for vertex in triangle: # Get the X, Y, Z coords out of the vertex iterator, x, y, z = VERTEXES[vertex] print(x, y, z) # Perspective formula, z += 5 f = FOV / z sx, sy = x * f, y * f # Add point, points.append((sx, sy)) # Draw trangle, pointer.goto(points[0][0], points[0][1]) pointer.down() pointer.goto(points[1][0], points[1][1]) pointer.goto(points[2][0], points[2][1]) pointer.goto(points[0][0], points[0][1]) pointer.up() ``` # Rotation To rotate our object, we'll be using the *Rotation Matrix*. It sounds scary, right? If you're familiar with linear algebra, you should already know this, but the rotation matrix is commonly defined as: ``` [x'] = [cos(0), -sin(0)] [y'] = [sin(0), cos(0)] ``` *using `0` as theta* I won't go into detail of the matrix. If you're unfamiliar, feel free to either research or copy & paste. To implement this, we'll first need the `math` library: ```python from math import sin, cos ``` Let's make a function to rotate: ```python def rotate(x, y, r): s, c = sin(r), cos(r) return x * c - y * s, x * s + y * c ``` Then let's place this before we do our perspective formula calculations: ```python # Rotate, x, z = rotate(x, z, 1) ``` As you can see the triangle is now rotated: ![chrome_2018-10-24_20-21-51](https://image.ibb.co/n60tFq/chrome-2018-10-24-20-21-51.png) Let's make the rest of the triangles: ```python TRIANGLES = [ (0, 1, 2), (2, 3, 0), (0, 4, 5), (5, 1, 0), (0, 4, 3), (4, 7, 3), (5, 4, 7), (7, 6, 5), (7, 6, 3), (6, 2, 3), (5, 1, 2), (2, 6, 5) ] ``` ![chrome_2018-10-24_20-23-06](https://image.ibb.co/k3Knaq/chrome-2018-10-24-20-23-06.png) Awesome! Let's initialize a counter at the start of the file: ```python counter = 0 ``` and increment this at the end of every loop: ```python # Update, turtle.update() counter += 0.025 ``` And replace our rotation function: ```python x, z = rotate(x, z, counter) ``` It's rotating, awesome! To rotate on the X, Y and Z axis: ```python x, z = rotate(x, z, counter) y, z = rotate(y, z, counter) x, y = rotate(x, y, counter) ``` We're done! # Complete code Before you read, I recommend you do read through the above, I know it's easier to just skip down to the bottom for the solutions. However, if you're here after reading through the above, feel free to post `Full read` in the comments as a token of my respect, and feel free to copy this code =) ```python from math import sin, cos import turtle VERTEXES = [(-1, -1, -1), ( 1, -1, -1), ( 1, 1, -1), (-1, 1, -1), (-1, -1, 1), ( 1, -1, 1), ( 1, 1, 1), (-1, 1, 1)] TRIANGLES = [ (0, 1, 2), (2, 3, 0), (0, 4, 5), (5, 1, 0), (0, 4, 3), (4, 7, 3), (5, 4, 7), (7, 6, 5), (7, 6, 3), (6, 2, 3), (5, 1, 2), (2, 6, 5) ] FOV = 400 # Create turtle, pointer = turtle.Turtle() # Turn off move time, makes drawing instant, turtle.tracer(0, 0) pointer.up() def rotate(x, y, r): s, c = sin(r), cos(r) return x * c - y * s, x * s + y * c counter = 0 while True: # Clear screen, pointer.clear() # Draw, for triangle in TRIANGLES: points = [] for vertex in triangle: # Get the X, Y, Z coords out of the vertex iterator, x, y, z = VERTEXES[vertex] # Rotate, x, z = rotate(x, z, counter) y, z = rotate(y, z, counter) x, y = rotate(x, y, counter) # Perspective formula, z += 5 f = FOV / z sx, sy = x * f, y * f # Add point, points.append((sx, sy)) # Draw trangle, pointer.goto(points[0][0], points[0][1]) pointer.down() pointer.goto(points[1][0], points[1][1]) pointer.goto(points[2][0], points[2][1]) pointer.goto(points[0][0], points[0][1]) pointer.up() # Update, turtle.update() counter += 0.025 ``` # Conclusion If you want to see an expanded and better written version: https://repl.it/@CoolqB/3D-Engine If there's demand I will perhaps dive into shading, lighting, culling, clipping and even texturing. If you've got any questions, fire away in the comments. Good luck!
5
posted by CoolqB (100) 7 months ago
โ–ฒ
58
Game Tutorial: Canyon Runner
Hey everyone, I made a canyon runner game (https://repl.it/@ericqweinstein/EverlastingEmbellishedDevelopments) and wrote up a tutorial for it here: https://medium.com/@eric.q.weinstein/canyon-runner-repl-it-tutorial-cdc6208d3358 Hope you like it!
26
posted by ericqweinstein (187) 9 months ago