<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Ahmad Abdolsaheb - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Ahmad Abdolsaheb - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 15 May 2026 14:53:39 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/ahmaxed/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Create a Custom Patreon Button ]]>
                </title>
                <description>
                    <![CDATA[ Patreon is a subscription management system for creators. Although it offers a default button snippet, you can create a custom button that includes your preferred design and call to action to increase your click through rate. In this article you will... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-a-custom-patreon-button/</link>
                <guid isPermaLink="false">66ac8af359c54e72c773092b</guid>
                
                    <category>
                        <![CDATA[ Web Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ahmad Abdolsaheb ]]>
                </dc:creator>
                <pubDate>Tue, 18 Jan 2022 15:53:41 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/01/Untitled_Artwork.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Patreon is a subscription management system for creators. Although it offers a default button snippet, you can create a custom button that includes your preferred design and call to action to increase your click through rate.</p>
<p>In this article you will learn how to create a simple custom Patreon link button that takes users to the payment flow of your preferred tier.</p>
<h2 id="heading-how-to-set-up-your-account">How to Set Up Your Account</h2>
<h3 id="heading-step-1">Step 1:</h3>
<p>To start the setup, you'll need a Patreon account. Create an account if you don't have one or sign in to your account.</p>
<h3 id="heading-step-2">Step 2:</h3>
<p>Visit your account's <a target="_blank" href="https://www.patreon.com/portal/registration/register-clients">registration portal</a>. Under <strong>Clients &amp; API Keys,</strong> click on the <strong>Create Client</strong> button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/image-63.png" alt="Image" width="600" height="400" loading="lazy">
<em>Patreon client registration portal</em></p>
<h3 id="heading-step-3">Step 3:</h3>
<p>After clicking the button, a modal will appear. Fill in the information related to your website and make sure to enter a complete URI (including the ending / )  in the <strong>Redirect URIs</strong> field. Then, click on the <strong>Create Client</strong> button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/image-60.png" alt="Image" width="600" height="400" loading="lazy">
<em>Patreon client registration form</em></p>
<h3 id="heading-step-4">Step 4:</h3>
<p>Under <strong>Your existing clients,</strong> you'll see your newly created client. Click on the  drop down icon of your new client.</p>
<p>Finally, copy the client ID as you will need it in the next steps.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/image-64.png" alt="Image" width="600" height="400" loading="lazy">
<em>Registered client information</em></p>
<h2 id="heading-the-code-for-the-custom-button">The Code for the Custom Button</h2>
<p>The following is a function that takes an account id, preferred amount or tier (in cents), and a redirect URI and returns a link to Patreon's checkout flow. </p>
<p>Use the following function in your code, add a custom log/message, and style the <a> element to make your desired link button.</a></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> PatreonButton = <span class="hljs-function">(<span class="hljs-params">clientId, amount, redirectURI</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> clientId = <span class="hljs-string">`&amp;client_id=<span class="hljs-subst">${patreonClientId}</span>`</span>;
  <span class="hljs-keyword">const</span> pledgeLevel = <span class="hljs-string">`$&amp;min_cents=<span class="hljs-subst">${amount}</span>`</span>;
  <span class="hljs-keyword">const</span> v2Params = <span class="hljs-string">"&amp;scope=identity%20identity[email]"</span>;
  <span class="hljs-keyword">const</span> redirectUri = <span class="hljs-string">`&amp;redirect_uri=<span class="hljs-subst">${redirectURI}</span>`</span>;
  <span class="hljs-keyword">const</span> href = <span class="hljs-string">`https://www.patreon.com/oauth2/become-patron?response_type=code<span class="hljs-subst">${pledgeLevel}</span><span class="hljs-subst">${clientId}</span><span class="hljs-subst">${redirectUri}</span><span class="hljs-subst">${v2Params}</span>`</span>;
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">a</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">"patreon-button link-button"</span>
      <span class="hljs-attr">data-patreon-widget-type</span>=<span class="hljs-string">"become-patron-button"</span>
      <span class="hljs-attr">href</span>=<span class="hljs-string">{href}</span>
      <span class="hljs-attr">rel</span>=<span class="hljs-string">"noreferrer"</span>
      <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>
    &gt;</span>
      /* 
      <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
        <span class="hljs-attr">id</span>=<span class="hljs-string">"patreon-logo"</span>
        <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"10 0 2560 356"</span>
        <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
        <span class="hljs-attr">xmlnsXlink</span>=<span class="hljs-string">"http://www.w3.org/1999/xlink"</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">g</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"M1536.54 72.449v76.933h128.24v61.473h-128.24v74.51h128.24v62.921h-206.64V9.529h206.64v62.92h-128.24M2070.82 178.907c0-55.652-37.76-107.434-99.21-107.434-61.95 0-99.21 51.782-99.21 107.434s37.26 107.435 99.21 107.435c61.45 0 99.21-51.783 99.21-107.435zm-278.77 0c0-92.916 66.79-178.093 179.56-178.093 112.26 0 179.05 85.177 179.05 178.093 0 92.916-66.79 178.093-179.05 178.093-112.77 0-179.56-85.177-179.56-178.093zM186.32 131.97c0-31.46-21.299-58.563-54.206-58.563H78.398v117.109h53.716c32.907 0 54.206-27.086 54.206-58.546zM0 9.529h141.788c75.016 0 123.417 56.628 123.417 122.441s-48.401 122.423-123.417 122.423h-63.39v93.893H0V9.529zM492.17 106.314l-41.621 139.382h82.266L492.17 106.314zm73.081 241.972-13.054-41.134H431.69l-13.072 41.134h-83.73L455.882 9.529h72.105l122.442 338.757h-85.178zM782.055 77.277H705.61V9.529h231.793v67.748h-76.951v271.009h-78.397V77.277M2485.08 230.202V9.529h77.91v338.757h-81.78l-121.97-217.78v217.78h-78.4V9.529h81.78l122.46 220.673M1245.68 131.97c0-31.46-21.3-58.563-54.21-58.563h-53.72v117.109h53.72c32.91 0 54.21-27.086 54.21-58.546zM1059.36 9.529h142.29c75 0 123.4 56.628 123.4 122.441 0 47.425-25.17 89.517-67.28 109.369l67.77 106.947h-90.98l-60.03-93.893h-36.78v93.893h-78.39V9.529z"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span> */
    <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></span>
  );
};
</code></pre>
<p>Feel free to uncomment the nested SVG element and use it as your button's illustration or insert your own. The followings are some styles to adjust the your button for light and dark mode.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">a</span><span class="hljs-selector-class">.patreon-button</span> {
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#ff424d</span>;
  <span class="hljs-attribute">min-height</span>: <span class="hljs-number">42px</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">place-items</span>: center;
}
<span class="hljs-selector-tag">a</span><span class="hljs-selector-class">.patreon-button</span> <span class="hljs-selector-tag">svg</span> {
  <span class="hljs-attribute">max-height</span>: <span class="hljs-number">12px</span>;
  <span class="hljs-attribute">fill</span>: white;
}
<span class="hljs-selector-tag">a</span><span class="hljs-selector-class">.patreon-button</span><span class="hljs-selector-pseudo">:active</span>,
<span class="hljs-selector-tag">a</span><span class="hljs-selector-class">.patreon-button</span><span class="hljs-selector-pseudo">:active</span><span class="hljs-selector-pseudo">:focus</span>,
<span class="hljs-selector-tag">a</span><span class="hljs-selector-class">.patreon-button</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#e13d47</span>;
}

<span class="hljs-selector-class">.dark-palette</span> <span class="hljs-selector-tag">a</span><span class="hljs-selector-class">.patreon-button</span> {
  <span class="hljs-attribute">background-color</span>: white;
}

<span class="hljs-selector-class">.dark-palette</span> <span class="hljs-selector-tag">a</span><span class="hljs-selector-class">.patreon-button</span> <span class="hljs-selector-tag">svg</span> {
  <span class="hljs-attribute">fill</span>: <span class="hljs-number">#ff424d</span>;
}
<span class="hljs-selector-class">.dark-palette</span> <span class="hljs-selector-tag">a</span><span class="hljs-selector-class">.patreon-button</span><span class="hljs-selector-pseudo">:active</span>,
<span class="hljs-selector-class">.dark-palette</span> <span class="hljs-selector-tag">a</span><span class="hljs-selector-class">.patreon-button</span><span class="hljs-selector-pseudo">:active</span><span class="hljs-selector-pseudo">:focus</span>,
<span class="hljs-selector-class">.dark-palette</span> <span class="hljs-selector-tag">a</span><span class="hljs-selector-class">.patreon-button</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#efefef</span>;
}
</code></pre>
<p>There you have it. A custom button to take users to your desired tier on Patreon.</p>
<p>At freeCodeCamp, we implemented the same button using <a target="_blank" href="https://github.com/freeCodeCamp/freeCodeCamp/blob/56a60700b7e999548262e3827b80d09fdf201ad2/client/src/components/Donation/patreon-button.tsx">TypeScript</a>  for our <a target="_blank" href="https://www.freecodecamp.org/donate/">donate page</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-18-at-9.13.20-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Custom Patreon button on freeCodeCamp's donate page</em></p>
<p>Clicking the button should take signed-in Patreon users directly to the checkout page. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-18-at-9.09.36-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Patreon checkout page</em></p>
<h2 id="heading-the-next-steps">The next steps</h2>
<p>If you would like to synchronize your platform with Patreon, you could add metadata to the button and receive them through a webhook.</p>
<p>Alternatively, if you are looking to create a full integration, there are a variety of open source integrations that you could use as a template. For specific questions, refer to Patreon's active <a target="_blank" href="https://www.patreondevelopers.com/">developer community</a>.</p>
<p>Finally, if you enjoyed reading this article, don't forget to follow me on <a target="_blank" href="https://twitter.com/abdolsaheb?lang=en">twitter</a> for more articles and tutorials.</p>
<p>Happy Coding.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to code your own procedural dungeon map generator using the Random Walk Algorithm ]]>
                </title>
                <description>
                    <![CDATA[ As technology evolves and game contents become more algorithmically generated, it’s not difficult to imagine the creation of a life-like simulation with unique experiences for each player. Technological breakthroughs, patience, and refined skills wil... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-make-your-own-procedural-dungeon-map-generator-using-the-random-walk-algorithm-e0085c8aa9a/</link>
                <guid isPermaLink="false">66ac8af659c54e72c773092e</guid>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ algorithms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Games ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ahmad Abdolsaheb ]]>
                </dc:creator>
                <pubDate>Tue, 02 Jun 2020 21:18:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/09/Screen-Shot-2020-09-12-at-11.30.55-PM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As technology evolves and game contents become more algorithmically generated, it’s not difficult to imagine the creation of a life-like simulation with unique experiences for each player.</p>
<p>Technological breakthroughs, patience, and refined skills will get us there, but the first step is to understand <strong>procedural content generation</strong>.</p>
<p>Though many out-of-the-box solutions for map generation exist, this tutorial will teach you to make your own two-dimensional dungeon map generator from scratch using JavaScript.</p>
<p>There are many two-dimensional map types, and all have the following characteristics:</p>
<ol>
<li><p>Accessible and inaccessible areas (tunnels and walls).</p>
</li>
<li><p>A connected route the player can navigate.</p>
</li>
</ol>
<p>The algorithm in this tutorial comes from the <a target="_blank" href="https://en.wikipedia.org/wiki/Random_walker_algorithm">Random Walk Algorithm</a>, one of the simplest solutions for map generation.</p>
<p>After making a grid-like map of walls, this algorithm starts from a random place on the map. It keeps making tunnels and taking random turns to complete its desired number of tunnels.</p>
<p>To see a demo, open the CodePen project below, click on the map to create a new map, and change the following values:</p>
<ol>
<li><strong>Dimensions:</strong> the width and height of the map.</li>
<li><strong>MaxTunnels:</strong> the greatest number of turns the algorithm can take while making the map.</li>
<li><strong>MaxLength:</strong> the greatest length of each tunnel the algorithm will choose before making a horizontal or vertical turn.</li>
</ol>
<div class="embed-wrapper"><iframe height="700" style="width:100%" src="https://codepen.io/abdolsa/embed/zEKdop?height=700&amp;theme-id=light&amp;default-tab=result" title="Embedded content" loading="lazy">
  See the Pen <a href="https://codepen.io/abdolsa/pen/zEKdop">CreatMap</a> by Ahmad Abdolsaheb
  (<a href="https://codepen.io/abdolsa">@abdolsa</a>) on <a href="https://codepen.io">CodePen</a>.
</iframe></div>

<p><strong>Note:</strong> the larger the <em>maxTurn</em> is compared to the dimensions, the denser the map will be. The larger the <em>maxLength</em> is compared to the dimensions, the more “tunnel-y” it will look.</p>
<p>Next, let’s go through the map generation algorithm to see how it:</p>
<ol>
<li>Makes a two dimensional map of walls</li>
<li>Chooses a random starting point on the map</li>
<li>While the number of tunnels is not zero</li>
<li>Chooses a random length from maximum allowed length</li>
<li>Chooses a random direction to turn to (right, left, up, down)</li>
<li>Draws a tunnel in that direction while avoiding the edges of the map</li>
<li>Decrements the number of tunnels and repeats the <a target="_blank" href="https://en.wikipedia.org/wiki/While_loop">while loop</a></li>
<li>Returns the map with the changes</li>
</ol>
<p>This loop continues until the number of tunnels is zero.</p>
<h3 id="heading-the-algorithm-in-code">The Algorithm in Code</h3>
<p>Since the map consists of tunnel and wall cells, we could describe it as zeros and ones in a two-dimensional array like the following:</p>
<pre><code class="lang-javascript">map = [[<span class="hljs-number">1</span>,<span class="hljs-number">1</span>,<span class="hljs-number">1</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>],
       [<span class="hljs-number">1</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>],
       [<span class="hljs-number">1</span>,<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">1</span>,<span class="hljs-number">1</span>],       
       [<span class="hljs-number">1</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">1</span>],       
       [<span class="hljs-number">1</span>,<span class="hljs-number">1</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>,<span class="hljs-number">1</span>]]
</code></pre>
<p>Since every cell is in a two-dimensional array, we can access its value by knowing its row and column such as map [row][column].</p>
<p>Before writing the algorithm, you need a helper function that takes a character and dimension as arguments and returns a two-dimensional array.</p>
<pre><code class="lang-javascript">createArray(num, dimensions) {
    <span class="hljs-keyword">var</span> array = [];    
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; dimensions; i++) { 
      array.push([]);      
      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> j = <span class="hljs-number">0</span>; j &lt; dimensions; j++) {  
         array[i].push(num);      
      }    
    }    
    <span class="hljs-keyword">return</span> array;  
}
</code></pre>
<p>To implement the Random Walk Algorithm, set the dimensions of the map (width and height), the<code>maxTunnels</code> variable, and the<code>maxLength</code> variable.</p>
<pre><code class="lang-javascript">createMap(){
 <span class="hljs-keyword">let</span> dimensions = <span class="hljs-number">5</span>,     
 maxTunnels = <span class="hljs-number">3</span>, 
 maxLength = <span class="hljs-number">3</span>;
</code></pre>
<p>Next, make a two-dimensional array using the predefined helper function (two dimensional array of ones).</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> map = createArray(<span class="hljs-number">1</span>, dimensions);
</code></pre>
<p>Set up a random column and random row to create a random starting point for the first tunnel.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> currentRow = <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random() * dimensions),       
    currentColumn = <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random() * dimensions);
</code></pre>
<p>To avoid the complexity of diagonal turns, the algorithm needs to specify the horizontal and vertical directions. Every cell sits in a two-dimensional array and could be identified with its row and column. Because of this, the directions could be defined as subtractions from and/or additions to the column and row numbers.</p>
<p>For example, to go to a cell around the cell [2][2], you could perform the following operations:</p>
<ul>
<li>to go <strong>up</strong>, subtract 1 from its row [1][2]</li>
<li>to go <strong>down</strong>, add 1 to its row [3][2]</li>
<li>to go <strong>right</strong>, add 1 to its column [2][3]</li>
<li>to go <strong>left</strong>, subtract 1 from its column [2][1]</li>
</ul>
<p>The following map illustrates these operations:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/1_P1AfxAKl6SAQMgn8SONUGQ.png" alt="Image" width="600" height="400" loading="lazy">
<em>Operational options grid</em></p>
<p>Now, set the <code>directions</code> variable to the following values that the algorithm will choose from before creating each tunnel:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> directions = [[<span class="hljs-number">-1</span>, <span class="hljs-number">0</span>], [<span class="hljs-number">1</span>, <span class="hljs-number">0</span>], [<span class="hljs-number">0</span>, <span class="hljs-number">-1</span>], [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>]];
</code></pre>
<p>Finally, initiate <code>randomDirection</code> variable to hold a random value from the directions array, and set the <code>lastDirection</code> variable to an empty array which will hold the older <code>randomDirection</code> value.</p>
<p><strong>Note:</strong> the <code>lastDirection</code> array is empty on the first loop because there is no older <code>randomDirection</code> value.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> lastDirection = [], 
    randomDirection;
</code></pre>
<p>Next, make sure <code>maxTunnel</code> is not zero and the dimensions and <code>maxLength</code>values have been received. Continue finding random directions until you find one that isn’t reverse or identical to <code>lastDirection</code>. This <a target="_blank" href="https://en.wikipedia.org/wiki/Do_while_loop">do while loop</a> helps to prevent overwriting the recently-drawn tunnel or drawing two tunnels back-to-back.</p>
<p>For example, if your <code>lastTurn</code> is [0, 1], the do while loop prevents the function from moving forward until <code>randomDirection</code> is set to a value that is not [0, 1] or the opposite [0, -1].</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">do</span> {         
randomDirection = directions[<span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random() * directions.length)];      
} <span class="hljs-keyword">while</span> ((randomDirection[<span class="hljs-number">0</span>] === -lastDirection[<span class="hljs-number">0</span>] &amp;&amp;    
          randomDirection[<span class="hljs-number">1</span>] === -lastDirection[<span class="hljs-number">1</span>]) || 
         (randomDirection[<span class="hljs-number">0</span>] === lastDirection[<span class="hljs-number">0</span>] &amp;&amp;  
          randomDirection[<span class="hljs-number">1</span>] === lastDirection[<span class="hljs-number">1</span>]));
</code></pre>
<p>In the do while loop, there are two main conditions that are divided by an || (OR) sign. The first part of the condition also consists of two conditions. The first one checks if the <code>randomDirection</code>’s first item is the reverse of the <code>lastDirection</code><em>’s</em> first item. The second one checks if the <code>randomDirection</code>’s second item is the reverse of the <code>lastTurn</code>’s second item.</p>
<p>To illustrate, if the <code>lastDirection</code> is [0,1] and <code>randomDirection</code> is [0,-1], the first part of the condition checks if <code>randomDirection</code>[0] === — <code>lastDirection</code>[0]), which equates to 0 === — 0, and is true.</p>
<p>Then, it checks if (<code>randomDirection</code>[1] === — <code>lastDirection</code>[1]) which equates to (-1 === -1) and is also true. Since both conditions are true, the algorithm goes back to find another <code>randomDirection</code>.</p>
<p>The second part of the condition checks if the first and second values of both arrays are the same.</p>
<p>After choosing a <code>randomDirection</code> that satisfies the conditions, set a variable to randomly choose a length from <code>maxLength</code>. Set <code>tunnelLength</code> variable to zero to server as an iterator.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> randomLength = <span class="hljs-built_in">Math</span>.ceil(<span class="hljs-built_in">Math</span>.random() * maxLength),       
    tunnelLength = <span class="hljs-number">0</span>;
</code></pre>
<p>Make a tunnel by turning the value of cells from one to zero while the <code>tunnelLength</code> is smaller than <code>randomLength</code><em>.</em> If within the loop the tunnel hits the edges of the map, the loop should break.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">while</span> (tunnelLength &lt; randomLength) { 
 <span class="hljs-keyword">if</span>(((currentRow === <span class="hljs-number">0</span>) &amp;&amp; (randomDirection[<span class="hljs-number">0</span>] === <span class="hljs-number">-1</span>))||  
    ((currentColumn === <span class="hljs-number">0</span>) &amp;&amp; (randomDirection[<span class="hljs-number">1</span>] === <span class="hljs-number">-1</span>))|| 
    ((currentRow === dimensions — <span class="hljs-number">1</span>) &amp;&amp; (randomDirection[<span class="hljs-number">0</span>] ===<span class="hljs-number">1</span>))||
 ((currentColumn === dimensions — <span class="hljs-number">1</span>) &amp;&amp; (randomDirection[<span class="hljs-number">1</span>] === <span class="hljs-number">1</span>)))   
 { <span class="hljs-keyword">break</span>; }
</code></pre>
<p>Else set the current cell of the map to zero using <code>currentRow</code> and <code>currentColumn.</code> Add the values in the <code>randomDirection</code> array by setting <code>currentRow</code> and <code>currentColumn</code> where they need to be in the upcoming iteration of the loop. Now, increment the <code>tunnelLength</code> iterator.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">else</span>{ 
  map[currentRow][currentColumn] = <span class="hljs-number">0</span>; 
  currentRow += randomDirection[<span class="hljs-number">0</span>];
  currentColumn += randomDirection[<span class="hljs-number">1</span>]; 
  tunnelLength++; 
 } 
}
</code></pre>
<p>After the loop makes a tunnel or breaks by hitting an edge of the map, check if the tunnel is at least one block long. If so, set the <code>lastDirection</code> to the <code>randomDirection</code> and decrement <code>maxTunnels</code> and go back to make another tunnel with another <code>randomDirection</code><em>.</em></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> (tunnelLength) { 
 lastDirection = randomDirection; 
 maxTunnels--; 
}
</code></pre>
<p>This IF statement prevents the for loop that hit the edge of the map and did not make a tunnel of at least one cell to decrement the <code>maxTunnel</code> and change the <code>lastDirection</code>. When that happens, the algorithm goes to find another <code>randomDirection</code> to continue.</p>
<p>When it finishes drawing tunnels and <code>maxTunnels</code> is zero, return the resulting map with all its turns and tunnels.</p>
<pre><code class="lang-javascript">}
 <span class="hljs-keyword">return</span> map;
};
</code></pre>
<p>You can see the complete algorithm in the following snippet:</p>
<p>Congratulations for reading through this tutorial. You are now well-equipped to make your own map generator or improve upon this version. Check out the project on <a target="_blank" href="https://codepen.io/anon/pen/aLpORx">CodePen</a> and on <a target="_blank" href="https://github.com/ahmadabdolsaheb/mapgen">GitHub</a> as a react application.</p>
<p><em>Thanks for reading! If you liked this story, don't forget to share it on social media.</em></p>
<p>Special thanks to <a target="_blank" href="https://github.com/moT01">Tom</a>  for co-writing this article.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to make your Tic Tac Toe game unbeatable by using the minimax algorithm ]]>
                </title>
                <description>
                    <![CDATA[ I struggled for hours scrolling through tutorials, watching videos, and banging my head on the desk trying to build an unbeatable Tic Tac Toe game with a reliable Artificial Intelligence. So if you are going through a similar journey, I would like to... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-make-your-tic-tac-toe-game-unbeatable-by-using-the-minimax-algorithm-9d690bad4b37/</link>
                <guid isPermaLink="false">66ac8afb0f96f64ded4b7bd3</guid>
                
                    <category>
                        <![CDATA[ algorithms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ gaming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ahmad Abdolsaheb ]]>
                </dc:creator>
                <pubDate>Sat, 02 May 2020 04:50:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/09/1_y2B2auvIpUI0vSLtT2KWyg-1.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>I struggled for hours scrolling through tutorials, watching videos, and banging my head on the desk trying to build an unbeatable Tic Tac Toe game with a reliable Artificial Intelligence. So if you are going through a similar journey, I would like to introduce you to the Minimax algorithm.</p>
<p>Like a professional chess player, this algorithm sees a few steps ahead and puts itself in the shoes of its opponent. It keeps playing ahead until it reaches a terminal arrangement of the board (<strong>terminal state</strong>) resulting in a tie, a win, or a loss. Once in a terminal state, the AI will assign an arbitrary positive score (+10) for a win, a negative score (-10) for a loss, or a neutral score (0) for a tie.</p>
<p>At the same time, the algorithm evaluates the moves that lead to a terminal state based on the players’ turn. It will choose the move with maximum score when it is the AI’s turn and choose the move with the minimum score when it is the human player’s turn. Using this strategy, Minimax avoids losing to the human player.</p>
<p>Try it for yourself in the following game preferably using a Chrome browser.</p>
<div class="embed-wrapper"><iframe height="454" style="width:100%" src="https://codepen.io/abdolsa/embed/vgjoMb?height=454&amp;theme-id=light&amp;default-tab=js,result" title="Embedded content" loading="lazy">
  See the Pen <a href="https://codepen.io/abdolsa/pen/vgjoMb">minimax 4 medium</a> by Ahmad Abdolsaheb
  (<a href="https://codepen.io/abdolsa">@abdolsa</a>) on <a href="https://codepen.io">CodePen</a>.
</iframe></div>

<p>A Minimax algorithm can be best defined as a recursive function that does the following things:</p>
<ol>
<li>return a value if a terminal state is found (+10, 0, -10)</li>
<li>go through available spots on the board</li>
<li>call the minimax function on each available spot (recursion)</li>
<li>evaluate returning values from function calls</li>
<li>and return the best value</li>
</ol>
<p>If you are new to the concept of recursion, I recommend watching this <a target="_blank" href="https://www.youtube.com/watch?v=VrrnjYgDBEk">video</a> from Harvard’s CS50.</p>
<p>To completely grasp the Minimax’s thought process, let’s implement it in code and see it in action in the following two sections.</p>
<h3 id="heading-minimax-in-code">Minimax in Code</h3>
<p>For this tutorial you will be working on a near end state of the game which is shown in figure 2 below. Since minimax evaluates every state of the game (hundreds of thousands), a near end state allows you to follow up with minimax’s recursive calls easier (9).</p>
<p>For the following figure, assume the AI is X and the human player is O.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/iYDAcMcMvbr0lBISCQqM-mBbfhqDx2sPqcYl" alt="Image" width="800" height="317" loading="lazy">
<em>figure 2 sample of game state</em></p>
<p>To work with the Ti Tac Toe board more easily, you should define it as an array with 9 items. Each item will have its index as a value. This will come in handy later on. Because the above board is already populated with some X and Y moves, let us define the board with the X and Y moves already in it (<em>origBoard</em>).</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> origBoard = [<span class="hljs-string">"O"</span>,<span class="hljs-number">1</span>,<span class="hljs-string">"X"</span>,<span class="hljs-string">"X"</span>,<span class="hljs-number">4</span>,<span class="hljs-string">"X"</span>,<span class="hljs-number">6</span>,<span class="hljs-string">"O"</span>,<span class="hljs-string">"O"</span>];
</code></pre>
<p>Then declare <em>aiPlayer</em> and <em>huPlayer</em> variables and set them to “X” and “O” respectively<em>.</em></p>
<p>Additionally, you need a function that looks for winning combinations and returns true if it finds one, and a function that lists the indexes of available spots in the board.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* the original board
 O |   | X
 ---------
 X |   | X
 ---------
   | O | O
 */</span>
<span class="hljs-keyword">var</span> origBoard = [“O”,<span class="hljs-number">1</span> ,”X”,”X”,<span class="hljs-number">4</span> ,”X”, <span class="hljs-number">6</span> ,”O”,”O”];

<span class="hljs-comment">// human</span>
<span class="hljs-keyword">var</span> huPlayer = “O”;

<span class="hljs-comment">// ai</span>
<span class="hljs-keyword">var</span> aiPlayer = “X”;

<span class="hljs-comment">// returns list of the indexes of empty spots on the board</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">emptyIndexies</span>(<span class="hljs-params">board</span>)</span>{
  <span class="hljs-keyword">return</span>  board.filter(<span class="hljs-function"><span class="hljs-params">s</span> =&gt;</span> s != <span class="hljs-string">"O"</span> &amp;&amp; s != <span class="hljs-string">"X"</span>);
}

<span class="hljs-comment">// winning combinations using the board indexies</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">winning</span>(<span class="hljs-params">board, player</span>)</span>{
 <span class="hljs-keyword">if</span> (
 (board[<span class="hljs-number">0</span>] == player &amp;&amp; board[<span class="hljs-number">1</span>] == player &amp;&amp; board[<span class="hljs-number">2</span>] == player) ||
 (board[<span class="hljs-number">3</span>] == player &amp;&amp; board[<span class="hljs-number">4</span>] == player &amp;&amp; board[<span class="hljs-number">5</span>] == player) ||
 (board[<span class="hljs-number">6</span>] == player &amp;&amp; board[<span class="hljs-number">7</span>] == player &amp;&amp; board[<span class="hljs-number">8</span>] == player) ||
 (board[<span class="hljs-number">0</span>] == player &amp;&amp; board[<span class="hljs-number">3</span>] == player &amp;&amp; board[<span class="hljs-number">6</span>] == player) ||
 (board[<span class="hljs-number">1</span>] == player &amp;&amp; board[<span class="hljs-number">4</span>] == player &amp;&amp; board[<span class="hljs-number">7</span>] == player) ||
 (board[<span class="hljs-number">2</span>] == player &amp;&amp; board[<span class="hljs-number">5</span>] == player &amp;&amp; board[<span class="hljs-number">8</span>] == player) ||
 (board[<span class="hljs-number">0</span>] == player &amp;&amp; board[<span class="hljs-number">4</span>] == player &amp;&amp; board[<span class="hljs-number">8</span>] == player) ||
 (board[<span class="hljs-number">2</span>] == player &amp;&amp; board[<span class="hljs-number">4</span>] == player &amp;&amp; board[<span class="hljs-number">6</span>] == player)
 ) {
 <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
 } <span class="hljs-keyword">else</span> {
 <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
 }
}
</code></pre>
<p>Now let’s dive into the good parts by defining the Minimax function with two arguments <em>newBoard</em> and <em>player</em>. Then, you need to find the indexes of the available spots in the board and set them to a variable called <em>availSpots</em>.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// the main minimax function</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">minimax</span>(<span class="hljs-params">newBoard, player</span>)</span>{

    <span class="hljs-comment">//available spots</span>
    <span class="hljs-keyword">var</span> availSpots = emptyIndexies(newBoard);
</code></pre>
<p>Also, you need to check for terminal states and return a value accordingly. If O wins you should return -10, if X wins you should return +10. In addition, if the length of the <em>availableSpots</em> array is zero, that means there is no more room to play, the game has resulted in a tie, and you should return zero.</p>
<pre><code class="lang-javascript">
  <span class="hljs-comment">// checks for the terminal states such as win, lose, and tie </span>
  <span class="hljs-comment">//and returning a value accordingly</span>
  <span class="hljs-keyword">if</span> (winning(newBoard, huPlayer)){
     <span class="hljs-keyword">return</span> {<span class="hljs-attr">score</span>:<span class="hljs-number">-10</span>};
  }
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (winning(newBoard, aiPlayer)){
    <span class="hljs-keyword">return</span> {<span class="hljs-attr">score</span>:<span class="hljs-number">10</span>};
    }
  <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (availSpots.length === <span class="hljs-number">0</span>){
      <span class="hljs-keyword">return</span> {<span class="hljs-attr">score</span>:<span class="hljs-number">0</span>};
  }
</code></pre>
<p>Next, you need to collect the scores from each of the empty spots to evaluate later. Therefore, make an array called <em>moves</em> and loop through empty spots while collecting each move’s index and score in an object called <em>move</em>.</p>
<p>Then, set the index number of the empty spot that was stored as a number in the <em>origBoard</em> to the index property of the <em>move</em> object. Later, set the empty spot on the <em>newboard</em> to the current player and call the <em>minimax</em> function with other player and the newly changed <em>newboard</em>. Next, you should store the object resulted from the <em>minimax</em> function call that includes a <em>score</em> property to the <em>score</em> property of the <em>move</em> object.</p>
<blockquote>
<p><em>If the minimax function does not find a terminal state, it keeps recursively going level by level deeper into the game. This recursion happens until it reaches a terminal state and returns a score one level up.</em></p>
</blockquote>
<p>Finally, Minimax resets <em>newBoard</em> to what it was before and pushes the <em>move</em> object to the <em>moves</em> array.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// an array to collect all the objects</span>
  <span class="hljs-keyword">var</span> moves = [];

  <span class="hljs-comment">// loop through available spots</span>
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; availSpots.length; i++){
    <span class="hljs-comment">//create an object for each and store the index of that spot </span>
    <span class="hljs-keyword">var</span> move = {};
      move.index = newBoard[availSpots[i]];

    <span class="hljs-comment">// set the empty spot to the current player</span>
    newBoard[availSpots[i]] = player;

    <span class="hljs-comment">/*collect the score resulted from calling minimax 
      on the opponent of the current player*/</span>
    <span class="hljs-keyword">if</span> (player == aiPlayer){
      <span class="hljs-keyword">var</span> result = minimax(newBoard, huPlayer);
      move.score = result.score;
    }
    <span class="hljs-keyword">else</span>{
      <span class="hljs-keyword">var</span> result = minimax(newBoard, aiPlayer);
      move.score = result.score;
    }

    <span class="hljs-comment">// reset the spot to empty</span>
    newBoard[availSpots[i]] = move.index;

    <span class="hljs-comment">// push the object to the array</span>
    moves.push(move);
  }
</code></pre>
<p>Then, the minimax algorithm needs to evaluate the best <em>move</em> in the <em>moves</em> array. It should choose the <em>move</em> with the highest score when AI is playing and the <em>move</em> with the lowest score when the human is playing. Therefore, If the <em>player</em> is <em>aiPlayer</em>, it sets a variable called <em>bestScore</em> to a very low number and loops through the <em>moves</em> array, if a <em>move</em> has a higher <em>score</em> than <em>bestScore</em>, the algorithm stores that <em>move</em>. In case there are moves with similar score, only the first one will be stored.</p>
<p>The same evaluation process happens when <em>player</em> is <em>huPlayer</em>, but this time <em>bestScore</em> would be set to a high number and Minimax looks for a move with the lowest score to store.</p>
<p>At the end, Minimax returns the object stored in <em>bestMove</em>.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// if it is the computer's turn loop over the moves and choose the move with the highest score</span>
  <span class="hljs-keyword">var</span> bestMove;
  <span class="hljs-keyword">if</span>(player === aiPlayer){
    <span class="hljs-keyword">var</span> bestScore = <span class="hljs-number">-10000</span>;
    <span class="hljs-keyword">for</span>(<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; moves.length; i++){
      <span class="hljs-keyword">if</span>(moves[i].score &gt; bestScore){
        bestScore = moves[i].score;
        bestMove = i;
      }
    }
  }<span class="hljs-keyword">else</span>{

<span class="hljs-comment">// else loop over the moves and choose the move with the lowest score</span>
    <span class="hljs-keyword">var</span> bestScore = <span class="hljs-number">10000</span>;
    <span class="hljs-keyword">for</span>(<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; moves.length; i++){
      <span class="hljs-keyword">if</span>(moves[i].score &lt; bestScore){
        bestScore = moves[i].score;
        bestMove = i;
      }
    }
  }

<span class="hljs-comment">// return the chosen move (object) from the moves array</span>
  <span class="hljs-keyword">return</span> moves[bestMove];
}
</code></pre>
<blockquote>
<p><em>That is it for the minimax function. :) you can find the above algorithm on <a target="_blank" href="https://github.com/ahmadabdolsaheb/minimaxarticle">github</a> and <a target="_blank" href="https://codepen.io/abdolsa/pen/mABGoz?editors=1011">codepen</a>. Play around with different boards and check the results in the console.</em></p>
</blockquote>
<p>In the next section, let’s go over the code line by line to better understand how the minimax function behaves given the board shown in figure 2.</p>
<h3 id="heading-minimax-in-action">Minimax in action</h3>
<p>Using the following figure, let’s follow the algorithm’s function calls (<strong>FC</strong>) one by one.</p>
<p>Note: In figure 3, large numbers represent each function call and levels refer to how many steps ahead of the game the algorithm is playing.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/1_VG79nxl-mJQrsp6p3q79qA--1-.png" alt="Image" width="600" height="400" loading="lazy">
<em>Figure 3 Minimax function call by function call</em></p>
<p><strong><em>1.</em></strong><em>origBoard</em> and <em>aiPlayer</em> is fed to the algorithm. The algorithm makes a list of the three empty spots it finds, checks for terminal states, and loops through every empty spot starting from the first one. Then, it changes the <em>newBoard</em> by placing the <em>aiPlayer</em> in the first empty spot. After that, it calls itself with <em>newBoard</em> and the <em>huPlayer</em> and waits for the FC to return a value.</p>
<p><strong>2.</strong> While the first FC is still running, the second one starts by making a list of the two empty spots it finds, checks for terminal states, and loops through the empty spot starting from the first one. Then, it changes the <em>newBoard</em> by placing the <em>huPlayer</em> in the first empty spot. After that it calls itself with <em>newBoard</em> and the <em>aiPlayer</em> and waits for the FC to return a value.</p>
<p><strong>3.</strong> Finally the algorithm makes a list of the empty spots, and finds a win for the human player after checking for terminal states. Therefore, it returns an object with a score property and value of -10.</p>
<blockquote>
<p><em>Since the second FC listed two empty spots, Minimax changes the</em> newBoard <em>by placing</em> huPlayer <em>in the second empty spot. Then, it calls itself with the new board and the</em> aiPlayer<em>.</em></p>
</blockquote>
<p><strong>4.</strong> The algorithm makes a list of the empty spots, and finds a win for the human player after checking for terminal states. Therefore, it returns an object with a score property and value of -10.</p>
<blockquote>
<p><em>On the second FC, the algorithm collects the values coming from lower levels (3rd and 4th FC). Since</em> huPlayer<em>’s turn resulted in the two values, the algorithm chooses the lowest of the two values. Because both of the values are similar, it chooses the first one and returns it up to the first FC.</em></p>
<p><em>At this point the first FC has evaluated the score of moving</em> aiPlayer <em>in the first empty spot. Next, it changes the</em> newBoard <em>by placing</em> aiPlayer <em>in the second empty spot. Then, it calls itself with the</em> newBoard <em>and the</em> huPlayer<em>.</em></p>
</blockquote>
<p><strong>5.</strong> On the fifth FC, The algorithm makes a list of the empty spots, and finds a win for the human player after checking for terminal states. Therefore, it returns an object with a score property and value of +10.</p>
<blockquote>
<p><em>After that, the first FC moves on by changing the</em> newBoard <em>and placing</em> aiPlayer <em>in the third empty spot. Then, it calls itself with the new board and the</em> huPlayer<em>.</em></p>
</blockquote>
<p><strong>6.</strong> The 6th FC starts by making a list of two empty spots it finds, checks for terminal states, and loops through the two empty spots starting from the first one. Then, it changes the <em>newBoard</em> by placing the <em>huPlayer</em> in the first empty spot. After that, it calls itself with <em>newBoard</em> and the <em>aiPlayer</em> and waits for the FC to return a score.</p>
<p><strong>7.</strong> Now the algorithm is two level deep into the recursion. It makes a list of the one empty spot it finds, checks for terminal states, and changes the <em>newBoard</em> by placing the <em>aiPlayer</em> in the empty spot. After that, it calls itself with <em>newBoard</em> and the <em>huPlayer</em> and waits for the FC to return a score so it can evaluate it.</p>
<p><strong>8.</strong> On the 8th FC, the algorithm makes an empty list of empty spots, and finds a win for the <em>aiPlayer</em> after checking for terminal states. Therefore, it returns an object with score property and value of +10 one level up (7th FC).</p>
<blockquote>
<p><em>The 7th FC only received one positive value from lower levels (8th FC). Because</em> aiPlayer’s turn <em>resulted in that value, the algorithm needs to return the highest value it has received from lower levels. Therefore, it returns its only positive value (+10) one level up (6th FC).</em></p>
<p><em>Since the 6th FC listed two empty spots, Minimax changes</em> newBoard <em>by placing</em> huPlayer <em>in the second empty spot. Then, calls itself with the new board and the</em> aiPlayer<em>.</em></p>
</blockquote>
<p><strong>9.</strong> Next, the algorithm makes a list of the empty spots, and finds a win for the <em>aiPlayer</em> after checking for terminal states. Therefore, it returns an object with score properties and value of +10.</p>
<blockquote>
<p><em>At this point, the 6 FC has to choose between the score (+10)that was sent up from the 7th FC (returned originally from from the 8 FC) and the score (-10) returned from the 9th FC. Since</em> huPlayer<em>’s turn resulted in those two returned values, the algorithm finds the minimum score (-10) and returns it upwards as an object containing score and index properties.</em></p>
<p><em>Finally, all three branches of the first FC have been evaluated ( -10, +10, -10). But because aiPlayer’s turn resulted in those values, the algorithm returns an object containing the highest score (+10) and its index (4).</em></p>
</blockquote>
<p><strong>In the above scenario, Minimax concludes that moving the X to the middle of the board results in the best outcome. :)</strong></p>
<h3 id="heading-the-end">The End!</h3>
<p>By now you should be able to understand the logic behind the Minimax algorithm. Using this logic try to implement a Minimax algorithm yourself or find the above sample on <a target="_blank" href="https://github.com/ahmadabdolsaheb/minimaxarticle">github</a> or <a target="_blank" href="https://codepen.io/abdolsa/pen/mABGoz?editors=1011">codepen</a> and optimize it.</p>
<p><em>Thanks for reading! If you liked this story, don't forget to share it on social media.</em></p>
<p><em>Special thanks to Tuba Yilmaz, Rick McGavin, and Javid Askerov</em> <em>for reviewing this article.</em></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
