<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Gabe Romualdo</title>
    <description>The latest articles on Forem by Gabe Romualdo (@gaberomualdo).</description>
    <link>https://forem.com/gaberomualdo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F91986%2Fa13fcbe8-d29b-4f9d-9b07-04625d756cae.jpg</url>
      <title>Forem: Gabe Romualdo</title>
      <link>https://forem.com/gaberomualdo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/gaberomualdo"/>
    <language>en</language>
    <item>
      <title>Random Seed in JavaScript and Node.js</title>
      <dc:creator>Gabe Romualdo</dc:creator>
      <pubDate>Fri, 26 Mar 2021 05:13:43 +0000</pubDate>
      <link>https://forem.com/gaberomualdo/random-seed-in-javascript-and-node-js-5gf4</link>
      <guid>https://forem.com/gaberomualdo/random-seed-in-javascript-and-node-js-5gf4</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Random seed is a method of initializing random number generators using an initial seed value. Random generators with the same seed will output the same pseudo-random results.&lt;/p&gt;

&lt;p&gt;I found this method to be particularly useful when developing a game I'm working on, which has a random 'Daily Challenge'. In this case, random seed can be useful to select a random game using the current date as a seed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;So, here's how to create a random seed in Node.js, using the seedrandom NPM package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In Node.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;seedrandom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;seedrandom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;seedrandom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[your seed here]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;randomNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if you're on the client-side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// On The Browser&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seedrandom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[your seed here]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;randomNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In both of these code snippets, the &lt;code&gt;generator&lt;/code&gt; function will return a new random number each time, given the seed the generator was initialized with. In this case, it will be formatted as a numerical value, although &lt;/p&gt;

&lt;h2&gt;
  
  
  Dependencies
&lt;/h2&gt;

&lt;p&gt;If you're running on Node.js, download the seedrandom package as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install seedrandom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or using Yarn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add seedrandom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're writing client-side code without webpack, you can either download the file from seedrandom's GitHub repository, or use a CDN by adding the following code snippet at the end of your &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdnjs.cloudflare.com/ajax/libs/seedrandom/3.0.5/seedrandom.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Random seed is one of a few features that is present in most major programming languages but is not available out-of-the-box in JavaScript. It can be incredibly useful in a wide array of cases, both on the web and running on the server-side using Node.&lt;/p&gt;

&lt;p&gt;I hope this helps, and thanks for scrolling.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;— Gabriel Romualdo, March 26, 2021&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>An Algorithm to Swap Two Variables Synchronously, Without Creating a Temporary Variable</title>
      <dc:creator>Gabe Romualdo</dc:creator>
      <pubDate>Wed, 24 Mar 2021 02:19:34 +0000</pubDate>
      <link>https://forem.com/gaberomualdo/an-algorithm-to-swap-two-variables-synchronously-without-creating-a-temporary-variable-1320</link>
      <guid>https://forem.com/gaberomualdo/an-algorithm-to-swap-two-variables-synchronously-without-creating-a-temporary-variable-1320</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Let's say you want to swap the values of two integer variables, &lt;code&gt;a&lt;/code&gt;, and &lt;code&gt;b&lt;/code&gt;. Simply setting &lt;code&gt;a&lt;/code&gt; equal to &lt;code&gt;b&lt;/code&gt; and then &lt;code&gt;b&lt;/code&gt; equal to &lt;code&gt;a&lt;/code&gt; does not work, since &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; would just end up both equaling the initial value of &lt;code&gt;b&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# doesn't work (both a and b end up equaling b):
&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, typically, you'd create another variable — let's call it &lt;code&gt;c&lt;/code&gt; — and set that variable to the value of &lt;code&gt;a&lt;/code&gt;, and then do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# the simplest solution, with a temporary variable:
&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is very simple, but the extra variable is not actually necessary.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that some programming languages, for example Python, provide the ability to swap two variables in a single line, like &lt;code&gt;a, b = b, a&lt;/code&gt;. I will explain how to swap two variables without a temporary variable without utilizing this feature.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Algorithm
&lt;/h2&gt;

&lt;p&gt;By summing the two variables and adding a few subtraction operations, this same swapping operation can be done without a temporary variable, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To see that this works, let's test it out with &lt;code&gt;a = 100&lt;/code&gt; and &lt;code&gt;b = 5&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="c1"&gt;# a = 100 + 5 = 105
&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="c1"&gt;# b = 105 - 5 = 100
&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="c1"&gt;# a = 105 - 100 = 5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see, after running these operations, &lt;code&gt;a = 5&lt;/code&gt; and &lt;code&gt;b = 100&lt;/code&gt;, so the values were swapped, as expected.&lt;/p&gt;

&lt;p&gt;This can also be similarly done with multiplication and division, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This version is generally less efficient because most (if not all) programming languages take longer to calculate products and quotients in comparison to sums and differences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Overall, this is an interesting algorithm that can be used in programs where you are swapping two integer values. Since it only saves a very small amount of space by not creating the temporary variable, it is not particularly useful in smaller projects and programs. However, on a larger scale when working with millions of variables and values at a time, and you'd like to save as much space and storage as possible, this can be useful.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this article and found this to be an interesting algorithm.&lt;/p&gt;

&lt;p&gt;Thanks for scrolling.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;— Gabriel Romualdo, March 23, 2021&lt;/em&gt;&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>python</category>
    </item>
    <item>
      <title>How to Set Up Rate Limiting and Rate Slowing Down in Express.js</title>
      <dc:creator>Gabe Romualdo</dc:creator>
      <pubDate>Tue, 12 Jan 2021 01:27:17 +0000</pubDate>
      <link>https://forem.com/gaberomualdo/rate-limiting-and-rate-slowing-down-in-express-js-in-3-minutes-1ea9</link>
      <guid>https://forem.com/gaberomualdo/rate-limiting-and-rate-slowing-down-in-express-js-in-3-minutes-1ea9</guid>
      <description>&lt;p&gt;&lt;strong&gt;Rate limiting&lt;/strong&gt; is the process of preventing repeated requests to a server in effort to remove spam requests. Typically, a limit is set, such as 200 requests to the server per minute, and any IP address that exceeds that limit will be blocked from making requests for a set period of time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7zdVx6eD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/rate-limiting-and-rate-slowing-down-in-expressjs-in-3-minutes/ratelimit.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7zdVx6eD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/rate-limiting-and-rate-slowing-down-in-expressjs-in-3-minutes/ratelimit.jpg" alt="Rate Limiting Visualization" width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rate slowing down&lt;/strong&gt; is the process of slowing down server responses to an IP that has been sending too many requests. For example, the slow down limit could be set to 200 requests per minute, and an extra 2.5 seconds more response time could be added for each request that exceeds the limit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cio9Gwmd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/rate-limiting-and-rate-slowing-down-in-expressjs-in-3-minutes/rateslowdown.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cio9Gwmd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/rate-limiting-and-rate-slowing-down-in-expressjs-in-3-minutes/rateslowdown.jpg" alt="Rate Slowing Down Visualization" width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both of these methods of preventing spam requests are common can be an essential feature to the server or API of many projects. In this article, I'll explain how rate limiting and rate slowing can be done  with Express.js in Node, and I'll discuss some of the use cases and differences between both of these techniques.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rate Limiting in Express
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install the express-rate-limit package
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install express-rate-limit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add express-rate-limit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Set a rate limit and use it in an Express app
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rateLimiter&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express-rate-limit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;trust proxy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// use this line if you’re using a proxy (Heroku, DigitalOcean, etc.); so req IPs are the client’s IP, not the IP of the proxy service&lt;/span&gt;

&lt;span class="c1"&gt;// set a rate limit of 200 reqs/min&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rateLimit&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nf"&gt;rateLimiter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="c1"&gt;// the rate limit in reqs&lt;/span&gt;
    &lt;span class="na"&gt;windowMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// time where limit applies&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// use the rate limit in your Express app&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rateLimit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Rate Slowing Down in Express
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install the express-slow-down package
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install express-slow-down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add express-slow-down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Configure rate slow down and use it in an Express app
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rateSpeedLimiter&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express-slow-down&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;trust proxy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// use this line if you’re using a proxy (Heroku, DigitalOcean, etc.); so req IPs are the client’s IP, not the IP of the proxy service&lt;/span&gt;

&lt;span class="c1"&gt;// allow 200 reqs/min, reqs after that are delayed by 2500ms&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rateSpeedLimit&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nf"&gt;rateSpeedLimiter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;delayAfter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="c1"&gt;// slow down limit (in reqs)&lt;/span&gt;
    &lt;span class="na"&gt;windowMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// time where limit applies&lt;/span&gt;
    &lt;span class="na"&gt;delayMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2500&lt;/span&gt; &lt;span class="c1"&gt;// slow down time&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// use the rate slow down in your Express app&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rateSpeedLimit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Rate Limiting vs Rate Slowing Down
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The case for rate limiting:&lt;/strong&gt; first, rate limiting is generally more common, especially in production. Once an effective rate limit has been chosen, rate limiting is a clear way to block malicious and unwanted requests. Rate limiting is also useful for public APIs. People that offer APIs often provide a rate limit for users without an API key, or users who haven’t paid a fee for a certain number of requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The case for rate slowing down:&lt;/strong&gt; rate slowing down is a more lenient approach on preventing spam requests. It can be more effective in cases where it is not ideal to outright block particular users, or if there are very rare cases where the rate limit could be exceeded, by search engine scrapers and spiders, for example.&lt;/p&gt;

&lt;p&gt;Overall, rate limiting is a stricter and more common way to prevent spam requests, whereas rate slowing down provides a more lenient approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope this article helps in understanding how to implement rate limiting and rate slowing down in Express.js, and what the use cases for both methods are.&lt;/p&gt;

&lt;p&gt;Thanks for scrolling.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;— Gabriel Romualdo, January 11, 2021&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>express</category>
    </item>
    <item>
      <title>Programs to Compute Trig Functions in Python, JavaScript, &amp; Perl (with Maclaurin Series)</title>
      <dc:creator>Gabe Romualdo</dc:creator>
      <pubDate>Thu, 31 Dec 2020 21:23:17 +0000</pubDate>
      <link>https://forem.com/gaberomualdo/three-quick-programs-to-compute-trig-functions-in-python-javascript-perl-with-maclaurin-series-4ce9</link>
      <guid>https://forem.com/gaberomualdo/three-quick-programs-to-compute-trig-functions-in-python-javascript-perl-with-maclaurin-series-4ce9</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Have you ever wondered how your computer calculates certain mathematical functions, like division, or trigonometric functions like sine or cosine? Well, for some of these mathematical functions, there exist useful formulas to calculate very accurate results pretty easily. For sine and cosine, one commonly used formula looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fxtrp.io%2Fapi%2Fcontent%2Fstatic_files%2Fthree-quick-programs-to-compute-trig-functions-in-python-javascript-perl-with-maclaurintaylor-series%2Fsinseries.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fxtrp.io%2Fapi%2Fcontent%2Fstatic_files%2Fthree-quick-programs-to-compute-trig-functions-in-python-javascript-perl-with-maclaurintaylor-series%2Fsinseries.jpg" alt="Maclaurin Series of sin(x)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And for cosine:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fxtrp.io%2Fapi%2Fcontent%2Fstatic_files%2Fthree-quick-programs-to-compute-trig-functions-in-python-javascript-perl-with-maclaurintaylor-series%2Fcosseries.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fxtrp.io%2Fapi%2Fcontent%2Fstatic_files%2Fthree-quick-programs-to-compute-trig-functions-in-python-javascript-perl-with-maclaurintaylor-series%2Fcosseries.jpg" alt="Maclaurin Series of cos(x)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that the input of each function is in radians, not degrees.&lt;/p&gt;

&lt;p&gt;The series used in both formulas is called a &lt;a href="https://mathworld.wolfram.com/TaylorSeries.html" rel="noopener noreferrer"&gt;Maclaurin series&lt;/a&gt; (a type of &lt;a href="https://mathworld.wolfram.com/MaclaurinSeries.html" rel="noopener noreferrer"&gt;Taylor series&lt;/a&gt;), and can be derived from the sine and cosine functions with a series expansion. &lt;/p&gt;

&lt;h2&gt;
  
  
  How the Programs Work
&lt;/h2&gt;

&lt;p&gt;I've written programs to implement these two computations in three major scripting languages: Python, JavaScript, and Perl. These programs do not include any built-in trig functions or other utilities except the use of the in-built π constant in some cases. All code is CC0 licensed.&lt;/p&gt;

&lt;p&gt;The approach I used creates a generalized function called &lt;code&gt;computeSeries&lt;/code&gt; which takes in x as the number to calculate the sine or cosine of, a starting number in the series (x for sine and 1 for cosine), and the exponent and factorial base in the first term of the series (3 for sine and 2 for cosine).&lt;/p&gt;

&lt;p&gt;In calculating each series, I found that only about 10 terms in the series were needed to get a decently accurate result. &lt;/p&gt;

&lt;p&gt;The programs additionally include utility functions for sine and cosine functions in degrees. The end of each program also includes a few tests of each function, which work as expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  In Python
&lt;/h2&gt;

&lt;p&gt;Feel free to &lt;a href="https://gist.github.com/xtrp/2a5f0d82cff8c14867dabd22e0209933" rel="noopener noreferrer"&gt;view the below code as a GitHub Gist&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pi&lt;/span&gt;

&lt;span class="c1"&gt;# round a number (x) to nearest 10 digits
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rounded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# get the factorial of a number (x)
# factorial(x) is the product of every number from 1 to N inclusive
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# n is the result
&lt;/span&gt;    &lt;span class="c1"&gt;# multiply n by every number from 1 to x inclusive
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;

&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt; get the result of the cos and sin formulas
    where the functions are sin(x radians) or cos(x radians),
    n is the start value (n = x for sin, n = 1 for cos), and
    i_start is the exponent and factorial base in the first term &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;computeSeries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i_start&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="c1"&gt;# iterations is twice the amount of terms to use
&lt;/span&gt;    &lt;span class="n"&gt;multiplier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i_start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i_start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;iterations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="c1"&gt;# i increases by 2 each term
&lt;/span&gt;        &lt;span class="n"&gt;multiplier&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# alternates between addition and subtraction each term
&lt;/span&gt;        &lt;span class="n"&gt;next_term&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# each term is (x^i) / i!
&lt;/span&gt;        &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;multiplier&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;next_term&lt;/span&gt; &lt;span class="c1"&gt;# add or subtract from final result
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;

&lt;span class="c1"&gt;# get sin of x radians
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;rounded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;computeSeries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# get cos of x radians
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;rounded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;computeSeries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# get sin of x degrees
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sinDeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pi&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# get cos of x degrees
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cosDeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pi&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# test the functions
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;# 0.5
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sinDeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;# 0.7071
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sinDeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;# 0.78801
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;# 0.5
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cosDeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;# 0.7071
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cosDeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;# 0.615661
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  In JavaScript
&lt;/h2&gt;

&lt;p&gt;Feel free to &lt;a href="https://gist.github.com/xtrp/a348743383cc80121ab9964ef1f7f1ac" rel="noopener noreferrer"&gt;view the below code as a GitHub Gist&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// round a number (x) to nearest 10 digits&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rounded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// get the factorial of a number (x)&lt;/span&gt;
&lt;span class="c1"&gt;// factorial(x) is the product of every number from 1 to x inclusive&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factorial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// n is the result&lt;/span&gt;
    &lt;span class="c1"&gt;// multiply n by every number from 1 to x inclusive&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/* get the result of the cos and sin formulas
   where the functions are sin(x radians) or cos(x radians),
   n is the start value (x for sin, 1 for cos), and i_start
   is the exponent and factorial base in the first term */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;computeSeries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i_start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// iterations is twice the amount of terms to use&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;multiplier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i_start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;i_start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;iterations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;multiplier&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// alternates between addition and subtraction each iteration&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;next_term&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// each term is (x^i) / i!&lt;/span&gt;
        &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;multiplier&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;next_term&lt;/span&gt; &lt;span class="c1"&gt;// add or subtract from final result&lt;/span&gt;
        &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;// i increases by 2 each term&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// get sin of x radians&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;rounded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;computeSeries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// get cos of x radians&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;rounded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;computeSeries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// get sin of x degrees&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sinDeg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// get cos of x degrees&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cosDeg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// test the functions&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 0.5&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sinDeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 0.7071&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sinDeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 0.78801&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 0.5&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cosDeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 0.7071&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cosDeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 0.615661&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  In Perl
&lt;/h2&gt;

&lt;p&gt;Feel free to &lt;a href="https://gist.github.com/xtrp/d93263899c7107f6a60517a084bf5388" rel="noopener noreferrer"&gt;view the below code as a GitHub Gist&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/perl&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$pi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.14159265358979323&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;# get the factorial of a number (x)&lt;/span&gt;
&lt;span class="c1"&gt;# factorial(x) is the product of every number from 1 to N inclusive&lt;/span&gt;
&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;factorial&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# n is the result&lt;/span&gt;
    &lt;span class="c1"&gt;# multiply n by every number from 1 to x inclusive&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@nums_to_multiply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@nums_to_multiply&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;=begin
get the result of the cos and sin formulas
where the functions are sin(x radians) or cos(x radians),
n is the start value (n = x for sin, n = 1 for cos), and
i_start is the exponent and factorial base in the first term
=cut&lt;/span&gt;
&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;computeSeries&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$ITERATIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# iterations is twice the amount of terms to use&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$i_start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$multiplier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$i_start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$i_start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$ITERATIONS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$multiplier&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# alternates between addition and subtraction each term&lt;/span&gt;
        &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nv"&gt;$multiplier&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;$x**$i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="sr"&gt;/ factorial($i)); # add or subtract ((x^i) /&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;from&lt;/span&gt; &lt;span class="nv"&gt;final&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt;
        &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# i increases by 2 each term&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# get sin of x radians&lt;/span&gt;
&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;mySin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;computeSeries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;# get cos of x radians&lt;/span&gt;
&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;myCos&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;computeSeries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;# get sin of x degrees&lt;/span&gt;
&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;sinDeg&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;mySin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$pi&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;# get cos of x degrees&lt;/span&gt;
&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;cosDeg&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;myCos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$pi&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# test the functions&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pi&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt; &lt;span class="c1"&gt;# 0.5&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sinDeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt; &lt;span class="c1"&gt;# 0.7071&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sinDeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt; &lt;span class="c1"&gt;# 0.78801&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pi&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt; &lt;span class="c1"&gt;# 0.5&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cosDeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt; &lt;span class="c1"&gt;# 0.7071&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cosDeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt; &lt;span class="c1"&gt;# 0.615661&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope this helps in understanding how computers and languages would go about calculating trigonometric functions like sine and cosine. If you'd like to read more about how exactly mathematical formulas used to calculate the trig functions are derived, I would recommend taking a look at &lt;a href="https://www.khanacademy.org/math/old-ap-calculus-bc/bc-series" rel="noopener noreferrer"&gt;the videos on Taylor and Maclaurin series&lt;/a&gt; by Khan Academy.&lt;/p&gt;

&lt;p&gt;These programs are all licensed under the CC0 license, so feel free to use any of the code as you wish, without attribution.&lt;/p&gt;

&lt;p&gt;Thanks for scrolling.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;— Gabriel Romualdo, December 31, 2020&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>javascript</category>
      <category>perl</category>
      <category>math</category>
    </item>
    <item>
      <title>How to Use the HTML5 Gamepad API (with complete examples)</title>
      <dc:creator>Gabe Romualdo</dc:creator>
      <pubDate>Tue, 15 Dec 2020 22:30:29 +0000</pubDate>
      <link>https://forem.com/gaberomualdo/a-complete-guide-to-the-html5-gamepad-api-2k</link>
      <guid>https://forem.com/gaberomualdo/a-complete-guide-to-the-html5-gamepad-api-2k</guid>
      <description>&lt;p&gt;The HTML5 Gamepad API is one of the more exciting HTML5 APIs in my opinion. It allows a website to pretty easily take input from a game controller that is connected to the user’s machine. The API supports &lt;a href="https://gamepad-tester.com/codes"&gt;hundreds of game controllers&lt;/a&gt;, both wireless and wired, including Xbox One controllers and PS4 controllers to name a few.&lt;/p&gt;

&lt;p&gt;Before we begin, note that &lt;strong&gt;the gamepad API may not detect a gamepad until you press a button or move a stick on the controller.&lt;/strong&gt; So, make sure to press some of the buttons when you test any sites or programs that use the Gamepad API.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: controllers and other game inputs are referred to as ‘gamepads’ throughout this article and in the gamepad API documentation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Checking if Your Gamepad is Connected and Troubleshooting Potential Issues
&lt;/h2&gt;

&lt;p&gt;To check if your gamepad is successfully connected, run &lt;code&gt;navigator.getGamepads()&lt;/code&gt; in the JavaScript console and check if the result has a Gamepad object, and is not an array of null elements.&lt;/p&gt;

&lt;p&gt;If your gamepad isn’t working with the API, here are a few things to try:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;check if the device is connected to your machine via bluetooth, USB, or other method&lt;/li&gt;
&lt;li&gt;try restarting your computer or web browser&lt;/li&gt;
&lt;li&gt;try pressing some of the buttons or moving one of the sticks on the controller so that it is detected&lt;/li&gt;
&lt;li&gt;try closing any other games or apps that are using the gamepad&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get a List of Connected Gamepads
&lt;/h2&gt;

&lt;p&gt;The Gamepad API allows up to four gamepads to be connected at once.&lt;/p&gt;

&lt;p&gt;To get an array of connected gamepads, use the &lt;code&gt;navigator.getGamepads()&lt;/code&gt; method. The array is always of length four, where unused gamepad slots are &lt;code&gt;null&lt;/code&gt;. The element(s) of connected gamepad(s) are &lt;code&gt;Gamepad&lt;/code&gt; object(s). Here’s an example value of the &lt;code&gt;navigator.getGamepads()&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getGamepads&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="c1"&gt;// --&amp;gt; [Gamepad Object, null, null, null]&lt;/span&gt;
&lt;span class="c1"&gt;// Here, only one gamepad is connected, and the other three gamepad slots are null.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Before trying to use a the functionality of the Gamepad API, make sure a gamepad is connected using the instructions in the previous section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;Gamepad&lt;/code&gt; Object
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Gamepad&lt;/code&gt; object includes two important properties that are available in the vast majority of all gamepads and controllers: &lt;code&gt;buttons&lt;/code&gt; and &lt;code&gt;axes&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;axes&lt;/code&gt; is an array of length four which represents the position of the left and right sticks in the gamepad. The first two elements in &lt;code&gt;axes&lt;/code&gt; are the (x, y) coordinates of the position of the left stick, whereas the third and fourth elements in &lt;code&gt;axes&lt;/code&gt; are the (x, y) coordinates of the position of the right stick. (x, y) values are numbers between -1 and 1 where the (0, 0) means the stick is has not moved.&lt;/p&gt;

&lt;p&gt;In the horizontal axes (first and third elements in &lt;code&gt;axes&lt;/code&gt;), &lt;code&gt;-1&lt;/code&gt; would indicate the stick is moved fully to the left, and 1 would mean the stick is moved fully to the right. In the vertical axes (second and fourth elements in &lt;code&gt;axes&lt;/code&gt;), &lt;code&gt;-1&lt;/code&gt; would indicate the stick is moved fully to the top, and 1 would mean the stick is moved fully to the bottom. &lt;/p&gt;

&lt;p&gt;Here’s an example value of &lt;code&gt;axes&lt;/code&gt; with explanations in the comments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myGamepad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getGamepads&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// use the first gamepad&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Left stick at (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;myGamepad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;myGamepad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Right stick at (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;myGamepad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;myGamepad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// print axes 10 times per second&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Contrary to buttons in HTML, &lt;strong&gt;event listeners cannot be added to gamepad buttons&lt;/strong&gt;. Instead, you can check if a button is currently pressed by using the boolean &lt;code&gt;pressed&lt;/code&gt; property in the element in the &lt;code&gt;buttons&lt;/code&gt; array.&lt;/p&gt;

&lt;p&gt;Here’s a list of button indexes are their Xbox and PS4 Equivalents in the HTML5 Gamepad API:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Index&lt;/th&gt;
&lt;th&gt;Button &lt;code&gt;.pressed&lt;/code&gt; Code&lt;/th&gt;
&lt;th&gt;Button on Xbox&lt;/th&gt;
&lt;th&gt;Button on PlayStation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[0].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[1].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[2].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;Square&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[3].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Triangle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[4].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;LB&lt;/td&gt;
&lt;td&gt;L1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[5].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;RB&lt;/td&gt;
&lt;td&gt;R1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[6].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;LT&lt;/td&gt;
&lt;td&gt;L2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[7].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;RT&lt;/td&gt;
&lt;td&gt;R2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[8].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show Address Bar&lt;/td&gt;
&lt;td&gt;Share&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[9].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show Menu&lt;/td&gt;
&lt;td&gt;Options&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[10].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Left Stick Pressed&lt;/td&gt;
&lt;td&gt;Left Stick Pressed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[11].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Right Stick Pressed&lt;/td&gt;
&lt;td&gt;Right Stick Pressed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[12].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Directional Up&lt;/td&gt;
&lt;td&gt;Directional Up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[13].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Directional Down&lt;/td&gt;
&lt;td&gt;Directional Down&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[14].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Directional Left&lt;/td&gt;
&lt;td&gt;Directional Left&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[15].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Directional Right&lt;/td&gt;
&lt;td&gt;Directional Right&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gamepad.buttons[16].pressed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Xbox Light-Up Logo&lt;/td&gt;
&lt;td&gt;PlayStation Logo&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here's an example of checking if Button One (A on Xbox, X on PS4) is pressed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myGamepad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getGamepads&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// use the first gamepad&lt;/span&gt;

&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Is Button One Pressed? &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;myGamepad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buttons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;pressed&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// check 10 times per second if the button one is pressed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Detect When a Gamepad Has Been Connected
&lt;/h2&gt;

&lt;p&gt;The name of the event when a gamepad has been connected to the user’s machine is &lt;code&gt;gamepadconnected&lt;/code&gt;. The event argument that is passed into the event function includes a &lt;code&gt;gamepad&lt;/code&gt; property, which is a &lt;code&gt;Gamepad&lt;/code&gt; object for the gamepad the has been connected.&lt;/p&gt;

&lt;p&gt;Instead of accessing this gamepad directly, it is more common to get the index of this gamepad in the &lt;code&gt;navigator.getGamepads()&lt;/code&gt; array by using the &lt;code&gt;Gamepad.index&lt;/code&gt;. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// global gamepad object&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;gamepadIndex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gamepadconnected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;gamepadIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gamepad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// now print the axes on the connected gamepad, for example: &lt;/span&gt;
&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gamepadIndex&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// a gamepad is connected and has an index&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myGamepad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getGamepads&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="nx"&gt;gamepadIndex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Left stick at (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;myGamepad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;myGamepad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Right stick at (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;myGamepad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;myGamepad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// print axes 10 times per second&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A More Complicated Example
&lt;/h2&gt;

&lt;p&gt;Here's an example program that displays which buttons on a controller are pressed at a given time. Try running this code and pressing buttons on your gamepad; you should see that the indexes of the buttons that are pressed is displayed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;No Controller Connected&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;// global gamepad object&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;gamepadIndex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gamepadconnected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;gamepadIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gamepad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gamepadIndex&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// a gamepad is connected and has an index&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myGamepad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getGamepads&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="nx"&gt;gamepadIndex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// reset page&lt;/span&gt;
        &lt;span class="nx"&gt;myGamepad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buttons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pressed&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;isPressed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buttonIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isPressed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// button is pressed; indicate this on the page&lt;/span&gt;
                &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;h1&amp;gt;Button &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;buttonIndex&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is pressed&amp;lt;/h1&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// print buttons that are pressed 10 times per second&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Browser Support
&lt;/h2&gt;

&lt;p&gt;The HTML5 Gamepad API has complete support in most modern web browsers today. However, there are a few browsers that don't yet support it as of December 2020, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IE (11)&lt;/li&gt;
&lt;li&gt;Opera Mini&lt;/li&gt;
&lt;li&gt;Opera Mobile&lt;/li&gt;
&lt;li&gt;Android Browser&lt;/li&gt;
&lt;li&gt;KaiOS Browser&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more up-to-date information on browser support, see the &lt;a href="https://caniuse.com/gamepad"&gt;Gamepad API's CanIUse Page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To check if the browser supports the Gamepad API in JavaScript, the following code can be used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hasGamepadAPI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;getGamepads&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope this helps in learning how to use the HTML5 Gamepad API. While the API is not yet widely used in online games at the moment, it can still be useful for a number of projects and can be fun to try out.&lt;/p&gt;

&lt;p&gt;Thanks for scrolling.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;— Gabriel Romualdo, December 15, 2020&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>html</category>
    </item>
    <item>
      <title>How to Schedule Cronjobs in Python</title>
      <dc:creator>Gabe Romualdo</dc:creator>
      <pubDate>Sat, 12 Dec 2020 22:52:11 +0000</pubDate>
      <link>https://forem.com/gaberomualdo/how-to-schedule-cronjobs-in-python-370i</link>
      <guid>https://forem.com/gaberomualdo/how-to-schedule-cronjobs-in-python-370i</guid>
      <description>&lt;p&gt;Cronjobs are tasks that can be run periodically, such as every five minutes, or every day at midnight, or even every Friday at noon.&lt;/p&gt;

&lt;p&gt;Cronjobs have a number of different use cases, and are widely used in many notable codebases.&lt;/p&gt;

&lt;p&gt;Many hosting servers have existing ways to set up cronjobs, but if you don't have that capability, you may want to go for a different solution.&lt;/p&gt;

&lt;p&gt;I'll explain how you would go about creating cronjobs in Python, in which a Python function, program, or command can be run periodically, whether that be every day, every few minutes, or even every month or year.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check if you have Python 3 installed:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the following command does not yield a version number, &lt;a href="https://www.python.org/downloads/"&gt;download Python 3 from python.org&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 -V
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Install the &lt;code&gt;schedule&lt;/code&gt; package from Pypi&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Run this command to install the &lt;code&gt;schedule&lt;/code&gt; package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install schedule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if you're using &lt;code&gt;pip3&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip3 install schedule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Set up and run a cronjob with the &lt;code&gt;.do&lt;/code&gt; method&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To schedule a cronjob, use the &lt;code&gt;.do&lt;/code&gt; method combined with the &lt;code&gt;.every&lt;/code&gt; method and others to choose when the cronjob should be run.&lt;/p&gt;

&lt;p&gt;The methods for scheduling cronjobs are pretty intuitively named, and more information on them can be found on &lt;a href="https://pypi.org/project/schedule/"&gt;the &lt;code&gt;schedule&lt;/code&gt; package documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After setting up your cronjob(s), create an infinite loop to run the cronjob(s) that are scheduled.&lt;/p&gt;

&lt;p&gt;You can also schedule multiple cronjobs if you'd like by adding them with the &lt;code&gt;.do&lt;/code&gt; method, just like how the initial cronjob was created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;schedule&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sleep&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cronjob&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, World!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# create the cronjob
&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cronjob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# runs cronjob every 5 minutes
&lt;/span&gt;
&lt;span class="c1"&gt;# run the cronjob
&lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_pending&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# check to run the cronjob every 10 seconds
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  More &lt;code&gt;.do&lt;/code&gt; Method Examples
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cronjob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# every 15 minutes
&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cronjob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# every 1 hour
&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;07:00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cronjob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# every day at 7:00 AM
&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;18:30&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cronjob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# every other day at 6:30 PM
&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;friday&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;17:00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cronjob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# every Friday at 5:00 PM
&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;minute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:17&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cronjob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# every minute at 17 seconds
&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cronjob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# every 10 seconds
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope this helps. I've found Python cronjobs like these particularly useful in a few of my projects. For example, I use cronjobs to periodically update data on the COVID-19 pandemic for my site &lt;a href="http://covid19.xtrp.io/"&gt;Coronavirus Live Monitor&lt;/a&gt;, and daily cronjobs are used to publish new posts for &lt;a href="http://dailydeveloperjokes.github.io/"&gt;Daily Developer Jokes&lt;/a&gt;, a project of mine which publishes programming humor every day at 8 AM (ET).&lt;/p&gt;

&lt;p&gt;Thanks for scrolling.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;— Gabriel Romualdo, December 12, 2020&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>cronjobs</category>
    </item>
    <item>
      <title>How to Generate the Sierpinski Triangle in Vanilla JavaScript with HTML5 Canvas</title>
      <dc:creator>Gabe Romualdo</dc:creator>
      <pubDate>Sat, 21 Nov 2020 04:15:36 +0000</pubDate>
      <link>https://forem.com/gaberomualdo/how-to-generate-the-sierpinski-triangle-in-vanilla-javascript-with-html5-canvas-239d</link>
      <guid>https://forem.com/gaberomualdo/how-to-generate-the-sierpinski-triangle-in-vanilla-javascript-with-html5-canvas-239d</guid>
      <description>&lt;p&gt;The &lt;a href="https://mathworld.wolfram.com/SierpinskiSieve.html" rel="noopener noreferrer"&gt;Sierpinski triangle&lt;/a&gt; is a famous mathematical figure which presents an interesting computer science problem: how to go about generating it. In this article I'll explain one method of generating the Sierpinski triangle recursively, with an implementation written in Vanilla JavaScript using HTML5 canvas. I'll also explain how to you'd go about downloading the contents of an HTML5 Canvas element as a PNG.&lt;/p&gt;

&lt;p&gt;First, here's what the Sierpinski triangle looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fxtrp.io%2Fapi%2Fcontent%2Fstatic_files%2Fgenerating-the-sierpinski-triangle-in-vanilla-javascript-with-html5-canvas-with-some-mathematical-background%2Fsierpinski-triangle.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fxtrp.io%2Fapi%2Fcontent%2Fstatic_files%2Fgenerating-the-sierpinski-triangle-in-vanilla-javascript-with-html5-canvas-with-some-mathematical-background%2Fsierpinski-triangle.jpg" alt="The Sierpinski Triangle"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Sierpinski Triangle?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Sierpinski Triangle is a Fractal, Making it Naturally Recursive
&lt;/h3&gt;

&lt;p&gt;One initial thing to notice about the Sierpinski triangle is that every triangle is composed of smaller, identical triangles. Those triangles are also made up of even smaller, identical triangles, which are also made up of more triangles, and so on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fxtrp.io%2Fapi%2Fcontent%2Fstatic_files%2Fgenerating-the-sierpinski-triangle-in-vanilla-javascript-with-html5-canvas-with-some-mathematical-background%2Ffractal.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fxtrp.io%2Fapi%2Fcontent%2Fstatic_files%2Fgenerating-the-sierpinski-triangle-in-vanilla-javascript-with-html5-canvas-with-some-mathematical-background%2Ffractal.jpg" alt="Sierpinski Triangle Fractal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This property in which the Sierpinski triangle is made up of identical, scaled-down copies of itself makes it a &lt;a href="https://mathworld.wolfram.com/Fractal.html" rel="noopener noreferrer"&gt;fractal&lt;/a&gt; in mathematics. Fractals are shapes that are made up of scaled down copies of themselves. The Sierpinski triangle is actually arguably one of the most famous fractals that exist, along with &lt;a href="https://mathworld.wolfram.com/PythagorasTree.html" rel="noopener noreferrer"&gt;Pythagoras Trees&lt;/a&gt;, &lt;a href="https://mathworld.wolfram.com/MandelbrotSet.html" rel="noopener noreferrer"&gt;the Mandelbrot set&lt;/a&gt;, and more.&lt;/p&gt;

&lt;p&gt;The fact that fractals are made up of copies of themselves makes them naturally recursive, and it tends to be simpler to programmatically generate fractals recursively as supposed to using an iterative approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Sierpinski Triangle Only Uses Equilateral Triangles
&lt;/h3&gt;

&lt;p&gt;Next, notice how the Sierpinski triangle is made up of a single shape: the equilateral triangle. This is not a coincidence, and it is in fact one of the reasons the Sierpinski triangle is a notable mathematical figure.&lt;/p&gt;

&lt;p&gt;The Sierpinski triangle takes advantage of a property of equilateral triangles: that they are one of the only shapes that can be made up solely by scaled down versions of itself, where a large equilateral triangle can be made by tesselating four equally smaller equilateral triangles. This makes them uniquely positioned to be the centerpiece of simple fractals, since it is intuitive to encompass smaller copies of an equilateral triangle inside a larger one.&lt;/p&gt;

&lt;p&gt;This also makes it possible for fractals based on equilateral triangles, like the Sierpinski triangle, to be composed of only one shape. Other polygon-based fractals that don't use equilateral triangles often include several different shapes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating the Sierpinski Triangle in JavaScript with HTML5 Canvas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setting Up the HTML and Canvas Element
&lt;/h3&gt;

&lt;p&gt;Let's start by setting up the &lt;code&gt;canvas&lt;/code&gt; element and basic HTML markup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Sierpinski Triangle&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;canvas&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"canvas"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"1000"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"1000"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- JavaScript Code Here --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the width and height variables in the canvas represent the inner dimensions of the canvas, not necessarily its size on the page. This means it can be resized in the future to fit different screen sizes, while maintaining its inner dimensions of 1000px by 1000px.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Equilateral Triangles on the Canvas in JavaScript
&lt;/h3&gt;

&lt;p&gt;Since equilateral triangles are the only shape used in the Sierpinski triangle, it makes sense to write a utility function to draw a given equilateral triangle on the canvas at a specified position and of a specified size.&lt;/p&gt;

&lt;p&gt;This function will take in two arguments: the position of the bottom left vertex on the triangle (&lt;code&gt;pos&lt;/code&gt;), and the length of the sides of the triangle (&lt;code&gt;sidelen&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;To create polygons in HTML5 canvas, there are several functions to move to positions on the canvas, draw a path around an area of the canvas, and fill in that area. These include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;context.beginPath()&lt;/code&gt; and &lt;code&gt;context.closePath()&lt;/code&gt; — create and close a path; commonly used with &lt;code&gt;context.fill()&lt;/code&gt; after closing the path&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;context.moveTo(x, y)&lt;/code&gt; — move to a position on the canvas.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;context.lineTo(x, y)&lt;/code&gt; — move to a position on the canvas while drawing a line from the current position.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;context.fill()&lt;/code&gt; — fill the most recent canvas path.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Creating a triangle simply means identifying the positions of the three vertices, drawing a path around those vertices, and filling the drawn area with a color. Identifying the positions of the vertices is pretty intuitive. Below is a visual showing the positions of the vertices. Note that the height of an equilateral triangle is mathematically equal to as &lt;code&gt;sin(Pi/3) * sidelen&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fxtrp.io%2Fapi%2Fcontent%2Fstatic_files%2Fgenerating-the-sierpinski-triangle-in-vanilla-javascript-with-html5-canvas-with-some-mathematical-background%2Fequilateral-triangle.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fxtrp.io%2Fapi%2Fcontent%2Fstatic_files%2Fgenerating-the-sierpinski-triangle-in-vanilla-javascript-with-html5-canvas-with-some-mathematical-background%2Fequilateral-triangle.jpg" alt="Equilateral Triangle Vertex Positions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the positions of the vertices done, here's what the function to create an equilateral triangle on the canvas would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;canvas&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// context variable is used to draw on a 2D plane&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createTriangle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sidelen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginPath&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;moveTo&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// go to the left vertex&lt;/span&gt;

  &lt;span class="c1"&gt;// note that (0,0) in canvas is the top left, so 'up' on the vertical component would use substraction.&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lineTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;sidelen&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;sidelen&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// draw line from left vertex to top vertex&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lineTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;sidelen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// draw line from top vertex to right vertex&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lineTo&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// draw line from right vertex back to left vertex&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;closePath&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// fill triangle&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Implementing an Algorithm to Generate the Sierpinski Triangle
&lt;/h3&gt;

&lt;p&gt;Now that the canvas and HTML has been set up and the &lt;code&gt;createTriangle&lt;/code&gt; utility function has been written, we can start implementing an algorithm to generate the Sierpinski triangle.&lt;/p&gt;

&lt;p&gt;Since fractals are naturally recursive, we'll use a recursive approach to generate the entire triangle.&lt;/p&gt;

&lt;p&gt;First, recall that every triangle in the Sierpinski triangle is made up of three smaller triangles, one on the left, another on the right, and a final one on the top. Each smaller triangle is a copy of the outer triangle, the Sierpinski triangle. So, simply create a smaller Sierpinski triangle inside of each of the three triangles, and then more smaller Sierpinski triangles inside of those, and so on. Technically, the Sierpinski triangle repeats forever, but for visualizations like this, a stopping point should be defined when there have been enough repeats that the smallest triangles are hard to make out. At this point, filling in the smallest triangles acts as an effective substitution of repeating further.&lt;/p&gt;

&lt;p&gt;To create this stopping condition, a variable called &lt;code&gt;depth&lt;/code&gt; can be used. &lt;code&gt;depth&lt;/code&gt; would represent the amount of times the program should continue repeating the fractal. &lt;code&gt;depth&lt;/code&gt; should start at a certain value and decrease for every repeat, and every smaller Sierpinski triangle created. Once &lt;code&gt;depth&lt;/code&gt; reaches zero (the base case), the program would stop and fill in the three triangles instead of continuing to repeat the fractal.&lt;/p&gt;

&lt;p&gt;To create this functionality, let's create a function called &lt;code&gt;createSierpinskiTriangle&lt;/code&gt; which takes the position of the Sierpinski triangle to generate, its side length, and the depth. The function should identify the positions of the three inner triangles, draw them if depth is equal to zero, or call &lt;code&gt;createSierpinskiTriangle&lt;/code&gt; on the three inner triangles if the depth is greater than zero.&lt;/p&gt;

&lt;p&gt;Here's what this would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createSierpinskiTriangle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sidelen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;depth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;innerTriangleSidelen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sidelen&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// side length of inner triangles is half the side length of the outer triangle&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;innerTrianglesPositions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;innerTriangleSidelen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;innerTriangleSidelen&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;innerTriangleSidelen&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// these positions are the same as what was used in the createTriangle function&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;depth&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;innerTrianglesPositions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;trianglePosition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;createTriangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trianglePosition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;innerTriangleSidelen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;innerTrianglesPositions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;trianglePosition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;createSierpinskiTriangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trianglePosition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;innerTriangleSidelen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;depth&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To call the function, draw the Sierpinski triangle at the bottom left of the canvas (&lt;code&gt;(0, 1000)&lt;/code&gt;) with a side length of &lt;code&gt;1000&lt;/code&gt;px (the width of the canvas) and a depth of &lt;code&gt;5&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;createSierpinskiTriangle&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fxtrp.io%2Fapi%2Fcontent%2Fstatic_files%2Fgenerating-the-sierpinski-triangle-in-vanilla-javascript-with-html5-canvas-with-some-mathematical-background%2Fsierpinski-triangle.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fxtrp.io%2Fapi%2Fcontent%2Fstatic_files%2Fgenerating-the-sierpinski-triangle-in-vanilla-javascript-with-html5-canvas-with-some-mathematical-background%2Fsierpinski-triangle.jpg" alt="Recursive Method Result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Try increasing the depth, and you should see that the triangle gets more and more detailed. Increasing the depth by one will result in three times the amount of total triangles to be drawn, so very high depths like 20 might not be performant since the canvas would have to draw 3^20 (~3.5 billion) triangles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Downloading the Generated Triangle From the Canvas as a PNG
&lt;/h3&gt;

&lt;p&gt;Now that we've generated the triangle recursively, one thing you may want to do is download the generated Sierpinski triangle as an image on your computer. Luckily, this is very simple to do in HTML5 Canvas.&lt;/p&gt;

&lt;p&gt;First, the canvas must be converted to a data URL. If you're not familiar with data URLs, here's a simple definition:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A data URL is a URL scheme that allows data and files (images, audio files, etc.) to be respresented in a single URL containing all of the data. For example, if one wanted to include an image on a website, you would add the image to the web server and link to it in the HTML. With data URLs, the data URL contains the contents of the entire file, so it can simply be put into the HTML directly. This is useful in canvas because we want to export the image without it having a specific public URL, and data URLs allow that to be done.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The contents of the &lt;code&gt;canvas&lt;/code&gt; element can be converted to a data URL with the &lt;code&gt;.toDataURL&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Next, let's download the data URL into the user's machine. In HTML, downloading a file is done by clicking a link and specifying the &lt;code&gt;download&lt;/code&gt; attribute. For example, here's how someone would download an image as &lt;code&gt;myimage.png&lt;/code&gt; when the user clicks a link: &lt;code&gt;&amp;lt;a href="image.png" download="myimage.png"&amp;gt;download!&amp;lt;/a&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Downloading a file through JavaScript is as simple as creating a link element with the specified &lt;code&gt;href&lt;/code&gt; and &lt;code&gt;download&lt;/code&gt; attributes, and artificially clicking on it.&lt;/p&gt;

&lt;p&gt;Here's what this would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;downloadCanvasContents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// create link element&lt;/span&gt;
  &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;download&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sierpinski Triangle.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// set download attribute&lt;/span&gt;
  &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toDataURL&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// set the link's URL to the data URL to be downloaded&lt;/span&gt;
  &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// click the element and download on the user's browser&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try running &lt;code&gt;downloadCanvasContents()&lt;/code&gt; in the JavaScript console after the Sierpinski triangle has been generated! An image should be downloaded to your machine with the contents of the &lt;code&gt;canvas&lt;/code&gt; element.&lt;/p&gt;

&lt;p&gt;To create a download button, adding a simple HTML button with the &lt;code&gt;onclick&lt;/code&gt; attribute set to the &lt;code&gt;downloadCanvasContents&lt;/code&gt; function should suffice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"downloadCanvasContents()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Download Generated Sierpinski Triangle&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Code and Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed this article, and found it interesting in generating the Sierpinski triangle with HTML5 canvas. For more mathematical background on the Sierpinski triangle and its history, I would recommend taking a look at the &lt;a href="https://mathworld.wolfram.com/SierpinskiSieve.html" rel="noopener noreferrer"&gt;Sierpinski Triangle Page on Wolfram MathWorld&lt;/a&gt; and the &lt;a href="https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle" rel="noopener noreferrer"&gt;Sierpinski Triangle Wikipedia Page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Feel free to take a look at the &lt;a href="https://github.com/xtrp/sierpinski" rel="noopener noreferrer"&gt;final code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for scrolling.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;— Gabriel Romualdo, November 20, 2020&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>html</category>
      <category>html5canvas</category>
    </item>
    <item>
      <title>Performance of AI Algorithms in Playing Games — Empirical Evidence From Jupiter, My 2048 AI</title>
      <dc:creator>Gabe Romualdo</dc:creator>
      <pubDate>Sun, 11 Oct 2020 18:48:47 +0000</pubDate>
      <link>https://forem.com/gaberomualdo/performance-of-ai-algorithms-in-playing-games-empirical-evidence-from-jupiter-my-2048-ai-5hj4</link>
      <guid>https://forem.com/gaberomualdo/performance-of-ai-algorithms-in-playing-games-empirical-evidence-from-jupiter-my-2048-ai-5hj4</guid>
      <description>&lt;p&gt;I recently worked on an open source &lt;a href="https://jupiter.xtrp.io/"&gt;project called Jupiter&lt;/a&gt;, an online AI written in JavaScript to beat the popular online game &lt;a href="https://play2048.co/"&gt;2048&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jupiter.xtrp.io/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IpMXTt0I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/xtrp/jupiter/master/demo-image.png" alt="Jupiter Screenshot" width="800" height="614"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The AI uses the Monte Carlo Tree Search (MCTS) algorithm, which makes moves based on the results of many simulations of random games, also known as Monte-Carlo simulations.&lt;/p&gt;

&lt;p&gt;I've written &lt;a href="https://dev.to/gaberomualdo/using-the-monte-carlo-tree-search-algorithm-in-an-ai-to-beat-2048-and-other-games-462b"&gt;an article&lt;/a&gt; on how this algorithm works, how it can be implemented, and where MCTS can be useful. I highly recommend reading that article:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/gaberomualdo/using-the-monte-carlo-tree-search-algorithm-in-an-ai-to-beat-2048-and-other-games-462b"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GyiUezp9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/performance-of-ai-algorithms-in-playing-games-empirical-evidence-from-jupiter-my-2048-ai/previousarticlelink.png" alt="Read Prerequisite Article Image" width="528" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's a brief summary of the algorithm that you can feel free to skip if you've read the above article or you understand it already:&lt;/p&gt;




&lt;p&gt;To find the optimal move at any given position, the program conducts a set of simulations for each possible move in that position (ex: &lt;code&gt;left&lt;/code&gt;, &lt;code&gt;right&lt;/code&gt;, &lt;code&gt;up&lt;/code&gt;, or &lt;code&gt;down&lt;/code&gt;). For each set of simulations, the algorithm starts by playing the move for that set first.&lt;/p&gt;

&lt;p&gt;After that, the rest of the game can be played completely randomly until it is over. The algorithm can then gather the total final game scores (sum of all the tiles on the board) of all the simulations, and average them for each set. We can then find the optimal move by optimizing for the highest final game score.&lt;/p&gt;

&lt;p&gt;For example, there could be 50 simulations where the first move was &lt;code&gt;left&lt;/code&gt;, in which the average score for those simulations was 250. Support there were 50 simulations for each of the &lt;code&gt;right&lt;/code&gt;, &lt;code&gt;up&lt;/code&gt;, and &lt;code&gt;down&lt;/code&gt; moves, and the average score for the 50 simulations in each of those was only 225. In this case, the optimal move would be &lt;code&gt;left&lt;/code&gt; since the algorithm optimizes for the move that yields the highest final game score.&lt;/p&gt;




&lt;p&gt;In this article, I'll be analyzing the performance and speed of Jupiter's algorithm with empirical data, and note potential improvements made to the algorithm and its JavaScript implementation on the web.&lt;/p&gt;

&lt;p&gt;Let's start with a few definitions that are relevant to the rest of the article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: how well the AI performs at the end of each game, in which a higher final game score would be better&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt;: how fast the AI performs in real-world speed running on the web in JavaScript, in which a higher speed to perform moves would be better&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Game State:&lt;/strong&gt; a set of tiles on the board which represents the board at a specific time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Game Score:&lt;/strong&gt; the sum of all the tiles on the board&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real Game:&lt;/strong&gt; the game that is being played and shown on the browser, not a simulation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Landmark Score/Tile:&lt;/strong&gt; a high tile or score of a power of two like 512, 1024, 2048, or 4096&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Analyzing the Performance of the Algorithm
&lt;/h2&gt;

&lt;p&gt;I ran 50 trial games with the AI at 200 simulations per move in about 34 minutes (avg. 40.8s/trial), storing data after every move, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current Game Score&lt;/li&gt;
&lt;li&gt;Best Tile in the Board&lt;/li&gt;
&lt;li&gt;Average Score of Simulations &lt;/li&gt;
&lt;li&gt;Average Move Count of Simulations&lt;/li&gt;
&lt;li&gt;Milliseconds Taken to Calculate Optimal Move&lt;/li&gt;
&lt;li&gt;The Move Made&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;The default 200 simulations per move used is meant to be a baseline so that the AI runs a decent speed at all tiers of devices including phones and tablets as well as desktops and laptops. I have personally done runs with 1500 simulations per move and have achieved much better results there while sacrificing speed in the process.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Game Score and Best Tiles
&lt;/h3&gt;

&lt;p&gt;In all of the 50 simulations done, 96% reached at least the 1024 tile, 62% reached at least the 2048 tile and 2% reached the 4096 tile. None of the simulations reached a tile beyond 4096.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DIoshdmc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/performance-of-ai-algorithms-in-playing-games-empirical-evidence-from-jupiter-my-2048-ai/besttile_and_finalscore.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DIoshdmc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/performance-of-ai-algorithms-in-playing-games-empirical-evidence-from-jupiter-my-2048-ai/besttile_and_finalscore.jpg" alt="Best Tile Across All Simulations Chart" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For game score, all trials reached at least 1024, including the two trials which didn't get the 1024 tile itself.&lt;/p&gt;

&lt;p&gt;In fact, there's a clear trend in which games reach a landmark game score like 2048 or 4096, but don't survive long enough to get the tile itself.&lt;/p&gt;

&lt;p&gt;I hypothesize this is because the game begins to get very cluttered with tiles right before a landmark tile is reached. For example, one move before getting 4096, the game board must already include at least 11 tiles: 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, and 2. In this case, the placement of the tiles could not be ideal, or a 4 tile may appear where a 2 tile was needed. As a result, the board could have all the tiles it needs to achieve a landmark tile, but is too cluttered and the game ends up ending before the landmark tile is reached. &lt;/p&gt;

&lt;p&gt;Another trend here is in trials which ended between the 2048 and 4096 game scores. There are several of these and this is likely because of board clutter. The algorithm doesn't have a built-in heuristic for tile placement, so tiles aren't perfectly lined up in increasing order like other strategies use.&lt;/p&gt;

&lt;p&gt;This becomes a problem for very high tiles, depending on the total simulations per move. For 200 simulations per move, it looks like 4096 is the most common to cause cluttering problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Jupiter is Very Different to Other AIs and Strategies
&lt;/h3&gt;

&lt;p&gt;One of the most interesting things about Jupiter's algorithm is that it doesn't follow a particular strategy. Watching Jupiter play 2048, it's hard to see any sort of pattern in its moves, other than the fact that it wins most of the time.&lt;/p&gt;

&lt;p&gt;The most common winning strategy among humans is a system where all tiles are lined up in increasing order along rows, alternating the direction in each row so that tiles can easily be added as new ones appear. Jupiter does not follow this type of strategy; in fact, &lt;strong&gt;it has no built-in strategy or heuristics at all&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I personally see this as an advantage which makes Jupiter a more creative AI. Jupiter's algorithm typically leads to more interesting and less predictable 2048 gameplay than other 2048 AIs or strategies. However, Jupiter's algorithm has a lack of precision that can lead to the issues with board clutter, because tiles are not algorithmically placed in a logical pattern.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2iBXhuL5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/performance-of-ai-algorithms-in-playing-games-empirical-evidence-from-jupiter-my-2048-ai/comparison.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2iBXhuL5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/performance-of-ai-algorithms-in-playing-games-empirical-evidence-from-jupiter-my-2048-ai/comparison.png" alt="Jupiter Compared to Other Algorithms Visualization" width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The common human strategy mentioned also depends on the idea that tiles are concentrated on a particular corner, which results in two of the possible moves (&lt;code&gt;up&lt;/code&gt; and &lt;code&gt;right&lt;/code&gt; in the above visualization) being used much less than their counterparts. Jupiter is not like this, and makes all moves an equal fraction of the time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1IrFGTyQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/performance-of-ai-algorithms-in-playing-games-empirical-evidence-from-jupiter-my-2048-ai/movesmade.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1IrFGTyQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/performance-of-ai-algorithms-in-playing-games-empirical-evidence-from-jupiter-my-2048-ai/movesmade.png" alt="Jupiter Moves Made Across All Trials Graph" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What a Single Trial Game Looks Like
&lt;/h3&gt;

&lt;p&gt;Let's take a look at a single game trial, trial #50, which got to the 4096 tile.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zp5H-W8p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/performance-of-ai-algorithms-in-playing-games-empirical-evidence-from-jupiter-my-2048-ai/trial50.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zp5H-W8p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/performance-of-ai-algorithms-in-playing-games-empirical-evidence-from-jupiter-my-2048-ai/trial50.png" alt="Trial #50 Graph with 200 Simulations Per Move" width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we can see, the current game score is almost linear, with an approximate 2.2 slope. This is because in 2048, a new tile is added after each move. This new tile is typically a 2 tile, but has a 10% chance of being a 4 tile instead. Thus, the expected value of the new tile is 2.2 &lt;code&gt;(2 × 90% + 4 × 10%)&lt;/code&gt;, which increases the game score by an average of 2.2 after every move.&lt;/p&gt;

&lt;p&gt;The average game score of all the simulations is always slightly above the current game score, because random moves incur a few tile combinations and increase the score before the simulated game ends.&lt;/p&gt;

&lt;p&gt;And as noted previously, game score is directly connected to current game move count, where game score can be calculated by multiplying current game move count by 2.2. Therefore, spikes in average move count of simulations occur identically in the average score of simulations as well.&lt;/p&gt;

&lt;p&gt;Notice how all three of these things occur at the same time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increase in best tile&lt;/li&gt;
&lt;li&gt;Spike in average move count of simulations&lt;/li&gt;
&lt;li&gt;Spike in average score of simulations&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;In the graph, average score of simulations is scaled to be much smaller than average move count of simulations, so you may have to look closely to see spikes there.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As we can also see, the game score reaches a landmark before the corresponding landmark tile is actually reached — when the orange best tile line jumps up, the blue game score line has already surpassed the value of the orange best tile line.&lt;/p&gt;

&lt;p&gt;Finally, possibly the most interesting insights we can gain from this graph are from the yellow average move count of simulations variable.&lt;/p&gt;

&lt;p&gt;In the beginning, the average move count starts very high because there are very little tiles on the board, and the ones that are there are tiles 2 or 4. This means that simulations can survive pretty long by just playing randomly.&lt;/p&gt;

&lt;p&gt;As higher tiles are created, the average move count starts getting lower and lower because there is more clutter and therefore a higher chance of the game ending in a shorter period of time.&lt;/p&gt;

&lt;p&gt;The less clutter there is on the board, the higher the average move count is. Clutter is reduced by combining larger and larger tiles.&lt;/p&gt;

&lt;p&gt;As a result of this relationship with tile combination, the amount of board clutter, and thus the average move count, we can see a clear fractal-like repeating shape, in which the average move count spikes up, goes down over time, spikes up again, goes down over time, and repeats.&lt;/p&gt;

&lt;p&gt;These spikes are always when large tiles are created by combining smaller ones. This is corroborated by the fact that several of these spikes occur at the same time as new best tile being created (see 512, 1024, 2048 for example).&lt;/p&gt;

&lt;p&gt;In the middle of each new best tile being created, there is another smaller spike, which we can assume is the tile half of the next best tile. For example, we can see right in the middle of 1024 and 2048 being reached, there is a large spike. This is likely when a new 512 tile was created. Subsequently we can see even smaller spikes between all adjacent spikes, corresponding to tiles being created with even smaller powers of two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Speed Improvements for Running on the Web, in JavaScript
&lt;/h2&gt;

&lt;p&gt;Speed was a key issue I faced while developing Jupiter, particularly because it runs on the web with frontend JavaScript code. Because it runs on the web, I had to make sure it could run well on lower-end devices including phones.&lt;/p&gt;

&lt;p&gt;I made several speed improvements, starting by refactoring code in my 2048 game implementation. I made changes to the gameover checking method and move methods to make them more efficient, resulting in a ~25% increase in speed. One immediate problem I faced was that code was running on the main thread. The main thread is not only responsible for running JavaScript code, but also dealing with various events such as mouse clicks. When other JavaScript code is currently running on the main thread, it can sometimes block events from being picked up and run. To remove this blocking, I had defer code to different threads.&lt;/p&gt;

&lt;p&gt;On the web, this is done by using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API"&gt;Web Workers&lt;/a&gt;. Each Web Worker runs on a separate thread, and I found that the optimal number of Web Workers is typically eight. I divided simulations and tasks among all eight of these workers equally to optimize speed. Concurrency with workers in JavaScript is thankfully very simple and works with message passing, so this took little effort to implement.&lt;/p&gt;

&lt;p&gt;I kept the original implementation without workers in the code to run for browsers like Opera Mini that don't support the Web Workers specification.&lt;/p&gt;

&lt;p&gt;This increased performance greatly. On a mid-tier laptop running on battery power, I was able to run 50 trials of full games on 200 simulations per move in approximately 34 minutes. This meant that I was able to run one full game of 2048 with approximately 1600 moves in about 40.8 seconds on average. This means the AI played ~39 moves per second, with each move taking ~25 ms to calculate.&lt;/p&gt;

&lt;p&gt;Overall, the speed improvements made in both optimizing existing JavaScript code and using Web Workers greatly improved the speed of the program, and allowed it to calculate millions of simulations for hundreds of thousands of moves in just minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed this post, and found it interesting in analyzing performance and improving the speed of Jupiter, my 2048 AI.&lt;/p&gt;

&lt;p&gt;Go check out &lt;a href="https://jupiter.xtrp.io/"&gt;Jupiter&lt;/a&gt; and &lt;a href="https://github.com/xtrp/jupiter"&gt;its source code on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for scrolling.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;— Gabriel Romualdo, October 11, 2020&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>javascript</category>
    </item>
    <item>
      <title>I Built Jupiter – A Machine Learning Based 2048 AI that Runs on the Web</title>
      <dc:creator>Gabe Romualdo</dc:creator>
      <pubDate>Sun, 13 Sep 2020 03:16:00 +0000</pubDate>
      <link>https://forem.com/gaberomualdo/i-built-jupiter-a-machine-learning-based-2048-ai-that-runs-on-the-web-2c6l</link>
      <guid>https://forem.com/gaberomualdo/i-built-jupiter-a-machine-learning-based-2048-ai-that-runs-on-the-web-2c6l</guid>
      <description>&lt;p&gt;Today I'm proud to release my online 2048 AI, &lt;a href="https://jupiter.xtrp.io/"&gt;Jupiter&lt;/a&gt;. Jupiter uses a machine learning method called the Monte Carlo Tree Search (MCTS) algorithm.&lt;/p&gt;

&lt;p&gt;Check it out:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jupiter.xtrp.io/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IpMXTt0I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/xtrp/jupiter/master/demo-image.png" alt="Jupiter Screenshot" width="800" height="614"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Quick Preview of the AI
&lt;/h2&gt;

&lt;p&gt;This is a snippet of some of what you'll see when you go to &lt;a href="https://jupiter.xtrp.io/"&gt;the Jupiter website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--veFWN2Ur--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://xtrp.io/api/content/static_files/jupiter-project-release-my-open-sourced-2048-ai-and-first-machine-learning-project/thumbnail.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--veFWN2Ur--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://xtrp.io/api/content/static_files/jupiter-project-release-my-open-sourced-2048-ai-and-first-machine-learning-project/thumbnail.gif" alt="AI Preview Animated GIF" width="600" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Relevant Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://jupiter.xtrp.io/"&gt;Jupiter (Website)&lt;/a&gt;&lt;/strong&gt; — run the AI on your browser and see realtime AI statistics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/xtrp/jupiter"&gt;Jupiter GitHub Repo and Source Code&lt;/a&gt;&lt;/strong&gt; — check out the code and feel free to submit a PR or issue.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  More About This Project
&lt;/h2&gt;

&lt;p&gt;Jupiter (formerly known as Jacob) started as a small AI project in January 2018. I got the idea of using Monte Carlo simulations and search trees as a method to play 2048 from &lt;a href="https://stackoverflow.com/a/23853848/10007107"&gt;this StackOverflow answer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I wrote a basic clone of what was described in the answer and built on the idea with an interactive console and my own 2048 game implementation, in contrast to the existing open sourced game code used in other AI projects. At this time, Jupiter ran on the main JavaScript thread, and had decent performance and speed: it was able to run ~800 Monte Carlo simulations of possible games per second. Running the game at 200 simulations per move gave roughly 4 moves per second. This amount of simulations reaches the winning 2048 tile about 65-75% of the time.&lt;/p&gt;

&lt;p&gt;In August 2020, I took a look at the project once again and noticed the potential to improve both performance and speed of the AI. I did some more research on Monte Carlo simulations and search trees, notably watching &lt;a href="https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-0002-introduction-to-computational-thinking-and-data-science-fall-2016/lecture-videos/lecture-6-monte-carlo-simulation/"&gt;a great lecture&lt;/a&gt; by MIT Prof. Guttag in MIT's 6.0002 undergraduate course. In the one and a half years since I had first started the project, I'd also learned and used numerous modern JavaScript features, frameworks, and libraries. This put in me the unique position to use these new skills to extend this project vastly from performance, speed, bundle size, and design perspectives.&lt;/p&gt;

&lt;p&gt;So, I spent time refactoring existing code and replacing older algorithms with newer and more performant ones. In particular, I took advantage of modern JavaScript features like &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers"&gt;Web Workers&lt;/a&gt; to differ tasks to new threads and utilize concurrency capabilities. I also added Webpack to the project for the automated speed and bundle size optimizations built into many of its loaders. With new CSS and design skills I had learned over the past one and half years, I built a new design for the site, with a clearer console and mobile responsiveness. And finally, among many other features, I added "tile milestones" to let users know how fast the AI had reached certain tiles in the game.&lt;/p&gt;

&lt;p&gt;With the numerous updates to the project in 2020, Jupiter was now able to run ~2650 simulations of possible games per second. Running the game at 200 simulations per move gave around 13 moves per second. This indicated that &lt;strong&gt;performance had more than tripled&lt;/strong&gt; with the new updates. Moreover, a new addition to the code allowed for performance to grow and scale horizontally by adding Web Workers and threads as general computing speed increases over time.&lt;/p&gt;

&lt;p&gt;All in all, the two year gap in which I learned invaluable frontend development and programming skills allowed me to improve the AI drastically in many areas while maintaining the original, extremely effective Monte Carlo based algorithm which stayed the same throughout the development process.&lt;/p&gt;

&lt;p&gt;I hope you find this project interesting and take the time to check it out!&lt;/p&gt;

&lt;p&gt;If you liked this post, consider following me on DEV.&lt;/p&gt;

&lt;p&gt;Thanks for scrolling.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;— Gabriel Romualdo, September 12, 2020&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>machinelearning</category>
      <category>ai</category>
    </item>
    <item>
      <title>Using the Monte Carlo Tree Search Algorithm in an AI to Beat 2048 (and other games)</title>
      <dc:creator>Gabe Romualdo</dc:creator>
      <pubDate>Sun, 13 Sep 2020 02:13:27 +0000</pubDate>
      <link>https://forem.com/gaberomualdo/using-the-monte-carlo-tree-search-algorithm-in-an-ai-to-beat-2048-and-other-games-462b</link>
      <guid>https://forem.com/gaberomualdo/using-the-monte-carlo-tree-search-algorithm-in-an-ai-to-beat-2048-and-other-games-462b</guid>
      <description>&lt;p&gt;I recently worked on an open source &lt;a href="https://jupiter.xtrp.io/"&gt;project called Jupiter&lt;/a&gt;, an online AI to beat the popular online game &lt;a href="http://play2048.co/"&gt;2048&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Go try out the AI:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jupiter.xtrp.io/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IpMXTt0I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/xtrp/jupiter/master/demo-image.png" alt="Jupiter Screenshot" width="800" height="614"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In writing this AI, I decided to use a machine learning method called the Monte Carlo Tree Search (MCTS) algorithm. Monte Carlo algorithms like the one used in Jupiter have been used in several notable AIs, including DeepMind's &lt;a href="https://deepmind.com/research/case-studies/alphago-the-story-so-far"&gt;AlphaGo&lt;/a&gt;, which famously beat the Go world champion in May 2017.&lt;/p&gt;

&lt;p&gt;In this article, I'll explain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How and why the Monte Carlo method works&lt;/li&gt;
&lt;li&gt;When and where Monte Carlo algorithms can be useful &lt;/li&gt;
&lt;li&gt;How I used the Monte Carlo method in an AI to beat 2048&lt;/li&gt;
&lt;li&gt;How to implement Monte Carlo algorithms in JavaScript and other languages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: I got the idea of using a Monte Carlo method to beat 2048 from &lt;a href="https://stackoverflow.com/a/23853848/10007107"&gt;this StackOverflow answer&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Monte Carlo Method?
&lt;/h2&gt;

&lt;p&gt;The Monte Carlo method is the idea of using a large number of random simulations of an experiment to gain insights into the experiment's end results. Random simulations of an experiment are frequently referred to as &lt;em&gt;Monte Carlo simulations&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For example, let's say that you were flipping a coin, and trying to figure out the probability of the coin landing heads. With the Monte Carlo method, we could simulate 10,000 coin tosses, and calculate the percentage of coins that landed heads.&lt;/p&gt;

&lt;p&gt;Here's what that would look like.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4sKQWlOF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/using-the-monte-carlo-tree-search-algorithm-in-an-ai-to-beat-2048-and-other-games/coinflip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4sKQWlOF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/using-the-monte-carlo-tree-search-algorithm-in-an-ai-to-beat-2048-and-other-games/coinflip.png" alt="Flip Coin Example Graph" width="800" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As can be seen, the result converges to the expected value, 50%. A notable feature of Monte Carlo simulations is that a higher number of simulations is correlated with higher accuracy. For example, if we only performed two simulations, there is a high (25%) probability of heads landing in both simulations, giving a result of 100%. This is very inaccurate in comparison to the expected result of 50%.&lt;/p&gt;

&lt;p&gt;Monte Carlo simulations &lt;strong&gt;work because of the Law of Large Numbers&lt;/strong&gt;, which says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you simulate the same experiment many times, the average of the results should converge to the expected value of the simulation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, Monte Carlo simulations are a way to estimate what will happen in a given experiment &lt;strong&gt;without having to implement any specific algorithms or heuristics&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  When and Where the Monte Carlo Method Can Be Useful
&lt;/h2&gt;

&lt;p&gt;The Monte Carlo method is used in a variety of fields, including game AI development, finance and economics, and evolutionary biology to name a few.&lt;/p&gt;

&lt;p&gt;The Monte Carlo method can be useful in any experiment with a random factor, where end results cannot be predicted algorithmically. For example, in 2048, a new tile at a random location is added after every move, making it impossible to calculate the exact location of upcoming tiles and subsequently the end result of the game as well.&lt;/p&gt;

&lt;p&gt;In these types of experiments, running a large number of Monte Carlo simulations can help get a sense of the average end results, the probability of various events occurring, and the relationship between the variables in the experiment.&lt;/p&gt;

&lt;p&gt;For example, using the Monte Carlo method to in Jupiter allowed me to better understand how variables like starting move, number of moves in a game, and best tile in the board affected the end results of the game.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Used the Monte Carlo Method in Jupiter, an AI to Beat 2048
&lt;/h2&gt;

&lt;p&gt;Let's start with a few definitions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Board and Tiles&lt;/strong&gt;: a 4x4 grid with tiles optionally placed on each grid spot&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Game State&lt;/strong&gt;: a set of tiles on the board which represents the board at a specific time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Game Score&lt;/strong&gt;: the sum of all the tiles on the board&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real Game&lt;/strong&gt;: the game that is being played and shown on the browser, not a simulation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At any given game state, let's assume that four possible moves can be made: left, right, up, or down.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are indeed cases where a certain move is not possible in a given game state. Removing impossible moves can be easily added to the algorithm later.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With the Monte Carlo method, we can run a set of game simulations for every move.&lt;/p&gt;

&lt;p&gt;For each possible move, the program simulates a set of simulations which &lt;strong&gt;start by playing the move for that set first&lt;/strong&gt;. After that, the rest of the game can be played completely randomly until it is over.&lt;/p&gt;

&lt;p&gt;In JavaScript, this algorithm looks something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// assume Game object exists&lt;/span&gt;
&lt;span class="c1"&gt;// assume currentGame variable exists as the real game&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalSimulations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 50 simulations are played for each move &lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;possibleMoves&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;right&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;down&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;up&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;possibleMoves&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// simulations for all four possible starting moves&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;totalSimulations&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;simulation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// create simulation&lt;/span&gt;
    &lt;span class="nx"&gt;simulation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;board&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentGame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;board&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// copy current game state to simulation&lt;/span&gt;
    &lt;span class="nx"&gt;simulation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// make initial move&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;simulation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gameover&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;simulation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;possibleMoves&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// make random moves until simulation game is over&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After all the simulations are completed, the program can gather the total final game scores of all the simulations, and average them for each move. We can then find the optimal move by optimizing for the highest final game score.&lt;/p&gt;

&lt;p&gt;For example, if the simulations which started by playing left had an average final score of 250, whereas the ones which started by playing the other moves had an average final game score of 225, then left is the optimal move.&lt;/p&gt;

&lt;p&gt;In this program, &lt;strong&gt;the optimal move is the one with simulations with the highest average final game score&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note: I could have chosen to optimize for a different value such as the number of moves in the game.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;However, this would actually make no difference in how the algorithm functions, because the number of moves in the game almost exactly predicts the game score. In 2048, the new tile added after each game move is normally a 2 tile, but has a 10% chance of being a 4 tile instead. This means the expected value of the new tile is 2.2 (&lt;code&gt;2 × 90% + 4 × 10%&lt;/code&gt;). The total value of tiles is also preserved after every tile combination (ex: 2 tile combined with another 2 tile gives a 4 tile). As a result, game score can be calculated by multiplying the expected value of the new tile by the number of moves in the game, or with this formula: &lt;code&gt;2.2 × (real game move count + average move count)&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To add this functionality of optimizing for highest score to our current code: add an array of total final scores for the simulations for each possible move, and choose the move with the highest value in that array to play like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;possibleMoves&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;right&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;down&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;up&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalSimulations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;moveSimulationTotalScores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;possibleMoves&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;moveIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// simulations for all four possible starting moves&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;totalSimulations&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;simulation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// create simulation&lt;/span&gt;
    &lt;span class="nx"&gt;simulation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;board&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentGame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;board&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// copy current game state to simulation&lt;/span&gt;
    &lt;span class="nx"&gt;simulation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// make initial move&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;simulation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gameover&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;simulation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;possibleMoves&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// make random moves until simulation game is over&lt;/span&gt;
    &lt;span class="nx"&gt;moveSimulationTotalScores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;moveIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;simulation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getScore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// make best move with highest total simulation scores&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;topScore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;moveSimulationTotalScores&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;topScoreIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;moveSimulationTotalScores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;topScore&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;bestMove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;possibleMoves&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;topScoreIndex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;currentGame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bestMove&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the end, this algorithm is simple to implement given a well-written 2048 game class. In JavaScript, there are a number of performance upgrades that can be made, starting by adding concurrency with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API"&gt;Web Workers&lt;/a&gt; and pruning moves with very low final game scores.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed this post, and found it useful in helping you understand and implement the Monte Carlo method in your own projects.&lt;/p&gt;

&lt;p&gt;Go check out &lt;a href="https://jupiter.xtrp.io/"&gt;Jupiter&lt;/a&gt; and &lt;a href="https://github.com/xtrp/jupiter"&gt;its source code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for scrolling.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;— Gabriel Romualdo, September 12, 2020&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>How to Parse XML in Python</title>
      <dc:creator>Gabe Romualdo</dc:creator>
      <pubDate>Sun, 16 Aug 2020 02:40:27 +0000</pubDate>
      <link>https://forem.com/gaberomualdo/how-to-parse-xml-in-python-3ah4</link>
      <guid>https://forem.com/gaberomualdo/how-to-parse-xml-in-python-3ah4</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;xml.dom&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;minidom&lt;/span&gt;

&lt;span class="n"&gt;parsedXML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;minidom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[your xml here]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;elements_by_tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parsedXML&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;[tagname here]&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# get list of elms with tagname
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements_by_tag&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;firstChild&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nodeValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# print inner text value of an element
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I recently spent a few hours refactoring some of the backend code on my personal website. In changing the backend, I wanted to make sure the refactored code worked the same way as my old code.&lt;/p&gt;

&lt;p&gt;To do this, I wrote a unit test in Python that sent a request to every URL on my site running the old backend code and the corresponding URL with my local server running the new code, to make sure they worked exactly the same.&lt;/p&gt;

&lt;p&gt;As with many other sites, I have a sitemap which lists all of the URLs on the site with their titles and other information for search engines and other bots. Since this sitemap is programmed to output all of the URLs on my site (excluding error pages like the 404 page), this seemed like a perfect way to get a list of URLs on my site to test the new backend code.&lt;/p&gt;

&lt;p&gt;Sitemaps are written in &lt;a href="https://www.w3.org/TR/xml/"&gt;XML&lt;/a&gt;, a language very similar to HTML, with the same tag and element based syntax.&lt;/p&gt;

&lt;p&gt;So, to go about getting all the URLs from my sitemap, I had to get the raw XML from the sitemap, and then parse that XML to get items of a particular tag name (&lt;code&gt;loc&lt;/code&gt; in this case).&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Parse XML with XML.DOM Minidom
&lt;/h2&gt;

&lt;p&gt;To parse the XML, we'll use Python's default &lt;a href="https://docs.python.org/3/library/xml.dom.minidom.html"&gt;xml.dom.minidom&lt;/a&gt; module.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;minidom&lt;/code&gt; module has a handy &lt;code&gt;.parseString&lt;/code&gt; method to parse XML from a Python string. The method returns an object with other methods for getting information from the parsed XML, and selecting various elements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;xml.dom&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;minidom&lt;/span&gt;

&lt;span class="n"&gt;parsedXML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;minidom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
&amp;lt;urlset xmlns=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://www.sitemaps.org/schemas/sitemap/0.9&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;https://gabrielromualdo.com/&amp;lt;/loc&amp;gt;
        &amp;lt;changefreq&amp;gt;weekly&amp;lt;/changefreq&amp;gt;
        &amp;lt;priority&amp;gt;0.9&amp;lt;/priority&amp;gt;
    &amp;lt;/url&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;https://gabrielromualdo.com/about/&amp;lt;/loc&amp;gt;
        &amp;lt;changefreq&amp;gt;monthly&amp;lt;/changefreq&amp;gt;
        &amp;lt;priority&amp;gt;0.6&amp;lt;/priority&amp;gt;
    &amp;lt;/url&amp;gt;
&amp;lt;/urlset&amp;gt;
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can call various functions on the &lt;code&gt;parsedXML&lt;/code&gt; variable to get information from elements in the XML.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Get Elements by Tag Name
&lt;/h2&gt;

&lt;p&gt;Getting elements by tag name from parsed XML in xml.dom.minidom is pretty simple: use the &lt;code&gt;getElementsByTagName&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;For example, in my case I want a list of elements with the tag name of &lt;code&gt;loc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parsedXML&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;loc&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# any tag name in place of 'loc' is valid
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Get the Inner Text of a Particular Element
&lt;/h2&gt;

&lt;p&gt;Now that I had a list of &lt;code&gt;loc&lt;/code&gt; elements, I needed to get text of each of those elements and add those to their own list.&lt;/p&gt;

&lt;p&gt;To get text from an element in xml.dom.minidom, use the &lt;code&gt;firstChild.nodeValue&lt;/code&gt; property of the element, like this: &lt;code&gt;element.firstChild.nodeValue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In my case, here's how I looped through each element and added the text content to a variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parsedXML&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;loc&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;locations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# loop through 'loc' elements
&lt;/span&gt;    &lt;span class="n"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;firstChild&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nodeValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;# get innertext of each element and add to list
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# https://gabrielromualdo.com/ https://gabrielromualdo.com/about/
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In getting the text of an element, the &lt;code&gt;firstChild&lt;/code&gt; property gets the text node from the element, and the &lt;code&gt;nodeValue&lt;/code&gt; property gets the value of that particular text node.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You can see the final source code of this article &lt;a href="https://github.com/xtrp/tutorials/blob/master/parse-xml-python/main.py"&gt;here at my tutorials repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post and found it useful in parsing XML from a URL in Python. I spent some time reading documentation myself to get this working myself, so I thought I'd make this post to help anyone out.&lt;/p&gt;

&lt;p&gt;Thanks for scrolling.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;— Gabriel Romualdo&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>xml</category>
    </item>
    <item>
      <title>Build and Deploy a Discord Bot with Node and Discord.js in 5 minutes</title>
      <dc:creator>Gabe Romualdo</dc:creator>
      <pubDate>Sat, 08 Aug 2020 01:54:42 +0000</pubDate>
      <link>https://forem.com/gaberomualdo/build-and-deploy-a-discord-bot-with-node-and-discord-js-in-5-minutes-3</link>
      <guid>https://forem.com/gaberomualdo/build-and-deploy-a-discord-bot-with-node-and-discord-js-in-5-minutes-3</guid>
      <description>&lt;p&gt;&lt;em&gt;Title assumes 265 words per minute reading time, as used by Medium and others.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Discord bots can be useful in doing a variety of things like playing music in a voice chat, or sending automated announcements when a Youtuber releases a new video.&lt;/p&gt;

&lt;p&gt;I'm active on several Discord servers myself and have always wanted to build my own Discord bot. After building, deploying, and using my own bot for over a month now, I've written this article as a starting point in building a basic bot and moving from there.&lt;/p&gt;

&lt;p&gt;We'll be building a bot that does something pretty simple: solves math equations. Users will be able to send a message on any channel that looks like &lt;code&gt;!solve [math equation]&lt;/code&gt; and receive a response with the calculated result. For example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A0ho0qXs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/botexamplefunctionality.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A0ho0qXs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/botexamplefunctionality.png" alt="Bot Functionality Graphic" width="375" height="105"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Before Reading, You Should:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Know basic JavaScript and Node.js (with Node and NPM installed)&lt;/li&gt;
&lt;li&gt;Have a Discord account (create one &lt;a href="https://discord.com/"&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Create a Discord API Application and Bot
&lt;/h2&gt;

&lt;p&gt;Go to &lt;a href="https://discord.com/developers/applications"&gt;discord.com/developers/applications&lt;/a&gt; and click 'New Application' on the top right. Let's call the app 'Solver Bot'.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wkKdNVzW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/newapp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wkKdNVzW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/newapp.png" alt="New Application Button Screenshot" width="800" height="42"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By creating an app, you'll be able to get a unique API key to connect to the Discord API, create a bot, and do things like send and receive messages with that bot.&lt;/p&gt;

&lt;p&gt;Now click on the 'Bot' tab on the right sidebar and click 'Add Bot'.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GwTwMc44--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/addbot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GwTwMc44--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/addbot.png" alt="Bot Tab and Add Bot Screenshot" width="800" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a profile picture to the bot by importing a file from your local machine.&lt;/p&gt;

&lt;p&gt;I'll be using an icon which you can &lt;a href="https://github.com/xtrp/tutorials/blob/master/discord-solver-bot/icon.png"&gt;download here&lt;/a&gt; (this icon is CC0 Licensed, and you can use it without attribution).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--udRHyeGC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/boticon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--udRHyeGC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/boticon.png" alt="Bot Icon and Name Screenshot" width="800" height="156"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Add Your Bot to a Server!
&lt;/h2&gt;

&lt;p&gt;Now that we've created a Discord API App with a bot account, we can add the bot to a server. I recommend making your own server to test your bots.&lt;/p&gt;

&lt;p&gt;To add a bot to a server, all we need is an Discord OAuth2 URL. Upon opening this URL, any Discord user can add your bot to a server they own, and grant it permissions.&lt;/p&gt;

&lt;p&gt;To generate the URL, open up the OAuth2 tab.&lt;/p&gt;

&lt;p&gt;You'll see a grid of checkboxes, and here, select the 'bot' option. Another grid should appear, and here is where you'll select bot permissions. For this basic bot, we'll just need to manage and read messages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xSi1iNhM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/botselection.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xSi1iNhM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/botselection.png" alt="App and Bot Scopes and Permissions Screenshot" width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Given these selected options, Discord automatically generates an OAuth2 URL, which you can see in the input box under the first grid. The URL should look something like &lt;code&gt;https://discord.com/oauth2/...&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Try copying and opening the URL! You should be able to add the bot to any servers you own.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QkIqe7C1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/copyoauthurl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QkIqe7C1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/copyoauthurl.png" alt="Discord OAuth2 URL" width="800" height="59"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Create the Functionality of Your Bot With Node and Discord.js
&lt;/h2&gt;

&lt;p&gt;Let's start building the functionality of the bot in Node.&lt;/p&gt;

&lt;p&gt;Make a new folder (or Git repository if that's what you prefer) on your machine called &lt;code&gt;discord-solver-bot&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On your Terminal or Command Line, navigate to the folder and run &lt;code&gt;npm init&lt;/code&gt;, adding any the necessary details when you see fit.&lt;/p&gt;

&lt;p&gt;Now, let's add our dependencies. We'll be using &lt;a href="https://discord.js.org/"&gt;Discord.js&lt;/a&gt;, a package which simplifies connecting and using the Discord API. For solving math equations, we'll use the useful &lt;a href="https://www.npmjs.com/package/equations"&gt;Equations&lt;/a&gt; module.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;npm install discord.js equations --save&lt;/code&gt; to install these packages.&lt;/p&gt;

&lt;p&gt;Okay, now we can create an &lt;code&gt;index.js&lt;/code&gt; file in the folder and start writing some code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GcyUvmTT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/commandline.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GcyUvmTT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/commandline.png" alt="Command Line Example of Creating a Node Project and Adding Packages" width="378" height="103"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can start by importing any necessary packages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Discord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;discord.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Equation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;equations&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// .default to fix a problem I encountered while importing without it&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Connect to Your Bot With Your Bot Token and Login to Discord
&lt;/h3&gt;

&lt;p&gt;To connect to your bot with Discord.js, we initialize Discord.js Client object to connect to the Discord API.&lt;/p&gt;

&lt;p&gt;To login with our bot with the client, we need the bot token. Copy the token by going to your app in the developer portal &amp;gt; bot &amp;gt; token &amp;gt; copy.&lt;/p&gt;

&lt;p&gt;Now we can login to our bot by calling the Client &lt;code&gt;login&lt;/code&gt; function and passing the copied token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Discord&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[your bot token here]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Don't share your bot token with anyone else. It can be used to take complete control over your bot.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Check if Your Bot is Logged In
&lt;/h3&gt;

&lt;p&gt;To check if your bot is logged in and ready to do things on Discord, use the Client &lt;code&gt;ready&lt;/code&gt; event:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ready&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Logged in successfully as bot!`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try running the bot by running &lt;code&gt;node index.js&lt;/code&gt;. You should see that your bot is logged in. In Discord, you should also be able to see that the bot is marked as online.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--R4Xs5i5I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/loggedin.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R4Xs5i5I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/loggedin.png" alt="Bot Logged In Screenshot" width="251" height="59"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Listen for a Message and Respond
&lt;/h3&gt;

&lt;p&gt;Use the client &lt;code&gt;message&lt;/code&gt; event to listen any time a user sends a message anywhere on any server the bot is on. The event comes with a message object which contains the &lt;code&gt;content&lt;/code&gt; (text content of the message) property among others.&lt;/p&gt;

&lt;p&gt;The object also has a &lt;code&gt;.reply&lt;/code&gt; method, for your bot to reply to the message directly to the user that sent it.&lt;/p&gt;

&lt;p&gt;Typically a message we're looking for looks like &lt;code&gt;!solve [equation here]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, all we have to do is check if the message starts with '!solve ', and then solve the equation written afterwards. We can do this with the JavaScript string &lt;code&gt;.startsWith&lt;/code&gt; and &lt;code&gt;.slice&lt;/code&gt; functions respectively.&lt;/p&gt;

&lt;p&gt;For solving the equation the &lt;code&gt;equations&lt;/code&gt; package has a &lt;code&gt;.solve&lt;/code&gt; function to solve any given equation. &lt;code&gt;.solve&lt;/code&gt; throws an error if the equation is not valid, and we can catch that error to reply saying the equation could not be solved.&lt;/p&gt;

&lt;p&gt;Here's what this code looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// remove extra whitespace&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;!solve &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toSolve&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;solved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Equation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toSolve&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;toSolve&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; = &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;solved&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// backticks (TLs) are used to embed variables in strings like `${var}`&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Could not solve the equation '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;toSolve&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. We're Done! Let's Test the Bot
&lt;/h2&gt;

&lt;p&gt;After running &lt;code&gt;node index&lt;/code&gt;, go to a server with the bot (in my case my bot testing server), and try sending a message like &lt;code&gt;!solve 2 + 2&lt;/code&gt;. You should see a response like &lt;code&gt;2 + 2 = 4&lt;/code&gt;. You can additionally try more complex equations, and test the error checking with a malformed equation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v8FfxP1L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/bottest.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v8FfxP1L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xtrp.io/api/content/static_files/build-and-deploy-a-discord-bot-with-node-and-discordjs-in-5-minutes/bottest.png" alt="Bot Functionality Screenshot" width="477" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Deploying Your Bot and Next Steps
&lt;/h2&gt;

&lt;p&gt;Deploying your bot is pretty simple. All you have to do is keep the index file (in this case &lt;code&gt;node index&lt;/code&gt;) running whenever you want your bot to be online, typically 24/7. You can choose to run it on an old computer or Raspberry Pi, your own server, or you can choose to deploy on a platform like &lt;a href="http://heroku.com/"&gt;Heroku&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In terms of next steps in building a more complex bot, the &lt;a href="https://discord.js.org/#/docs/main/stable/general/welcome"&gt;Discord.js documentation&lt;/a&gt; can be really useful in using the Discord API to perform functions on text and voice channels, multiple servers, direct messages, and more.&lt;/p&gt;

&lt;p&gt;In sharing your bot, there are many websites dedicated to listing Discord bots, including &lt;a href="https://bots.ondiscord.xyz/"&gt;bots.ondiscord.xyz&lt;/a&gt;, &lt;a href="https://discord.bots.gg/"&gt;discord.bots.gg&lt;/a&gt;, and &lt;a href="https://top.gg/"&gt;top.gg&lt;/a&gt;. Building a website for your bot can be useful in showcasing its features and linking the URL to add the bot to a server. Sharing the bot among servers you own are know the owner of can also be useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks for Reading
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;View the source code and assets &lt;a href="https://github.com/xtrp/tutorials"&gt;here, at my tutorials repo&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post and found it useful in creating your own Discord bots with Node and Discord.js.&lt;/p&gt;

&lt;p&gt;Thanks for scrolling.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;— Gabriel Romualdo&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>discord</category>
      <category>bot</category>
    </item>
  </channel>
</rss>
