<?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" version="2.0"><channel><title><![CDATA[Jothin kumar]]></title><description><![CDATA[I am Jothin kumar, a programming hobbyist from India.]]></description><link>https://blog.jothin.tech</link><generator>RSS for Node</generator><lastBuildDate>Sat, 18 Apr 2026 10:38:14 GMT</lastBuildDate><atom:link href="https://blog.jothin.tech/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Tic Tac Toe 🎮 with Python tkinter - part 2]]></title><description><![CDATA[This tutorial is part of a series. Make sure to check out the previous tutorial, if you haven't already.In this tutorial, we will add a functionality to the Tic-Tac-Toe game: Player vs Computer 👀
Logic in Tic-Tac-Toe 🎮
Let's go ahead and create a f...]]></description><link>https://blog.jothin.tech/tic-tac-toe-with-python-tkinter-part-2</link><guid isPermaLink="true">https://blog.jothin.tech/tic-tac-toe-with-python-tkinter-part-2</guid><dc:creator><![CDATA[Jothin kumar]]></dc:creator><pubDate>Tue, 03 May 2022 12:53:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1651564918093/szUmT8UVJ.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>This tutorial is part of a series. Make sure to check out the <a target="_blank" href="https://blog.jothin.tech/tic-tac-toe-with-python-tkinter-part-1">previous tutorial</a>, if you haven't already.</strong><br />In this tutorial, we will add a functionality to the Tic-Tac-Toe game: <strong>Player vs Computer</strong> 👀</p>
<h2 id="heading-logic-in-tic-tac-toe">Logic in Tic-Tac-Toe 🎮</h2>
<p>Let's go ahead and create a function for the computer to determine the moves in this game.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">auto_play</span>():</span>
</code></pre>
<p>Before completing the code, let's take a look at the logic 🤔:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1651579341926/wiGozcCit.png" alt="Logic in Tic-Tac-Toe game" /></p>
<h3 id="heading-1-when-the-game-can-be-won-on-the-next-move-either-by-the-computer-or-the-player">1. When the game can be won on the next move, either by the computer or the player</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1651571708210/tGyVeOxV_.png" alt="Tic Tac Toe with Python tkinter - Game can be won in next move" />
When the game can be won on the next move by computer, the move should be done. If the game can be won by player on the next move, the best option is to prevent it. It can be implemented in Python as:</p>
<pre><code class="lang-python"><span class="hljs-comment"># If winning of computer is possible on the next move, go ahead and win the game</span>
<span class="hljs-keyword">for</span> winning_possibility <span class="hljs-keyword">in</span> winning_possibilities:
    winning_possibility.check(<span class="hljs-string">'O'</span>)  <span class="hljs-comment"># Check how many conditions for winning of computer are satisfied</span>
    <span class="hljs-keyword">if</span> winning_possibility.p1_satisfied <span class="hljs-keyword">and</span> winning_possibility.p2_satisfied:  <span class="hljs-comment"># If condition 1 and 2 are satisfied, satisfy condition 3</span>
        <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:
            <span class="hljs-keyword">if</span> point.x == winning_possibility.x3 <span class="hljs-keyword">and</span> point.y == winning_possibility.y3 <span class="hljs-keyword">and</span> point <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> X_points + O_points:  <span class="hljs-comment"># Find the point that needs to be occupied to satisfy condtion 3 and make sure that it is not already occupied</span>
                point.set()  <span class="hljs-comment"># Occupy point</span>
                <span class="hljs-keyword">return</span>  <span class="hljs-comment"># End the function</span>
     <span class="hljs-keyword">elif</span> winning_possibility.p2_satisfied <span class="hljs-keyword">and</span> winning_possibility.p3_satisfied:  <span class="hljs-comment"># If condition 2 and 3 are satisfied, satisfy condition 1</span>
        <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:
            <span class="hljs-keyword">if</span> point.x == winning_possibility.x1 <span class="hljs-keyword">and</span> point.y == winning_possibility.y1 <span class="hljs-keyword">and</span> point <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> X_points + O_points:  <span class="hljs-comment"># Find the point that needs to be occupied to satisfy condition 1 and make sure that it is not already occupied</span>
                point.set()  <span class="hljs-comment"># Occupy point</span>
                <span class="hljs-keyword">return</span>  <span class="hljs-comment"># End the function</span>
     <span class="hljs-keyword">elif</span> winning_possibility.p3_satisfied <span class="hljs-keyword">and</span> winning_possibility.p1_satisfied:  <span class="hljs-comment"># If condition 1 and 3 are satisfied, satisfy condition 2</span>
        <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:
            <span class="hljs-keyword">if</span> point.x == winning_possibility.x2 <span class="hljs-keyword">and</span> point.y == winning_possibility.y2 <span class="hljs-keyword">and</span> point <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> X_points + O_points:  <span class="hljs-comment"># Find the point that needs to be occupied to satisfy condition 2 and make sure that it is not already occupied</span>
                point.set()  <span class="hljs-comment"># Occupy point</span>
                <span class="hljs-keyword">return</span>  <span class="hljs-comment"># End the function</span>

<span class="hljs-comment"># If the player might win on the next move, prevent it</span>
<span class="hljs-keyword">for</span> winning_possibility <span class="hljs-keyword">in</span> winning_possibilities:  
    winning_possibility.check(<span class="hljs-string">'X'</span>)  <span class="hljs-comment"># Check how many conditions for winning of player are satisfied</span>
    <span class="hljs-keyword">if</span> winning_possibility.p1_satisfied <span class="hljs-keyword">and</span> winning_possibility.p2_satisfied:  <span class="hljs-comment"># If condition 1 and 2 are satisfied, prevent condition 3 from being satisfied</span>
        <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:
            <span class="hljs-keyword">if</span> point.x == winning_possibility.x3 <span class="hljs-keyword">and</span> point.y == winning_possibility.y3 <span class="hljs-keyword">and</span> point <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> X_points + O_points:  <span class="hljs-comment"># Find the point and make sure that it is not already occupied</span>
                point.set()  <span class="hljs-comment"># Occupy point</span>
                <span class="hljs-keyword">return</span>  <span class="hljs-comment"># End function</span>
    <span class="hljs-keyword">elif</span> winning_possibility.p2_satisfied <span class="hljs-keyword">and</span> winning_possibility.p3_satisfied:  <span class="hljs-comment"># If condition 2 and 3 are satisfied, prevent condition 1 from being satisfied</span>
        <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:
            <span class="hljs-keyword">if</span> point.x == winning_possibility.x1 <span class="hljs-keyword">and</span> point.y == winning_possibility.y1 <span class="hljs-keyword">and</span> point <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> X_points + O_points:  <span class="hljs-comment"># Find the point and make sure that it is not already occupied</span>
                point.set()  <span class="hljs-comment"># Occupy point</span>
                <span class="hljs-keyword">return</span>  <span class="hljs-comment"># End function</span>
    <span class="hljs-keyword">elif</span> winning_possibility.p3_satisfied <span class="hljs-keyword">and</span> winning_possibility.p1_satisfied:  <span class="hljs-comment"># If condition 1 and 3 are satisfied, prevent condition 2 from being satisfied</span>
        <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:
            <span class="hljs-keyword">if</span> point.x == winning_possibility.x2 <span class="hljs-keyword">and</span> point.y == winning_possibility.y2 <span class="hljs-keyword">and</span> point <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> X_points + O_points:  <span class="hljs-comment"># Find the point and make sure that it is not already occupied</span>
                point.set()  <span class="hljs-comment"># Occupy point</span>
                <span class="hljs-keyword">return</span>  <span class="hljs-comment"># End function</span>
</code></pre>
<h4 id="heading-some-changes-to-function-check-in-class-winningpossibility">Some changes to function "check" in class "WinningPossibility"</h4>
<p>To check how many conditions are currently satisfied to win the game, we need to make variables <code>p1_satisfied</code>, <code>p2_satisfied</code> and <code>p3_satisfied</code> accessible outside the function. So, let's rename them as <code>self.p1_satisfied</code>, <code>self.p2_satisfied</code> and <code>self.p3_satisfied</code> respectively. The new code for the function would be:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check</span>(<span class="hljs-params">self, for_chr</span>):</span>  
    self.p1_satisfied = <span class="hljs-literal">False</span>  
    self.p2_satisfied = <span class="hljs-literal">False</span>  
    self.p3_satisfied = <span class="hljs-literal">False</span>  
    <span class="hljs-keyword">if</span> for_chr == <span class="hljs-string">'X'</span>:  
        <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> X_points:  
            <span class="hljs-keyword">if</span> point.x == self.x1 <span class="hljs-keyword">and</span> point.y == self.y1:  
                self.p1_satisfied = <span class="hljs-literal">True</span>  
    <span class="hljs-keyword">elif</span> point.x == self.x2 <span class="hljs-keyword">and</span> point.y == self.y2:  
                self.p2_satisfied = <span class="hljs-literal">True</span>  
    <span class="hljs-keyword">elif</span> point.x == self.x3 <span class="hljs-keyword">and</span> point.y == self.y3:  
                self.p3_satisfied = <span class="hljs-literal">True</span>  
    <span class="hljs-keyword">elif</span> for_chr == <span class="hljs-string">'O'</span>:  
        <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> O_points:  
            <span class="hljs-keyword">if</span> point.x == self.x1 <span class="hljs-keyword">and</span> point.y == self.y1:  
                self.p1_satisfied = <span class="hljs-literal">True</span>  
    <span class="hljs-keyword">elif</span> point.x == self.x2 <span class="hljs-keyword">and</span> point.y == self.y2:  
                self.p2_satisfied = <span class="hljs-literal">True</span>  
    <span class="hljs-keyword">elif</span> point.x == self.x3 <span class="hljs-keyword">and</span> point.y == self.y3:  
                self.p3_satisfied = <span class="hljs-literal">True</span>  
    <span class="hljs-keyword">return</span> all([self.p1_satisfied, self.p2_satisfied, self.p3_satisfied])
</code></pre>
<h3 id="heading-2-if-center-is-not-currently-occupied">2. If center is not currently occupied</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1651571206777/JWO75RyOQ.png" alt="Tic Tac Toe with Python tkinter - Center not occupied" />
It's a good idea to occupy the center if it's not currently occupied. It can be implemented in Python as:</p>
<pre><code class="lang-python">center_occupied = <span class="hljs-literal">False</span>
<span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> X_points + O_points:  <span class="hljs-comment"># Check if center is already occupied</span>
    <span class="hljs-keyword">if</span> point.x == <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> point.y == <span class="hljs-number">2</span>:
        center_occupied = <span class="hljs-literal">True</span>
        <span class="hljs-keyword">break</span>
 <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> center_occupied:  <span class="hljs-comment"># If center is not occupied</span>
    <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:
        <span class="hljs-keyword">if</span> point.x == <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> point.y == <span class="hljs-number">2</span>:
            point.set()  <span class="hljs-comment"># Occupy center</span>
            <span class="hljs-keyword">return</span>  <span class="hljs-comment"># End the function</span>
</code></pre>
<h3 id="heading-3-if-the-center-is-already-occupied-and-currently-there-is-no-winning-possibility">3. If the center is already occupied, and currently there is no winning possibility</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1651576306706/mIv1z2bOB.png" alt="Tic Tac Toe with Python tkinter - center occupied and no current winning possibilities" />
In this case, we need to occupy either a corner point or a middle one. If fewer than two corners are occupied by the player, "O" must try to occupy the rest. If 2 or more corners are occupied by the player, it is safer to occupy the middle points instead. This can be implemented in Python as:</p>
<pre><code class="lang-python">corner_points = [(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>), (<span class="hljs-number">1</span>, <span class="hljs-number">3</span>), (<span class="hljs-number">3</span>, <span class="hljs-number">1</span>), (<span class="hljs-number">3</span>, <span class="hljs-number">3</span>)]
middle_points = [(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>), (<span class="hljs-number">2</span>, <span class="hljs-number">1</span>), (<span class="hljs-number">2</span>, <span class="hljs-number">3</span>), (<span class="hljs-number">3</span>, <span class="hljs-number">2</span>)]
num_of_corner_points_occupied_by_X = <span class="hljs-number">0</span>
<span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> X_points:  <span class="hljs-comment"># Iterate over all points occupied by the player</span>
    <span class="hljs-keyword">if</span> (point.x, point.y) <span class="hljs-keyword">in</span> corner_points:
        num_of_corner_points_occupied_by_X += <span class="hljs-number">1</span>
<span class="hljs-keyword">if</span> num_of_corner_points_occupied_by_X &gt;= <span class="hljs-number">2</span>:  <span class="hljs-comment"># If two or more corner points are occupied by the player</span>
    <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:
        <span class="hljs-keyword">if</span> (point.x, point.y) <span class="hljs-keyword">in</span> middle_points <span class="hljs-keyword">and</span> point <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> X_points + O_points:  <span class="hljs-comment"># Find a middle point and make sure that it is not already occupied</span>
            point.set()  <span class="hljs-comment"># Occupy the point</span>
            <span class="hljs-keyword">return</span>  <span class="hljs-comment"># End the function</span>
<span class="hljs-keyword">elif</span> num_of_corner_points_occupied_by_X &lt; <span class="hljs-number">2</span>:  <span class="hljs-comment"># If less than two corner points are occupied by the player</span>
    <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:
        <span class="hljs-keyword">if</span> (point.x, point.y) <span class="hljs-keyword">in</span> corner_points <span class="hljs-keyword">and</span> point <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> X_points + O_points:  <span class="hljs-comment"># Find a corner point and make sure that it is not already occupied</span>
            point.set()  <span class="hljs-comment"># Occupy the point</span>
            <span class="hljs-keyword">return</span>  <span class="hljs-comment"># End the function</span>
</code></pre>
<h3 id="heading-combining-all-code-lets-write-the-function-autoplay">Combining all code, let's write the function <code>auto_play</code>:</h3>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">auto_play</span>():</span>  

    <span class="hljs-comment"># If winning is possible in the next move  </span>
    <span class="hljs-keyword">for</span> winning_possibility <span class="hljs-keyword">in</span> winning_possibilities:  
        winning_possibility.check(<span class="hljs-string">'O'</span>)  
        <span class="hljs-keyword">if</span> winning_possibility.p1_satisfied <span class="hljs-keyword">and</span> winning_possibility.p2_satisfied:  
            <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:  
                <span class="hljs-keyword">if</span> point.x == winning_possibility.x3 <span class="hljs-keyword">and</span> point.y == winning_possibility.y3 <span class="hljs-keyword">and</span> point <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> X_points + O_points:  
                    point.set()  
                    <span class="hljs-keyword">return</span>  
        <span class="hljs-keyword">elif</span> winning_possibility.p2_satisfied <span class="hljs-keyword">and</span> winning_possibility.p3_satisfied:  
            <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:  
                <span class="hljs-keyword">if</span> point.x == winning_possibility.x1 <span class="hljs-keyword">and</span> point.y == winning_possibility.y1 <span class="hljs-keyword">and</span> point <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> X_points + O_points:  
                    point.set()  
                    <span class="hljs-keyword">return</span>  
        <span class="hljs-keyword">elif</span> winning_possibility.p3_satisfied <span class="hljs-keyword">and</span> winning_possibility.p1_satisfied:  
            <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:  
                <span class="hljs-keyword">if</span> point.x == winning_possibility.x2 <span class="hljs-keyword">and</span> point.y == winning_possibility.y2 <span class="hljs-keyword">and</span> point <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> X_points + O_points:  
                    point.set()  
                    <span class="hljs-keyword">return</span>  

    <span class="hljs-comment"># If the opponent can win in the next move  </span>
    <span class="hljs-keyword">for</span> winning_possibility <span class="hljs-keyword">in</span> winning_possibilities:  
        winning_possibility.check(<span class="hljs-string">'X'</span>)  
        <span class="hljs-keyword">if</span> winning_possibility.p1_satisfied <span class="hljs-keyword">and</span> winning_possibility.p2_satisfied:  
            <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:  
                <span class="hljs-keyword">if</span> point.x == winning_possibility.x3 <span class="hljs-keyword">and</span> point.y == winning_possibility.y3 <span class="hljs-keyword">and</span> point <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> X_points + O_points:  
                    point.set()  
                    <span class="hljs-keyword">return</span>  
        <span class="hljs-keyword">elif</span> winning_possibility.p2_satisfied <span class="hljs-keyword">and</span> winning_possibility.p3_satisfied:  
            <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:  
                <span class="hljs-keyword">if</span> point.x == winning_possibility.x1 <span class="hljs-keyword">and</span> point.y == winning_possibility.y1 <span class="hljs-keyword">and</span> point <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> X_points + O_points:  
                    point.set()  
                    <span class="hljs-keyword">return</span>  
        <span class="hljs-keyword">elif</span> winning_possibility.p3_satisfied <span class="hljs-keyword">and</span> winning_possibility.p1_satisfied:  
            <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:  
                <span class="hljs-keyword">if</span> point.x == winning_possibility.x2 <span class="hljs-keyword">and</span> point.y == winning_possibility.y2 <span class="hljs-keyword">and</span> point <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> X_points + O_points:  
                    point.set()  
                    <span class="hljs-keyword">return</span>  

    <span class="hljs-comment"># If the center is free...  </span>
    center_occupied = <span class="hljs-literal">False</span>  
    <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> X_points + O_points:  
        <span class="hljs-keyword">if</span> point.x == <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> point.y == <span class="hljs-number">2</span>:  
            center_occupied = <span class="hljs-literal">True</span>  
            <span class="hljs-keyword">break</span>
     <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> center_occupied:  
        <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:  
            <span class="hljs-keyword">if</span> point.x == <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> point.y == <span class="hljs-number">2</span>:  
                point.set()  
                <span class="hljs-keyword">return</span>  

    <span class="hljs-comment"># Occupy corner or middle based on what opponent occupies  </span>
    corner_points = [(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>), (<span class="hljs-number">1</span>, <span class="hljs-number">3</span>), (<span class="hljs-number">3</span>, <span class="hljs-number">1</span>), (<span class="hljs-number">3</span>, <span class="hljs-number">3</span>)]  
    middle_points = [(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>), (<span class="hljs-number">2</span>, <span class="hljs-number">1</span>), (<span class="hljs-number">2</span>, <span class="hljs-number">3</span>), (<span class="hljs-number">3</span>, <span class="hljs-number">2</span>)]  
    num_of_corner_points_occupied_by_X = <span class="hljs-number">0</span>  
    <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> X_points:
        <span class="hljs-keyword">if</span> (point.x, point.y) <span class="hljs-keyword">in</span> corner_points:  
            num_of_corner_points_occupied_by_X += <span class="hljs-number">1</span>  
    <span class="hljs-keyword">if</span> num_of_corner_points_occupied_by_X &gt;= <span class="hljs-number">2</span>:  
        <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:  
            <span class="hljs-keyword">if</span> (point.x, point.y) <span class="hljs-keyword">in</span> middle_points <span class="hljs-keyword">and</span> point <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> X_points + O_points:  
                point.set()  
                <span class="hljs-keyword">return</span>  
    <span class="hljs-keyword">elif</span> num_of_corner_points_occupied_by_X &lt; <span class="hljs-number">2</span>:  
        <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:  
            <span class="hljs-keyword">if</span> (point.x, point.y) <span class="hljs-keyword">in</span> corner_points <span class="hljs-keyword">and</span> point <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> X_points + O_points:  
                point.set()  
                <span class="hljs-keyword">return</span>
</code></pre>
<h2 id="heading-creating-a-button-to-toggle-play-with-a-computer-or-play-with-a-human">Creating a button to toggle play with a computer or play with a human</h2>
<p>Let’s create a button that can switch opponents as either human or computer, as well as make a callback to change the toggle button text and command.</p>
<pre><code class="lang-python">play_with = <span class="hljs-string">"Computer"</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">play_with_human</span>():</span>
    <span class="hljs-keyword">global</span> play_with
    play_with = <span class="hljs-string">"Human"</span>  <span class="hljs-comment"># switch opponent to human</span>
    play_with_button[<span class="hljs-string">'text'</span>] = <span class="hljs-string">"Play with computer"</span>  <span class="hljs-comment"># switch text</span>
    play_with_button[<span class="hljs-string">'command'</span>] = play_with_computer  <span class="hljs-comment"># switch command so that the user can play with the computer again, if required</span>
    play_again()  <span class="hljs-comment"># restart game</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">play_with_computer</span>():</span>
    <span class="hljs-keyword">global</span> play_with
    play_with = <span class="hljs-string">"Computer"</span>  <span class="hljs-comment"># switch opponent to computer</span>
    play_with_button[<span class="hljs-string">'text'</span>] = <span class="hljs-string">"Play with human"</span>  <span class="hljs-comment"># switch text</span>
    play_with_button[<span class="hljs-string">'command'</span>] = play_with_human  <span class="hljs-comment"># switch command so that the user can play with a human again, if required</span>
    play_again()  <span class="hljs-comment"># restart game</span>
play_with_button = tk.Button(root, text=<span class="hljs-string">'Play with human'</span>, font=(<span class="hljs-string">'Ariel'</span>, <span class="hljs-number">15</span>), command=play_with_human)
play_with_button.pack()
</code></pre>
<p>We need to call the function <code>auto_play</code> whenever it's O's turn and the value of <code>play_with</code> is <code>"Computer"</code>. For this, append the following code to the function <code>set</code> in class <code>XOPoint</code>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">if</span> play_with == <span class="hljs-string">"Computer"</span> <span class="hljs-keyword">and</span> status_label[<span class="hljs-string">'text'</span>] == <span class="hljs-string">"O's turn"</span>:
    auto_play()
</code></pre>
<h2 id="heading-result">Result</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1651581368987/gCi8Q69sv.gif" alt="Tic Tac Toe with Python tkinter demo" />
If you find this article useful, drop a like ⭐ and follow me to get all my latest content.<br />Full code in GitHub repository: github.com/jothin-kumar/tic-tac-toe/</p>
]]></content:encoded></item><item><title><![CDATA[Tic Tac Toe 🎮 with HTML, CSS and JS - part 1]]></title><description><![CDATA[In this tutorial, we will be creating a basic Tic Tac Toe game with HTML, CSS and JavaScript.Python version: https://blog.jothin.tech/tic-tac-toe-with-python-tkinter-part-1  
The webpage 👀
Let's go ahead and create a GUI for the game.Step 1: Create ...]]></description><link>https://blog.jothin.tech/tic-tac-toe-with-html-css-and-js-part-1</link><guid isPermaLink="true">https://blog.jothin.tech/tic-tac-toe-with-html-css-and-js-part-1</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[HTML]]></category><category><![CDATA[CSS]]></category><category><![CDATA[js]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Jothin kumar]]></dc:creator><pubDate>Wed, 16 Mar 2022 18:11:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1647453614340/ZsVRxszJx.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this tutorial, we will be creating a basic Tic Tac Toe game with HTML, CSS and JavaScript.<br /><strong>Python version: https://blog.jothin.tech/tic-tac-toe-with-python-tkinter-part-1</strong>  </p>
<h2 id="heading-the-webpage">The webpage 👀</h2>
<p>Let's go ahead and create a GUI for the game.<br /><strong>Step 1:</strong> Create webpage and add some CSS.</p>
<ul>
<li><strong>index.html</strong></li>
</ul>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Tic Tac Toe<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"style.css"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Tic Tac Toe<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"play-area"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square1"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square2"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square3"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square5"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square6"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square7"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square8"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square9"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<ul>
<li><strong>style.css</strong></li>
</ul>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">text-align</span>: center;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">50%</span>;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">50%</span>, -<span class="hljs-number">50%</span>);
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">box-shadow</span>: black <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">10px</span>;
}
<span class="hljs-selector-tag">h1</span> {
    <span class="hljs-attribute">color</span>: red;
}
<span class="hljs-selector-id">#play-area</span> {
    <span class="hljs-attribute">border</span>: black solid <span class="hljs-number">2px</span>;
    <span class="hljs-attribute">overflow</span>: hidden;
}
<span class="hljs-selector-class">.square</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">5em</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">5em</span>;
    <span class="hljs-attribute">float</span>: left;
    <span class="hljs-attribute">border</span>: black solid <span class="hljs-number">1px</span>;
    <span class="hljs-attribute">background-color</span>: white;
    <span class="hljs-attribute">cursor</span>: pointer;
}
<span class="hljs-selector-class">.square</span><span class="hljs-selector-pseudo">:hover</span> {
    <span class="hljs-attribute">background-color</span>: orange;
    <span class="hljs-attribute">color</span>: white;
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1647349835032/P41wNLY6A.gif" alt="Tic Tac Toe webpage interface with HTML and CSS" /></p>
<p><strong>Step 2:</strong> Make the webpage functional with JavaScript.</p>
<ul>
<li><strong>script.js</strong></li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> currentChr = <span class="hljs-string">"X"</span>;
<span class="hljs-keyword">let</span> XPoint = [];
<span class="hljs-keyword">let</span> OPoint = [];

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">XOSquare</span> </span>{
    <span class="hljs-keyword">constructor</span>(x, y, buttonId) {
        <span class="hljs-built_in">this</span>.x = x;
        <span class="hljs-built_in">this</span>.y = y;
        <span class="hljs-built_in">this</span>.button = <span class="hljs-built_in">document</span>.getElementById(buttonId);
        <span class="hljs-built_in">this</span>.button.onclick = <span class="hljs-function">() =&gt;</span> {
            <span class="hljs-built_in">this</span>.set(buttonId)
        }
    }
    set(buttonId) {
        <span class="hljs-built_in">this</span>.button = <span class="hljs-built_in">document</span>.getElementById(buttonId);
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.button.innerText === <span class="hljs-string">""</span>) {
            <span class="hljs-built_in">this</span>.button.innerText = currentChr;
            switchChr();
        }
    }
    reset() {
        <span class="hljs-built_in">this</span>.button.innerText = <span class="hljs-string">""</span>;
    }
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">switchChr</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">if</span> (currentChr === <span class="hljs-string">"X"</span>) {
        currentChr = <span class="hljs-string">"O"</span>;
    } <span class="hljs-keyword">else</span> {
        currentChr = <span class="hljs-string">"X"</span>;
    }
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setup</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> squares = [];
    <span class="hljs-keyword">let</span> squareElements = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"square"</span>);
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; squareElements.length; i++) {
        <span class="hljs-keyword">let</span> square = <span class="hljs-keyword">new</span> XOSquare(i % <span class="hljs-number">3</span>, <span class="hljs-built_in">Math</span>.floor(i / <span class="hljs-number">3</span>), squareElements[i].id);
        squares.push(square);
    }
}
<span class="hljs-built_in">window</span>.onload = setup;
</code></pre>
<p>Add this to <strong>index.html</strong> under <strong>head</strong> tag.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"script.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1647350472573/-Mozu1IX0.gif" alt="Tic Tac Toe functional webpage interface with HTML, CSS and JavaScript" /></p>
<h2 id="heading-detect-win-and-draw">Detect win and draw 🤔</h2>
<p>Let's now implement a logic to detect win/draw.<br /><strong>Step 3:</strong> Implement logic to detect win.<br />We need to check after each move if X or O won the game. There are 8 possible ways in which one can win Tic Tac Toe:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1646563368479/YUL7azLEZ.png" alt="8 possible ways of winning Tic Tac Toe" /></p>
<p>Let's add some the JavaScript in <strong>script.js</strong> to detect game win.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> currentChr = <span class="hljs-string">"X"</span>;
<span class="hljs-keyword">let</span> XPoint = [];
<span class="hljs-keyword">let</span> OPoint = [];

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">XOSquare</span> </span>{
    <span class="hljs-keyword">constructor</span>(x, y, buttonId) {
        <span class="hljs-built_in">this</span>.x = x;
        <span class="hljs-built_in">this</span>.y = y;
        <span class="hljs-built_in">this</span>.button = <span class="hljs-built_in">document</span>.getElementById(buttonId);
        <span class="hljs-built_in">this</span>.button.onclick = <span class="hljs-function">() =&gt;</span> {
            <span class="hljs-built_in">this</span>.set(buttonId)
        }
    }
    set(buttonId) {
        <span class="hljs-built_in">this</span>.button = <span class="hljs-built_in">document</span>.getElementById(buttonId);
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.button.innerText === <span class="hljs-string">""</span>) {
            <span class="hljs-built_in">this</span>.button.innerText = currentChr;
            <span class="hljs-keyword">if</span> (currentChr === <span class="hljs-string">"X"</span>) {
                XPoint.push(<span class="hljs-built_in">this</span>);
            } <span class="hljs-keyword">else</span> {
                OPoint.push(<span class="hljs-built_in">this</span>);
            }
            switchChr();
            checkWin();
        }
    }
    reset() {
        <span class="hljs-built_in">this</span>.button.innerText = <span class="hljs-string">""</span>;
    }
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">winningPossibility</span> </span>{
    <span class="hljs-keyword">constructor</span>(x1, y1, x2, y2, x3, y3) {
        <span class="hljs-built_in">this</span>.x1 = x1;
        <span class="hljs-built_in">this</span>.y1 = y1;
        <span class="hljs-built_in">this</span>.x2 = x2;
        <span class="hljs-built_in">this</span>.y2 = y2;
        <span class="hljs-built_in">this</span>.x3 = x3;
        <span class="hljs-built_in">this</span>.y3 = y3;
    }
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkWinningPossibility</span>(<span class="hljs-params">winningPossibility, forChr</span>) </span>{
    <span class="hljs-keyword">let</span> p1Satisfied = <span class="hljs-literal">false</span>;
    <span class="hljs-keyword">let</span> p2Satisfied = <span class="hljs-literal">false</span>;
    <span class="hljs-keyword">let</span> p3Satisfied = <span class="hljs-literal">false</span>;
    <span class="hljs-keyword">if</span> (forChr === <span class="hljs-string">'X'</span>) {
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; XPoint.length; i++) {
            <span class="hljs-keyword">if</span> (XPoint[i].x === winningPossibility.x1 &amp;&amp; XPoint[i].y === winningPossibility.y1) {
                p1Satisfied = <span class="hljs-literal">true</span>;
            }
            <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (XPoint[i].x === winningPossibility.x2 &amp;&amp; XPoint[i].y === winningPossibility.y2) {
                p2Satisfied = <span class="hljs-literal">true</span>;
            }
            <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (XPoint[i].x === winningPossibility.x3 &amp;&amp; XPoint[i].y === winningPossibility.y3) {
                p3Satisfied = <span class="hljs-literal">true</span>;
            }
        }
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; OPoint.length; i++) {
            <span class="hljs-keyword">if</span> (OPoint[i].x === winningPossibility.x1 &amp;&amp; OPoint[i].y === winningPossibility.y1) {
                p1Satisfied = <span class="hljs-literal">true</span>;
            }
            <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (OPoint[i].x === winningPossibility.x2 &amp;&amp; OPoint[i].y === winningPossibility.y2) {
                p2Satisfied = <span class="hljs-literal">true</span>;
            }
            <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (OPoint[i].x === winningPossibility.x3 &amp;&amp; OPoint[i].y === winningPossibility.y3) {
                p3Satisfied = <span class="hljs-literal">true</span>;
            }
        }
    }
    <span class="hljs-keyword">return</span> p1Satisfied &amp;&amp; p2Satisfied &amp;&amp; p3Satisfied;
}
<span class="hljs-keyword">const</span> winningPossibilities = [
    <span class="hljs-keyword">new</span> winningPossibility(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>),
    <span class="hljs-keyword">new</span> winningPossibility(<span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>),
    <span class="hljs-keyword">new</span> winningPossibility(<span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>),
    <span class="hljs-keyword">new</span> winningPossibility(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">1</span>),
    <span class="hljs-keyword">new</span> winningPossibility(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>),
    <span class="hljs-keyword">new</span> winningPossibility(<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>),
    <span class="hljs-keyword">new</span> winningPossibility(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>),
    <span class="hljs-keyword">new</span> winningPossibility(<span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>)
]
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkWin</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; winningPossibilities.length; i++) {
        <span class="hljs-keyword">if</span> (checkWinningPossibility(winningPossibilities[i], <span class="hljs-string">'X'</span>)) {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"X wins"</span>);
            <span class="hljs-keyword">return</span>;
        }
        <span class="hljs-keyword">if</span> (checkWinningPossibility(winningPossibilities[i], <span class="hljs-string">'O'</span>)) {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"O wins"</span>);
            <span class="hljs-keyword">return</span>;
        }
    }
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setup</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> squares = [];
    <span class="hljs-keyword">let</span> squareElements = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"square"</span>);
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; squareElements.length; i++) {
        <span class="hljs-keyword">let</span> square = <span class="hljs-keyword">new</span> XOSquare(i % <span class="hljs-number">3</span> + <span class="hljs-number">1</span>, <span class="hljs-built_in">Math</span>.floor(i / <span class="hljs-number">3</span>) + <span class="hljs-number">1</span>, squareElements[i].id);
        squares.push(square);
    }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1647351570648/yJORhfNkG.gif" alt="Tic Tac Toe interface with HTML, CSS and JS" /></p>
<p>When X or O wins the game, console.log is triggered.<br /><strong>Step 4:</strong> Detect draw.<br />Append the following code to function "checkWin" in <strong>script.js</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> (XPoint.length + OPoint.length === <span class="hljs-number">9</span>) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Draw"</span>);
}
</code></pre>
<h2 id="heading-enhancements">Enhancements</h2>
<p><strong>Step 5:</strong> Add a status label and use it instead of console.log<br />Let's make a few changes to <strong>script.js</strong>:</p>
<ul>
<li>function <strong>"switchChr"</strong>:</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">switchChr</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> statusLabel = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"status"</span>);
    <span class="hljs-keyword">if</span> (currentChr === <span class="hljs-string">"X"</span>) {
        currentChr = <span class="hljs-string">"O"</span>;
        statusLabel.innerText = <span class="hljs-string">"O's turn"</span>;
    } <span class="hljs-keyword">else</span> {
        currentChr = <span class="hljs-string">"X"</span>;
        statusLabel.innerText = <span class="hljs-string">"X's turn"</span>;
    }
}
</code></pre>
<ul>
<li>function <strong>"checkWin"</strong>:</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkWin</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> statusLabel = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"status"</span>);
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; winningPossibilities.length; i++) {
        <span class="hljs-keyword">if</span> (checkWinningPossibility(winningPossibilities[i], <span class="hljs-string">'X'</span>)) {
            statusLabel.innerText = <span class="hljs-string">"X wins"</span>;
            disableGame();
            <span class="hljs-keyword">return</span>;
        }
        <span class="hljs-keyword">if</span> (checkWinningPossibility(winningPossibilities[i], <span class="hljs-string">'O'</span>)) {
            statusLabel.innerText = <span class="hljs-string">"O wins"</span>;
            disableGame();
            <span class="hljs-keyword">return</span>;
        }
    }
    <span class="hljs-keyword">if</span> (XPoint.length + OPoint.length === <span class="hljs-number">9</span>) {
        statusLabel.innerText = <span class="hljs-string">"Draw"</span>;
        disableGame();
    }
}
</code></pre>
<p>Add this new element in <strong>index.html</strong> under body tag</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"status"</span>&gt;</span>X's turn<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>Add the following to <strong>style.css</strong></p>
<pre><code class="lang-css"><span class="hljs-selector-id">#status</span> {
    <span class="hljs-attribute">color</span>: green;
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1647352737325/6eqi3M0Kz.gif" alt="Tic Tac Toe with HTML, CSS and JS with status label" /></p>
<p><strong>Step 6:</strong> Play again<br />Let's add a play again button so that we don't need to refresh the webpage if we want to replay. We need to create new functions in <strong>script.js</strong></p>
<ul>
<li>function "playAgain"</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">playAgain</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> buttons = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"square"</span>);
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; buttons.length; i++) {
        buttons[i].disabled = <span class="hljs-literal">false</span>;
        buttons[i].innerText = <span class="hljs-string">""</span>;
    }
    XPoint = [];
    OPoint = [];
    currentChr = <span class="hljs-string">"X"</span>;
    <span class="hljs-keyword">const</span> statusLabel = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"status"</span>);
    statusLabel.innerText = <span class="hljs-string">"X's turn"</span>;
    <span class="hljs-keyword">const</span> playAgainButton = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"play-again"</span>);
    playAgainButton.style.display = <span class="hljs-string">"none"</span>;
}
</code></pre>
<ul>
<li>function "disableGame":</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">disableGame</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> buttons = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"square"</span>);
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; buttons.length; i++) {
        buttons[i].disabled = <span class="hljs-literal">true</span>;
    }
    <span class="hljs-keyword">const</span> playAgainButton = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"play-again"</span>);
    playAgainButton.style.display = <span class="hljs-string">"block"</span>;
}
</code></pre>
<p>Add this element to <strong>index.html</strong> under body tag:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"play-again"</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"playAgain()"</span>&gt;</span>Play Again<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>Add this property to <strong>#play-area</strong> in <strong>style.css</strong>:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">margin-bottom</span>: 10<span class="hljs-selector-tag">px</span>;
</code></pre>
<p>Add some css for <strong>#play-again</strong> (play again button) in <strong>style.css</strong>:</p>
<pre><code class="lang-css"><span class="hljs-selector-id">#play-again</span> {
    <span class="hljs-attribute">box-shadow</span>: black <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">5px</span>;
    <span class="hljs-attribute">margin</span>: auto;
    <span class="hljs-attribute">display</span>: none;
}
</code></pre>
<p><strong>Step 7:</strong> Theme switch.<br />A webpage won't be complete without a cool theme switch. So, let's add one!<br />Add the following JS code to <strong>script.js</strong>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> currentTheme = <span class="hljs-string">'light'</span>;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">switchTheme</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">if</span> (currentTheme === <span class="hljs-string">'dark'</span>) {
        <span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">'.dark-mode'</span>).forEach(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">element</span>) </span>{
            element.classList.remove(<span class="hljs-string">'dark-mode'</span>);
            element.classList.add(<span class="hljs-string">'light-mode'</span>);
        });
        currentTheme = <span class="hljs-string">'light'</span>;
    }
    <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">'.light-mode'</span>).forEach(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">element</span>) </span>{
            element.classList.remove(<span class="hljs-string">'light-mode'</span>);
            element.classList.add(<span class="hljs-string">'dark-mode'</span>);
        });
        currentTheme = <span class="hljs-string">'dark'</span>;
    }
}
</code></pre>
<p>Let's rewrite the CSS:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span><span class="hljs-selector-class">.light-mode</span> {
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">text-align</span>: center;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">50%</span>;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">50%</span>, -<span class="hljs-number">50%</span>);
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">box-shadow</span>: black <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">10px</span>;
}
<span class="hljs-selector-tag">h1</span><span class="hljs-selector-class">.light-mode</span> {
    <span class="hljs-attribute">color</span>: red;
}
<span class="hljs-selector-id">#status</span><span class="hljs-selector-class">.light-mode</span> {
    <span class="hljs-attribute">color</span>: green;
}
<span class="hljs-selector-id">#play-area</span><span class="hljs-selector-class">.light-mode</span> {
    <span class="hljs-attribute">border</span>: black solid <span class="hljs-number">2px</span>;
    <span class="hljs-attribute">overflow</span>: hidden;
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">10px</span>;
}
<span class="hljs-selector-class">.square</span><span class="hljs-selector-class">.light-mode</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">5em</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">5em</span>;
    <span class="hljs-attribute">float</span>: left;
    <span class="hljs-attribute">border</span>: black solid <span class="hljs-number">1px</span>;
    <span class="hljs-attribute">background-color</span>: white;
    <span class="hljs-attribute">cursor</span>: pointer;
}
<span class="hljs-selector-class">.square</span><span class="hljs-selector-class">.light-mode</span><span class="hljs-selector-pseudo">:hover</span> {
    <span class="hljs-attribute">background-color</span>: orange;
    <span class="hljs-attribute">color</span>: white;
}
<span class="hljs-selector-class">.square</span><span class="hljs-selector-class">.clicked</span><span class="hljs-selector-class">.light-mode</span> {
    <span class="hljs-attribute">background-color</span>: red;
    <span class="hljs-attribute">color</span>: white;
}
<span class="hljs-selector-id">#play-again</span><span class="hljs-selector-class">.light-mode</span> {
    <span class="hljs-attribute">box-shadow</span>: black <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">5px</span>;
    <span class="hljs-attribute">margin</span>: auto;
    <span class="hljs-attribute">display</span>: none;
}

<span class="hljs-selector-tag">body</span><span class="hljs-selector-class">.dark-mode</span> {
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">text-align</span>: center;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">50%</span>;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">50%</span>, -<span class="hljs-number">50%</span>);
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">box-shadow</span>: white <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">background</span>: black;
}
<span class="hljs-selector-tag">h1</span><span class="hljs-selector-class">.dark-mode</span> {
    <span class="hljs-attribute">color</span>: white;
}
<span class="hljs-selector-id">#status</span><span class="hljs-selector-class">.dark-mode</span> {
    <span class="hljs-attribute">color</span>: blue;
}
<span class="hljs-selector-id">#play-area</span><span class="hljs-selector-class">.dark-mode</span> {
    <span class="hljs-attribute">border</span>: white solid <span class="hljs-number">2px</span>;
    <span class="hljs-attribute">overflow</span>: hidden;
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">10px</span>;
}
<span class="hljs-selector-class">.square</span><span class="hljs-selector-class">.dark-mode</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">5em</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">5em</span>;
    <span class="hljs-attribute">float</span>: left;
    <span class="hljs-attribute">border</span>: white solid <span class="hljs-number">1px</span>;
    <span class="hljs-attribute">background-color</span>: black;
    <span class="hljs-attribute">color</span>: white;
    <span class="hljs-attribute">cursor</span>: pointer;
}
<span class="hljs-selector-class">.square</span><span class="hljs-selector-class">.dark-mode</span><span class="hljs-selector-pseudo">:hover</span> {
    <span class="hljs-attribute">background-color</span>: gray;
    <span class="hljs-attribute">color</span>: white;
}
<span class="hljs-selector-id">#play-again</span><span class="hljs-selector-class">.dark-mode</span> {
    <span class="hljs-attribute">box-shadow</span>: black <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">5px</span>;
    <span class="hljs-attribute">margin</span>: auto;
    <span class="hljs-attribute">display</span>: none;
}
</code></pre>
<p>Let's change the body tag in <strong>index.html</strong>:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">body</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"light-mode"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"light-mode"</span>&gt;</span>Tic Tac Toe<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"status"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"light-mode"</span>&gt;</span>X's turn<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"theme-switch"</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"switchTheme()"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"light-mode"</span>&gt;</span>Switch Theme<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"play-area"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"light-mode"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square light-mode"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square1"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square light-mode"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square2"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square light-mode"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square3"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square light-mode"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square light-mode"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square5"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square light-mode"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square6"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square light-mode"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square7"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square light-mode"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square8"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square light-mode"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"square9"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"play-again"</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"playAgain()"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"light-mode"</span>&gt;</span>Play Again<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1647453110816/FqujNgEot.gif" alt="Tic Tac Toe with HTML, CSS and JS theme switch" /></p>
<p><strong>Full code available at GitHub repository: https://github.com/Jothin-kumar/tic-tac-toe</strong>  </p>
<p>If you find this article useful, drop a like ⭐ and follow me to get all my latest content.</p>
]]></content:encoded></item><item><title><![CDATA[Tic Tac Toe 🎮 with Python tkinter - part 1]]></title><description><![CDATA[In this tutorial, we will be creating a basic Tic Tac Toe game 🎮 with Python tkinter. If you are new to tkinter, refer this crash course:     https://blog.jothin.tech/getting-started-with-tkinter-crash-course  
Webpage version: https://blog.jothin.t...]]></description><link>https://blog.jothin.tech/tic-tac-toe-with-python-tkinter-part-1</link><guid isPermaLink="true">https://blog.jothin.tech/tic-tac-toe-with-python-tkinter-part-1</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python projects]]></category><category><![CDATA[GUI]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Jothin kumar]]></dc:creator><pubDate>Sun, 06 Mar 2022 14:53:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1646578267299/hM079NXNE.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this tutorial, we will be creating a basic Tic Tac Toe game 🎮 with Python tkinter. If you are new to tkinter, refer this crash course:     https://blog.jothin.tech/getting-started-with-tkinter-crash-course  </p>
<p><strong>Webpage version: https://blog.jothin.tech/tic-tac-toe-with-html-css-and-js-part-1</strong></p>
<h2 id="heading-the-gui">The GUI 👀</h2>
<p>Let's go ahead and create a GUI for the game.<br /><strong>Step 1:</strong> Create a tkinter window</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tkinter <span class="hljs-keyword">as</span> tk

root = tk.Tk()
root.resizable(<span class="hljs-literal">False</span>, <span class="hljs-literal">False</span>)
root.title(<span class="hljs-string">"Tic Tac Toe"</span>)
root.mainloop()
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1646555891994/fLQd6WfL2.png" alt="Screenshot of a basic tkinter window" /><br /><strong>Step 2:</strong> Add play area and a label with text "Tic Tac Toe"</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tkinter <span class="hljs-keyword">as</span> tk  

root = tk.Tk()  
root.resizable(<span class="hljs-literal">False</span>, <span class="hljs-literal">False</span>)  
root.title(<span class="hljs-string">"Tic Tac Toe"</span>)  

tk.Label(root, text=<span class="hljs-string">"Tic Tac Toe"</span>, font=(<span class="hljs-string">'Ariel'</span>, <span class="hljs-number">25</span>)).pack()  

play_area = tk.Frame(root, width=<span class="hljs-number">300</span>, height=<span class="hljs-number">300</span>, bg=<span class="hljs-string">'white'</span>)  
XO_points = []  
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">XOPoint</span>:</span>  
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, x, y</span>):</span>  
        self.x = x  
        self.y = y  
        self.value = <span class="hljs-literal">None</span>  
        self.button = tk.Button(play_area, text=<span class="hljs-string">""</span>, width=<span class="hljs-number">10</span>, height=<span class="hljs-number">5</span>)  
        self.button.grid(row=x, column=y)  

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">reset</span>(<span class="hljs-params">self</span>):</span>  
        self.button.configure(text=<span class="hljs-string">""</span>, bg=<span class="hljs-string">'white'</span>)  
        self.value = <span class="hljs-literal">None</span>  
<span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, <span class="hljs-number">4</span>):
    <span class="hljs-keyword">for</span> y <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, <span class="hljs-number">4</span>):
        XOPoint(x, y) 
play_area.pack(pady=<span class="hljs-number">10</span>, padx=<span class="hljs-number">10</span>)  

root.mainloop()
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1646556480858/YhdBUTbPm.png" alt="screenshot of a tkinter window with tic tac toe" />
<strong>Step 3:</strong> Make the GUI functional<br />Let's make the GUI functional by changing button text and color when clicked. For this, we need to make some changes to class "XOPoint" in code.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">XOPoint</span>:</span>  
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, x, y</span>):</span>
        self.x = x  
        self.y = y  
        self.value = <span class="hljs-literal">None</span>  
        self.button = tk.Button(play_area, text=<span class="hljs-string">""</span>, width=<span class="hljs-number">10</span>, height=<span class="hljs-number">5</span>, command=self.set)
        self.button.grid(row=x, column=y)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">global</span> current_chr
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> self.value:
            self.button.configure(text=current_chr, bg=<span class="hljs-string">'snow'</span>, fg=<span class="hljs-string">'black'</span>)
            self.value = current_chr 
            <span class="hljs-keyword">if</span> current_chr == <span class="hljs-string">"X"</span>:
                current_chr = <span class="hljs-string">"O"</span>
            <span class="hljs-keyword">elif</span> current_chr == <span class="hljs-string">"O"</span>:
                current_chr = <span class="hljs-string">"X"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">reset</span>(<span class="hljs-params">self</span>):</span>  
        self.button.configure(text=<span class="hljs-string">""</span>, bg=<span class="hljs-string">'white'</span>)  
        self.value = <span class="hljs-literal">None</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1646557832817/xtXcts6rK.gif" alt="Tic Tac Toe functional tkinter GUI" /></p>
<h2 id="heading-detect-win-and-draw">Detect win and draw 🤔</h2>
<p>Let's now implement a logic to detect win/draw.<br /><strong>Step 4:</strong> Implement logic to detect win<br />We need to check after each move if X or O won the game. There are 8 possible ways in which one can win Tic Tac Toe:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1646563368479/YUL7azLEZ.png" alt="8 possible ways of winning Tic Tac Toe" />
Let's modify the code to detect game win.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tkinter <span class="hljs-keyword">as</span> tk  

root = tk.Tk()  
root.resizable(<span class="hljs-literal">False</span>, <span class="hljs-literal">False</span>)  
root.title(<span class="hljs-string">"Tic Tac Toe"</span>)  

tk.Label(root, text=<span class="hljs-string">"Tic Tac Toe"</span>, font=(<span class="hljs-string">'Ariel'</span>, <span class="hljs-number">25</span>)).pack()
current_chr = <span class="hljs-string">"X"</span>

play_area = tk.Frame(root, width=<span class="hljs-number">300</span>, height=<span class="hljs-number">300</span>, bg=<span class="hljs-string">'white'</span>)  
X_points = []
O_points = []
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">XOPoint</span>:</span>  
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, x, y</span>):</span>
        self.x = x  
        self.y = y  
        self.value = <span class="hljs-literal">None</span>  
        self.button = tk.Button(play_area, text=<span class="hljs-string">""</span>, width=<span class="hljs-number">10</span>, height=<span class="hljs-number">5</span>, command=self.set)
        self.button.grid(row=x, column=y)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">global</span> current_chr
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> self.value:
            self.button.configure(text=current_chr, bg=<span class="hljs-string">'snow'</span>, fg=<span class="hljs-string">'black'</span>)
            self.value = current_chr 
            <span class="hljs-keyword">if</span> current_chr == <span class="hljs-string">"X"</span>:
                X_points.append(self)
                current_chr = <span class="hljs-string">"O"</span>
            <span class="hljs-keyword">elif</span> current_chr == <span class="hljs-string">"O"</span>:
                O_points.append(self)
                current_chr = <span class="hljs-string">"X"</span>
        check_win()

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">reset</span>(<span class="hljs-params">self</span>):</span>  
        self.button.configure(text=<span class="hljs-string">""</span>, bg=<span class="hljs-string">'white'</span>)  
        self.value = <span class="hljs-literal">None</span>
<span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, <span class="hljs-number">4</span>):
    <span class="hljs-keyword">for</span> y <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, <span class="hljs-number">4</span>):
        XOPoint(x, y)
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WinningPossibility</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, x1, y1, x2, y2, x3, y3</span>):</span>
        self.x1 = x1
        self.y1 = y1
        self.x2 = x2
        self.y2 = y2
        self.x3 = x3
        self.y3 = y3
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check</span>(<span class="hljs-params">self, for_chr</span>):</span>
        p1_satisfied = <span class="hljs-literal">False</span>
        p2_satisfied = <span class="hljs-literal">False</span>
        p3_satisfied = <span class="hljs-literal">False</span>
        <span class="hljs-keyword">if</span> for_chr == <span class="hljs-string">'X'</span>:
            <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> X_points:
                <span class="hljs-keyword">if</span> point.x == self.x1 <span class="hljs-keyword">and</span> point.y == self.y1:
                    p1_satisfied = <span class="hljs-literal">True</span>
                <span class="hljs-keyword">elif</span> point.x == self.x2 <span class="hljs-keyword">and</span> point.y == self.y2:
                    p2_satisfied = <span class="hljs-literal">True</span>
                <span class="hljs-keyword">elif</span> point.x == self.x3 <span class="hljs-keyword">and</span> point.y == self.y3:
                    p3_satisfied = <span class="hljs-literal">True</span>
        <span class="hljs-keyword">elif</span> for_chr == <span class="hljs-string">'O'</span>:
            <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> O_points:
                <span class="hljs-keyword">if</span> point.x == self.x1 <span class="hljs-keyword">and</span> point.y == self.y1:
                    p1_satisfied = <span class="hljs-literal">True</span>
                <span class="hljs-keyword">elif</span> point.x == self.x2 <span class="hljs-keyword">and</span> point.y == self.y2:
                    p2_satisfied = <span class="hljs-literal">True</span>
                <span class="hljs-keyword">elif</span> point.x == self.x3 <span class="hljs-keyword">and</span> point.y == self.y3:
                    p3_satisfied = <span class="hljs-literal">True</span>
        <span class="hljs-keyword">return</span> all([p1_satisfied, p2_satisfied, p3_satisfied])
winning_possibilities = [
    WinningPossibility(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>),
    WinningPossibility(<span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>),
    WinningPossibility(<span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>),
    WinningPossibility(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">1</span>),
    WinningPossibility(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>),
    WinningPossibility(<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>),
    WinningPossibility(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>),
    WinningPossibility(<span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>)
]
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_win</span>():</span>
    <span class="hljs-keyword">for</span> possibility <span class="hljs-keyword">in</span> winning_possibilities:
        <span class="hljs-keyword">if</span> possibility.check(<span class="hljs-string">'X'</span>):
            print(<span class="hljs-string">"X won!"</span>)
            <span class="hljs-keyword">return</span>
        <span class="hljs-keyword">elif</span> possibility.check(<span class="hljs-string">'O'</span>):
            print(<span class="hljs-string">"O won!"</span>)
            <span class="hljs-keyword">return</span>
play_area.pack(pady=<span class="hljs-number">10</span>, padx=<span class="hljs-number">10</span>)  

root.mainloop()
</code></pre>
<p><strong>Step 5:</strong> Detect draw<br />If all 9 squares were filled and still no one won the game, it's a draw! Detecting game draw is simple. Just append the following code to the function "check_win".</p>
<pre><code class="lang-python"><span class="hljs-keyword">if</span> len(X_points) + len(O_points) == <span class="hljs-number">9</span>:
        print(<span class="hljs-string">"Draw!"</span>)
</code></pre>
<h2 id="heading-enhancements">Enhancements</h2>
<p>Now that everything works fine, we can improve it further.<br /><strong>Step 6:</strong> Status Label<br />Tic Tac Toe is a GUI game and displaying game result in GUI is better than printing them in console. So, let's create a tkinter Label via which we can display result. Add the following code:</p>
<pre><code class="lang-python">status_label = tk.Label(root, text=<span class="hljs-string">""</span>, font=(<span class="hljs-string">'Ariel'</span>, <span class="hljs-number">15</span>), bg=<span class="hljs-string">'green'</span>, fg=<span class="hljs-string">'snow'</span>)
status_label.pack(fill=tk.X)
</code></pre>
<p>Also, we need to make some changes to function "check_win":</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_win</span>():</span>
    <span class="hljs-keyword">for</span> possibility <span class="hljs-keyword">in</span> winning_possibilities:
        <span class="hljs-keyword">if</span> possibility.check(<span class="hljs-string">'X'</span>):
            status_label.configure(text=<span class="hljs-string">"X won!"</span>)
            <span class="hljs-keyword">return</span>
        <span class="hljs-keyword">elif</span> possibility.check(<span class="hljs-string">'O'</span>):
            status_label.configure(text=<span class="hljs-string">"O won!"</span>)
            <span class="hljs-keyword">return</span>
    <span class="hljs-keyword">if</span> len(X_points) + len(O_points) == <span class="hljs-number">9</span>:
        status_label.configure(text=<span class="hljs-string">"Draw!"</span>)
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1646573789896/3i-aArFXi.gif" alt="Python tkinter Tic Tac Toe working demo" />
<strong>Step 7:</strong> Display whose turn it is<br />The status label is not used till someone wins the game. Let's use it to display if it's X's turn or O's turn! We need to make some changes to function "set" in class "XOPoint".</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">global</span> current_chr
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> self.value:
            self.button.configure(text=current_chr, bg=<span class="hljs-string">'snow'</span>, fg=<span class="hljs-string">'black'</span>)
            self.value = current_chr
            <span class="hljs-keyword">if</span> current_chr == <span class="hljs-string">"X"</span>:
                X_points.append(self)
                current_chr = <span class="hljs-string">"O"</span>
                status_label.configure(text=<span class="hljs-string">"O's turn"</span>)
            <span class="hljs-keyword">elif</span> current_chr == <span class="hljs-string">"O"</span>:
                O_points.append(self)
                current_chr = <span class="hljs-string">"X"</span>
                status_label.configure(text=<span class="hljs-string">"X's turn"</span>)
        check_win()
</code></pre>
<p>Also, the text property of status label must be changed:</p>
<pre><code class="lang-python">status_label = tk.Label(root, text=<span class="hljs-string">"X's turn"</span>, font=(<span class="hljs-string">'Ariel'</span>, <span class="hljs-number">15</span>), bg=<span class="hljs-string">'green'</span>, fg=<span class="hljs-string">'snow'</span>)
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1646574794546/B1iaYgOTO.gif" alt="Python tkinter Tic Tac Toe working demo" />
<strong>Step 8:</strong> Create Play again button<br />Once the game is over, the game needs to be disabled and a button to play the game again must be displayed. Let's add the following code to disable the game once it is over:</p>
<pre><code class="lang-python">XO_points = []
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">disable_game</span>():</span>
    <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:
        point.button.configure(state=tk.DISABLED)
</code></pre>
<p>We need to make changes to the function "check_win" and to the for loops that create "XOPoint" objects:</p>
<pre><code class="lang-python"><span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, <span class="hljs-number">4</span>):
    <span class="hljs-keyword">for</span> y <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, <span class="hljs-number">4</span>):
        XO_points.append(XOPoint(x, y))

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_win</span>():</span>
    <span class="hljs-keyword">for</span> possibility <span class="hljs-keyword">in</span> winning_possibilities:
        <span class="hljs-keyword">if</span> possibility.check(<span class="hljs-string">'X'</span>):
            status_label.configure(text=<span class="hljs-string">"X won!"</span>)
            disable_game()
            <span class="hljs-keyword">return</span>
        <span class="hljs-keyword">elif</span> possibility.check(<span class="hljs-string">'O'</span>):
            status_label.configure(text=<span class="hljs-string">"O won!"</span>)
            disable_game()
            <span class="hljs-keyword">return</span>
    <span class="hljs-keyword">if</span> len(X_points) + len(O_points) == <span class="hljs-number">9</span>:
        status_label.configure(text=<span class="hljs-string">"Draw!"</span>)
        disable_game()
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1646575620434/t_RZjeoVk.gif" alt="Python tkinter Tic Tac Toe working demo" />
Add the following code to display Play again button once the game is over:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">play_again</span>():</span>
    <span class="hljs-keyword">global</span> current_chr
    current_chr = <span class="hljs-string">'X'</span>
    <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:
        point.button.configure(state=tk.NORMAL)
        point.reset()
    status_label.configure(text=<span class="hljs-string">"X's turn"</span>)
    play_again_button.pack_forget()
play_again_button = tk.Button(root, text=<span class="hljs-string">'Play again'</span>, font=(<span class="hljs-string">'Ariel'</span>, <span class="hljs-number">15</span>), command=play_again)
</code></pre>
<p>We also need to make changes to function "disable_game" and function "reset" in class "XOPoint":</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">disable_game</span>():</span>
    <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:
        point.button.configure(state=tk.DISABLED)
    play_again_button.pack()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">reset</span>(<span class="hljs-params">self</span>):</span>
        self.button.configure(text=<span class="hljs-string">""</span>, bg=<span class="hljs-string">'lightgray'</span>)
        <span class="hljs-keyword">if</span> self.value == <span class="hljs-string">"X"</span>:
            X_points.remove(self)
        <span class="hljs-keyword">elif</span> self.value == <span class="hljs-string">"O"</span>:
            O_points.remove(self)
        self.value = <span class="hljs-literal">None</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1646576404833/tLwM-yGes.gif" alt="Python tkinter Tic Tac Toe working demo" /></p>
<h2 id="heading-summary">Summary</h2>
<p>The steps done in this tutorial are:</p>
<ol>
<li>Create a tkinter window.</li>
<li>Add play area and a label with text "Tic Tac Toe".</li>
<li>Make the GUI functional.</li>
<li>Implement logic to detect win.</li>
<li>Detect draw.</li>
<li>Status Label.</li>
<li>Display whose turn it is.</li>
<li>Create Play again button.</li>
</ol>
<p><strong>Final code:</strong></p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tkinter <span class="hljs-keyword">as</span> tk

root = tk.Tk()
root.resizable(<span class="hljs-literal">False</span>, <span class="hljs-literal">False</span>)
root.title(<span class="hljs-string">"Tic Tac Toe"</span>)

tk.Label(root, text=<span class="hljs-string">"Tic Tac Toe"</span>, font=(<span class="hljs-string">'Ariel'</span>, <span class="hljs-number">25</span>)).pack()
status_label = tk.Label(root, text=<span class="hljs-string">"X's turn"</span>, font=(<span class="hljs-string">'Ariel'</span>, <span class="hljs-number">15</span>), bg=<span class="hljs-string">'green'</span>, fg=<span class="hljs-string">'snow'</span>)
status_label.pack(fill=tk.X)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">play_again</span>():</span>
    <span class="hljs-keyword">global</span> current_chr
    current_chr = <span class="hljs-string">'X'</span>
    <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:
        point.button.configure(state=tk.NORMAL)
        point.reset()
    status_label.configure(text=<span class="hljs-string">"X's turn"</span>)
    play_again_button.pack_forget()
play_again_button = tk.Button(root, text=<span class="hljs-string">'Play again'</span>, font=(<span class="hljs-string">'Ariel'</span>, <span class="hljs-number">15</span>), command=play_again)

current_chr = <span class="hljs-string">"X"</span>

play_area = tk.Frame(root, width=<span class="hljs-number">300</span>, height=<span class="hljs-number">300</span>, bg=<span class="hljs-string">'white'</span>)
XO_points = []
X_points = []
O_points = []
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">XOPoint</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, x, y</span>):</span>
        self.x = x
        self.y = y
        self.value = <span class="hljs-literal">None</span>
        self.button = tk.Button(play_area, text=<span class="hljs-string">""</span>, width=<span class="hljs-number">10</span>, height=<span class="hljs-number">5</span>, command=self.set)
        self.button.grid(row=x, column=y)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">global</span> current_chr
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> self.value:
            self.button.configure(text=current_chr, bg=<span class="hljs-string">'snow'</span>, fg=<span class="hljs-string">'black'</span>)
            self.value = current_chr
            <span class="hljs-keyword">if</span> current_chr == <span class="hljs-string">"X"</span>:
                X_points.append(self)
                current_chr = <span class="hljs-string">"O"</span>
                status_label.configure(text=<span class="hljs-string">"O's turn"</span>)
            <span class="hljs-keyword">elif</span> current_chr == <span class="hljs-string">"O"</span>:
                O_points.append(self)
                current_chr = <span class="hljs-string">"X"</span>
                status_label.configure(text=<span class="hljs-string">"X's turn"</span>)
        check_win()

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">reset</span>(<span class="hljs-params">self</span>):</span>
        self.button.configure(text=<span class="hljs-string">""</span>, bg=<span class="hljs-string">'lightgray'</span>)
        <span class="hljs-keyword">if</span> self.value == <span class="hljs-string">"X"</span>:
            X_points.remove(self)
        <span class="hljs-keyword">elif</span> self.value == <span class="hljs-string">"O"</span>:
            O_points.remove(self)
        self.value = <span class="hljs-literal">None</span>
<span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, <span class="hljs-number">4</span>):
    <span class="hljs-keyword">for</span> y <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, <span class="hljs-number">4</span>):
        XO_points.append(XOPoint(x, y))
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WinningPossibility</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, x1, y1, x2, y2, x3, y3</span>):</span>
        self.x1 = x1
        self.y1 = y1
        self.x2 = x2
        self.y2 = y2
        self.x3 = x3
        self.y3 = y3
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check</span>(<span class="hljs-params">self, for_chr</span>):</span>
        p1_satisfied = <span class="hljs-literal">False</span>
        p2_satisfied = <span class="hljs-literal">False</span>
        p3_satisfied = <span class="hljs-literal">False</span>
        <span class="hljs-keyword">if</span> for_chr == <span class="hljs-string">'X'</span>:
            <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> X_points:
                <span class="hljs-keyword">if</span> point.x == self.x1 <span class="hljs-keyword">and</span> point.y == self.y1:
                    p1_satisfied = <span class="hljs-literal">True</span>
                <span class="hljs-keyword">elif</span> point.x == self.x2 <span class="hljs-keyword">and</span> point.y == self.y2:
                    p2_satisfied = <span class="hljs-literal">True</span>
                <span class="hljs-keyword">elif</span> point.x == self.x3 <span class="hljs-keyword">and</span> point.y == self.y3:
                    p3_satisfied = <span class="hljs-literal">True</span>
        <span class="hljs-keyword">elif</span> for_chr == <span class="hljs-string">'O'</span>:
            <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> O_points:
                <span class="hljs-keyword">if</span> point.x == self.x1 <span class="hljs-keyword">and</span> point.y == self.y1:
                    p1_satisfied = <span class="hljs-literal">True</span>
                <span class="hljs-keyword">elif</span> point.x == self.x2 <span class="hljs-keyword">and</span> point.y == self.y2:
                    p2_satisfied = <span class="hljs-literal">True</span>
                <span class="hljs-keyword">elif</span> point.x == self.x3 <span class="hljs-keyword">and</span> point.y == self.y3:
                    p3_satisfied = <span class="hljs-literal">True</span>
        <span class="hljs-keyword">return</span> all([p1_satisfied, p2_satisfied, p3_satisfied])
winning_possibilities = [
    WinningPossibility(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>),
    WinningPossibility(<span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>),
    WinningPossibility(<span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>),
    WinningPossibility(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">1</span>),
    WinningPossibility(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>),
    WinningPossibility(<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>),
    WinningPossibility(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>),
    WinningPossibility(<span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>)
]
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">disable_game</span>():</span>
    <span class="hljs-keyword">for</span> point <span class="hljs-keyword">in</span> XO_points:
        point.button.configure(state=tk.DISABLED)
    play_again_button.pack()
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_win</span>():</span>
    <span class="hljs-keyword">for</span> possibility <span class="hljs-keyword">in</span> winning_possibilities:
        <span class="hljs-keyword">if</span> possibility.check(<span class="hljs-string">'X'</span>):
            status_label.configure(text=<span class="hljs-string">"X won!"</span>)
            disable_game()
            <span class="hljs-keyword">return</span>
        <span class="hljs-keyword">elif</span> possibility.check(<span class="hljs-string">'O'</span>):
            status_label.configure(text=<span class="hljs-string">"O won!"</span>)
            disable_game()
            <span class="hljs-keyword">return</span>
    <span class="hljs-keyword">if</span> len(X_points) + len(O_points) == <span class="hljs-number">9</span>:
        status_label.configure(text=<span class="hljs-string">"Draw!"</span>)
        disable_game()
play_area.pack(pady=<span class="hljs-number">10</span>, padx=<span class="hljs-number">10</span>)

root.mainloop()
</code></pre>
<p>GitHub repo link: https://github.com/Jothin-kumar/tic-tac-toe
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1646576404833/tLwM-yGes.gif" alt="Python tkinter Tic Tac Toe working demo" />
If you find this article useful, drop a like ⭐ and follow me to get all my latest content.<br />Part 2 of this tutorial: https://blog.jothin.tech/tic-tac-toe-with-python-tkinter-part-2</p>
]]></content:encoded></item><item><title><![CDATA[Getting started with tkinter - crash course]]></title><description><![CDATA[What is GUI? 🤔
GUI stands for Graphical user interface. Unlike text based interfaces (terminals), GUI uses graphical and interactive components for the user to interact with.
What is tkinter?

tkinter is an easy to use and standard GUI for Python. 
...]]></description><link>https://blog.jothin.tech/getting-started-with-tkinter-crash-course</link><guid isPermaLink="true">https://blog.jothin.tech/getting-started-with-tkinter-crash-course</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[GUI]]></category><dc:creator><![CDATA[Jothin kumar]]></dc:creator><pubDate>Thu, 06 Jan 2022 11:11:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1641467371210/Cs5RiQpw15.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-what-is-gui">What is GUI? 🤔</h2>
<p>GUI stands for <strong>Graphical user interface</strong>. Unlike text based interfaces (<em>terminals</em>), GUI uses graphical and interactive components for the user to interact with.</p>
<h2 id="heading-what-is-tkinter">What is tkinter?</h2>
<ul>
<li>tkinter is an easy to use and standard GUI for Python. </li>
<li>tkinter stands for <strong>Tk interface</strong>.</li>
<li>tkinter is supported by most platforms including <strong>Linux</strong>, <strong>WIndows</strong> and <strong>macOS</strong>.</li>
</ul>
<h2 id="heading-summary">Summary:</h2>
<p>The topics covered in this tutorial are:</p>
<ul>
<li>Tkinter widgets</li>
<li>Tkinter message boxes</li>
<li>Tkinter simple dialogs</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641467296035/I3PMj_m5J.png" alt="Tkinter flowchart" /></p>
<h2 id="heading-before-you-start">Before you start:</h2>
<p>Make sure that the following requirements are installed:</p>
<ul>
<li>Python 3</li>
<li>tkinter</li>
</ul>
<h3 id="heading-installation-instructions-for-linux">Installation instructions for Linux.</h3>
<ul>
<li>Run the following commands in your terminal:</li>
</ul>
<pre><code class="lang-bash">sudo apt-get install python3 python3-tk
</code></pre>
<ul>
<li>Ensure proper installation of tkinter by running this command in terminal:</li>
</ul>
<pre><code class="lang-bash">python3 -m tkinter
</code></pre>
<ul>
<li><em>A window should popup after running this command.</em></li>
</ul>
<h3 id="heading-installation-instructions-for-windows">Installation instructions for Windows.</h3>
<ul>
<li>tkinter can be downloaded using <a target="_blank" href="https://www.python.org/downloads/">Python installer</a>. Run the following command in cmd after installing tkinter to ensure proper installation:</li>
</ul>
<pre><code class="lang-bash">python -m tkinter
</code></pre>
<ul>
<li><em>A window should popup after running this command.</em></li>
</ul>
<h2 id="heading-lets-start">Let's start!</h2>
<ul>
<li>All components of a GUI are placed inside a window. Here is the code to create a blank tkinter window:</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tkinter <span class="hljs-keyword">as</span> tk  <span class="hljs-comment"># Importing the tkinter module.</span>

my_window = tk.Tk()  <span class="hljs-comment"># Creating a window.</span>
my_window.mainloop()  <span class="hljs-comment"># mainloop should be called at the end of script for the window to function properly.</span>
</code></pre>
<h3 id="heading-widgets">Widgets</h3>
<p>The 3 basic widgets in tkinter are:</p>
<ul>
<li><strong>Label</strong> - <em>Used to display text.</em></li>
<li><strong>Button</strong> - <em>Interactive widget on which user can click on.</em></li>
<li><strong>Entry</strong> - <em>Interactive widget to get user input.</em></li>
</ul>
<h4 id="heading-label">Label</h4>
<p>The Label widget in tkinter can be used to display text of various sizes and styles. Here is the code to use Label widget in a window:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tkinter <span class="hljs-keyword">as</span> tk  <span class="hljs-comment"># Importing the tkinter module.</span>

my_window = tk.Tk()  <span class="hljs-comment"># Creating a window.</span>
my_label = tk.Label(text=<span class="hljs-string">'Hello, tkinter!'</span>)  <span class="hljs-comment"># Creating a Label.</span>
my_label.pack()  <span class="hljs-comment"># Displaying the Label in window.</span>
my_window.mainloop()  <span class="hljs-comment"># mainloop should be called at the end of script for the window to function properly.</span>
</code></pre>
<h5 id="heading-properties-of-a-label-widget">Properties of a Label widget.</h5>
<p>The major properties of a Label widget are:</p>
<ul>
<li><p>Text</p>
</li>
<li><p>Background colour</p>
</li>
<li><p>Foreground colour</p>
</li>
<li><p>Font family and size</p>
<p>Here is the code to make a Label widget with custom properties:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tkinter <span class="hljs-keyword">as</span> tk

my_window = tk.Tk()
my_label = tk.Label(
    text=<span class="hljs-string">'I am a label widget with custom properties'</span>,
    background=<span class="hljs-string">'black'</span>,  <span class="hljs-comment"># bg parameter can be used instead of background parameter as a short hand.</span>
    foreground=<span class="hljs-string">'white'</span>,  <span class="hljs-comment"># fg parameter can be used instead of foreground parameter as a short hand.</span>
    font=(<span class="hljs-string">'Ariel'</span>, <span class="hljs-number">25</span>)  <span class="hljs-comment"># Syntax: (font family, size).</span>
)
my_label.pack()
my_window.mainloop()
</code></pre>
</li>
</ul>
<h4 id="heading-button">Button</h4>
<p>The Button widget in tkinter can be used to call a command when clicked. Here is the code to use Button widget in a window:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tkinter <span class="hljs-keyword">as</span> tk  <span class="hljs-comment"># Importing the tkinter module.</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">command_to_be_called_when_button_is_pressed</span>():</span>
    print(<span class="hljs-string">'The button is pressed.'</span>)

my_window = tk.Tk()  <span class="hljs-comment"># Creating a window.</span>
my_button = tk.Button(text=<span class="hljs-string">'Click me'</span>, command=command_to_be_called_when_button_is_pressed)  <span class="hljs-comment"># Creating a Button.</span>
my_button.pack()  <span class="hljs-comment"># Displaying the Button widget in window.</span>
my_window.mainloop()  <span class="hljs-comment"># mainloop should be called at the end of script for the window to function properly.</span>
</code></pre>
<h5 id="heading-properties-of-a-button-widget">Properties of a Button widget.</h5>
<p>The major properties of a Button widget are:</p>
<ul>
<li><p>Text</p>
</li>
<li><p>Background colour</p>
</li>
<li><p>Foreground colour</p>
</li>
<li><p>Font</p>
</li>
<li><p>Command</p>
<p>Usage is the same as Label widget. Arguements can be passed.</p>
</li>
</ul>
<h4 id="heading-entry">Entry</h4>
<p>The Entry widget in tkinter can be used to get user input graphically. The text entered in an Entry widget can be obtained by <code>get()</code> method. Here is the code to use Entry widget along with Button widget in a window:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tkinter <span class="hljs-keyword">as</span> tk  <span class="hljs-comment"># Importing the tkinter module.</span>

my_window = tk.Tk()  <span class="hljs-comment"># Creating a window.</span>
my_entry = tk.Entry()  <span class="hljs-comment"># Creating a Entry widget.</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">submit</span>():</span>  <span class="hljs-comment"># Command to be called by the Button widget.</span>
    print(my_entry.get())

my_button = tk.Button(text=<span class="hljs-string">'Submit'</span>, command=submit)  <span class="hljs-comment"># Creating a Button widget.</span>
my_entry.pack()  <span class="hljs-comment"># Displaying the Entry widget in window.</span>
my_button.pack()  <span class="hljs-comment"># Displaying the Button widget in window.</span>
my_window.mainloop()  <span class="hljs-comment"># mainloop should be called at the end of script for the window to function properly.</span>
</code></pre>
<h5 id="heading-properties-of-an-entry-widget">Properties of an Entry widget:</h5>
<p>The major properties of an Entry widget are:</p>
<ul>
<li><p>Background colour</p>
</li>
<li><p>Foreground colour</p>
</li>
<li><p>Font family and size</p>
<p>Usage is the same as Label widget. Arguements can be passed.</p>
</li>
</ul>
<h3 id="heading-message-boxes">Message boxes</h3>
<p>Other than widgets, Message boxes can be used in tkinter for basic prompts. Message boxes cannot be used without a main window. The Message boxes available in tkinter can be classified into two types based on usage:</p>
<ol>
<li>Message boxes for showing information.</li>
<li>Message boxes for asking questions.</li>
</ol>
<h4 id="heading-message-boxes-for-showing-information">Message boxes for showing information.</h4>
<p>There are three message boxes for showing information. The code below explains them.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tkinter <span class="hljs-keyword">as</span> tk
<span class="hljs-keyword">from</span> tkinter <span class="hljs-keyword">import</span> messagebox

main_window = tk.Tk()

messagebox.showinfo(<span class="hljs-string">'Information title.'</span>, <span class="hljs-string">'Information description.'</span>)
messagebox.showwarning(<span class="hljs-string">'Warning title'</span>, <span class="hljs-string">'Warning description'</span>)
messagebox.showerror(<span class="hljs-string">'Error title'</span>, <span class="hljs-string">'Error description.'</span>)

main_window.mainloop()
</code></pre>
<h4 id="heading-message-boxes-for-asking-questions">Message boxes for asking questions.</h4>
<p>There are two message boxes for asking questions. The code below explains them.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tkinter <span class="hljs-keyword">as</span> tk
<span class="hljs-keyword">from</span> tkinter <span class="hljs-keyword">import</span> messagebox

main_window = tk.Tk()

user_likes_python = messagebox.askyesno(<span class="hljs-string">'yes or no question'</span>, <span class="hljs-string">'Do you like Python?'</span>)
<span class="hljs-comment"># The messagebox returns True if yes is selected, returns False if no is selected or message box is closed.</span>
<span class="hljs-keyword">if</span> user_likes_python:
    print(<span class="hljs-string">'You like Python'</span>)
retry = messagebox.askretrycancel(<span class="hljs-string">'retry or cancel?'</span>, <span class="hljs-string">'An error occured, please select retry or cancel.'</span>)  <span class="hljs-comment"># Returns True if retry is selected, returns False if cancel is selected or message box is closed.</span>
<span class="hljs-keyword">if</span> retry:
    print(<span class="hljs-string">'You selected retry'</span>)

main_window.mainloop()
</code></pre>
<h3 id="heading-simple-dialogs">Simple dialogs.</h3>
<p>Simple dialogs are like Message boxes and they too require a main window to run. Unlike Message boxes, Simple dialogs are used for getting input(<em>strings, integers and floats</em>). The code below explains how to get input using a simpledialog.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tkinter <span class="hljs-keyword">as</span> tk
<span class="hljs-keyword">from</span> tkinter <span class="hljs-keyword">import</span> simpledialog

main_window = tk.Tk()

name = simpledialog.askstring(<span class="hljs-string">'String input using tkinter simple dialog'</span>, <span class="hljs-string">'What is your name?'</span>)
age = simpledialog.askinteger(<span class="hljs-string">'Integer input using tkinter simple dialog'</span>, <span class="hljs-string">'What is your age?'</span>)
favourite_decimal_num = simpledialog.askfloat(<span class="hljs-string">'Float input using tkinter simple dialog'</span>, <span class="hljs-string">'What is your favourite decimal number?'</span>)
<span class="hljs-string">"""
All of the above functions return the input given or return None if cancel is clicked or if the simpledialog is closed.
"""</span>

main_window.mainloop()
</code></pre>
<p><strong>Thank you!</strong></p>
<p><strong><a target="_blank" href="https://jothin.tech/">About me</a></strong></p>
]]></content:encoded></item><item><title><![CDATA[🛡️2FA with Python.]]></title><description><![CDATA[What is 2FA and why 2FA?🤔
2FA stands for two factor authentication. It adds an extra layer of security other than password. The user must enter a 2FA code along with password in order to sign in. 2FA codes can be generated in two ways, time based co...]]></description><link>https://blog.jothin.tech/2fa-with-python</link><guid isPermaLink="true">https://blog.jothin.tech/2fa-with-python</guid><category><![CDATA[Python]]></category><category><![CDATA[Security]]></category><category><![CDATA[2Articles1Week]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[tutorials]]></category><dc:creator><![CDATA[Jothin kumar]]></dc:creator><pubDate>Wed, 22 Dec 2021 06:22:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1640154006276/ifZ0T9KAB.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-what-is-2fa-and-why-2fa">What is 2FA and why 2FA?🤔</h2>
<p>2FA stands for two factor authentication. It adds an extra layer of security other than password. The user must enter a 2FA code along with password in order to sign in. 2FA codes can be generated in two ways, time based codes and counter based codes.</p>
<h3 id="heading-advantages-of-2fa-over-e-mail-or-sms-verification">Advantages of 2FA over E-Mail or SMS verification:</h3>
<ul>
<li><strong>No network required</strong>: <em>2FA codes can be generated offline</em>.</li>
<li>🛡️ <strong>Better security</strong>.</li>
</ul>
<h3 id="heading-time-based-codes-vs-counter-based-code">Time based codes vs counter based code.</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Time based codes</td><td>Counter based codes</td></tr>
</thead>
<tbody>
<tr>
<td>Time based codes changes depending on time. 🕖</td><td>Counter based codes change depending on number of successful sign-in(s). ✔️</td></tr>
<tr>
<td>No need of adding counter every time in client side.</td><td>After every successful login, counter must be increased by one in server side as well as client side.</td></tr>
</tbody>
</table>
</div><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1640153891760/aAJYjh944.png" alt="2FA flowchart" /></p>
<h2 id="heading-2fa-with-python">2FA with Python</h2>
<h3 id="heading-requirements">Requirements</h3>
<ul>
<li><strong><a target="_blank" href="https://pypi.org/project/onetimepass/">onetimepass python package</a></strong> <em>(Can be installed using the command: <code>pip install onetimepass</code>)</em>.</li>
<li><strong>Your favourite authenticator app</strong> <em>(Example: Google authenticator, Microsoft authenticator)</em>.</li>
</ul>
<h3 id="heading-lets-start">Let's start!👀</h3>
<p>For both time based codes and counter based code, a secret string is securely shared with the authenticator app while setting up 2FA. All codes are generated based on this secret string. This string is not case sensitive.</p>
<h4 id="heading-time-based-codes">🕖Time based codes</h4>
<p>Let us now, write a simple Python script to understand how time based 2FA works!</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> onetimepass <span class="hljs-keyword">import</span> valid_totp
<span class="hljs-keyword">from</span> secrets <span class="hljs-keyword">import</span> choice


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">generate_secret</span>():</span>  <span class="hljs-comment"># Function to return a random string with length 16.</span>
    secret = <span class="hljs-string">''</span>
    <span class="hljs-keyword">while</span> len(secret) &lt; <span class="hljs-number">16</span>:
        secret += choice(<span class="hljs-string">'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'</span>)
    <span class="hljs-keyword">return</span> secret


secret = generate_secret()
print(<span class="hljs-string">'Enter the following secret in your authenticator app: '</span>, secret)
print(<span class="hljs-string">"""
Instructions for saving this secret it Google Authenticator:
1. Open Google Authenticator.
2. Click plus icon at the right bottom.
3. Click Enter a setup key.
4. Enter an Account name of your choice and enter the secret provided above.
5. Click Add.
"""</span>)
<span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
    otp = int(input(<span class="hljs-string">'Please enter the otp generated by your authenticator app: '</span>))
    authenticated = valid_totp(otp, secret)
    <span class="hljs-keyword">if</span> authenticated:
        print(<span class="hljs-string">'Correct otp, Authenticated!'</span>)
    <span class="hljs-keyword">elif</span> <span class="hljs-keyword">not</span> authenticated:
        print(<span class="hljs-string">'Wrong otp, please try again.'</span>)
</code></pre>
<h4 id="heading-counter-based-codes">✔️ Counter based codes</h4>
<p>Here is a complete Python script to understand how counter based 2FA works!</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> onetimepass <span class="hljs-keyword">import</span> valid_hotp
<span class="hljs-keyword">from</span> secrets <span class="hljs-keyword">import</span> choice


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">generate_secret</span>():</span>  <span class="hljs-comment"># Function to return a random string with length 16.</span>
    secret = <span class="hljs-string">''</span>
    <span class="hljs-keyword">while</span> len(secret) &lt; <span class="hljs-number">16</span>:
        secret += choice(<span class="hljs-string">'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'</span>)
    <span class="hljs-keyword">return</span> secret


secret = generate_secret()
print(<span class="hljs-string">'Enter the following secret in your authenticator app: '</span>, secret)
print(<span class="hljs-string">"""
Instructions for saving this secret it Google Authenticator:
1. Open Google Authenticator.
2. Click plus icon at the right bottom.
3. Click Enter a setup key.
4. Enter an Account name of your choice and enter the secret provided above.
5. Click Add.
"""</span>)
<span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
    counter = <span class="hljs-number">0</span>
    otp = int(input(<span class="hljs-string">'Please enter the otp generated by your authenticator app: '</span>))
    authenticated = valid_hotp(otp, secret)
    <span class="hljs-keyword">if</span> authenticated:
        print(<span class="hljs-string">'Correct otp, Authenticated!'</span>)
        counter += <span class="hljs-number">1</span>
    <span class="hljs-keyword">elif</span> <span class="hljs-keyword">not</span> authenticated:
        print(<span class="hljs-string">'Wrong otp, please try again.'</span>)
</code></pre>
<p><strong>Thank you</strong>! Leave a comment and a like if you find this article useful :-)</p>
<p><strong><a target="_blank" href="https://jothin.tech/">About me</a></strong></p>
<p><a target="_blank" href="https://jothin.tech/"><img src="https://jothin.tech/assets/img/my%20logo.png" alt="Jothin kumar" /></a></p>
]]></content:encoded></item><item><title><![CDATA[How to create installers for your Python application?🤔]]></title><description><![CDATA[Requirements

Debian operating system.
Windows operating system with Python 3, pip and inno setup installed.

Creating inno setup installer (on windows)
In order to create an installer, we must convert the application script to executable. We can do ...]]></description><link>https://blog.jothin.tech/how-to-create-installers-for-your-python-application</link><guid isPermaLink="true">https://blog.jothin.tech/how-to-create-installers-for-your-python-application</guid><category><![CDATA[Ubuntu]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Windows]]></category><category><![CDATA[Python]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Jothin kumar]]></dc:creator><pubDate>Mon, 20 Dec 2021 08:05:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1639985053377/2FrtGu0We.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-requirements">Requirements</h2>
<ol>
<li>Debian operating system.</li>
<li>Windows operating system with Python 3, pip and inno setup installed.</li>
</ol>
<h2 id="heading-creating-inno-setup-installer-on-windows">Creating inno setup installer (on windows)</h2>
<p>In order to create an installer, we must convert the application script to executable. We can do this using pyinstaller.<br />Step 1: create a directory <code>my_app</code>.<br />Step 2: Create a new file <code>my_app/app.py</code> and copy the following contents to it:</p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-title">tkinter</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title">tk</span>

<span class="hljs-title">root</span> <span class="hljs-operator">=</span> <span class="hljs-title">tk</span>.<span class="hljs-title">Tk</span>()
<span class="hljs-title">tk</span>.<span class="hljs-title">Label</span>(<span class="hljs-title">master</span><span class="hljs-operator">=</span><span class="hljs-title">root</span>, <span class="hljs-title">text</span><span class="hljs-operator">=</span><span class="hljs-string">"Hello world"</span>, <span class="hljs-title">font</span><span class="hljs-operator">=</span>(<span class="hljs-string">"Arial"</span>, 30)).<span class="hljs-title">pack</span>()
<span class="hljs-title">root</span>.<span class="hljs-title">mainloop</span>()
</code></pre><p>Step 3: Navigate to <code>my_app</code> directory and run the following command in CMD:  </p>
<pre><code>pip install pyinstaller
pyinstaller <span class="hljs-operator">-</span><span class="hljs-operator">-</span>onefile app.py <span class="hljs-operator">-</span>w
</code></pre><p>Step 4: Wait for the command to complete and open inno setup compiler.<br />Step 5: On the inno setup welcome screen, click "Create a new script file using the Script Wizard" and hit ok.<br />Step 6: Follow on screen instructions (main executable file is in <code>my_app/dist/app.exe</code>).<br />Step 7: Compile the script and done!</p>
<h2 id="heading-creating-deb-package-on-debian-os">Creating deb package (On Debian OS)</h2>
<p>Just like windows, we must create an executable from our script for deb package.<br />Step 1: Create a directory <code>my_app</code><br />Step 2: Create a new file <code>my_app/app.py</code> and copy the following contents to it:</p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-title">tkinter</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title">tk</span>

<span class="hljs-title">root</span> <span class="hljs-operator">=</span> <span class="hljs-title">tk</span>.<span class="hljs-title">Tk</span>()
<span class="hljs-title">tk</span>.<span class="hljs-title">Label</span>(<span class="hljs-title">master</span><span class="hljs-operator">=</span><span class="hljs-title">root</span>, <span class="hljs-title">text</span><span class="hljs-operator">=</span><span class="hljs-string">"Hello world"</span>, <span class="hljs-title">font</span><span class="hljs-operator">=</span>(<span class="hljs-string">"Arial"</span>, 30)).<span class="hljs-title">pack</span>()
<span class="hljs-title">root</span>.<span class="hljs-title">mainloop</span>()
</code></pre><p>Step 3: Navigate to <code>my_app</code> directory and run the following command in terminal:</p>
<pre><code>pip install pyinstaller
pyinstaller app.py <span class="hljs-operator">-</span>w
</code></pre><p>Step 4: wait for it to complete and create the following directories.  </p>
<pre><code><span class="hljs-attribute">my</span>-app_<span class="hljs-number">1</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span>/DEBIAN
<span class="hljs-attribute">my</span>-app_<span class="hljs-number">1</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span>/my_app
<span class="hljs-attribute">my</span>-app_<span class="hljs-number">1</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span>/usr/share/applications
</code></pre><p>Step 5: Create a file <code>my-app_1.0.0/DEBIAN/control</code> and copy the following contents into it.  </p>
<pre><code><span class="hljs-attr">Package:</span> <span class="hljs-string">my-app</span>
<span class="hljs-attr">Version:</span> <span class="hljs-number">1.0</span><span class="hljs-number">.0</span>
<span class="hljs-attr">Architecture:</span> <span class="hljs-string">all</span>
<span class="hljs-attr">Maintainer:</span> [<span class="hljs-string">Your</span> <span class="hljs-string">name</span>]
<span class="hljs-attr">Copyright:</span> [<span class="hljs-string">year</span>] [<span class="hljs-string">Your</span> <span class="hljs-string">name</span>]
<span class="hljs-attr">License:</span> <span class="hljs-string">MIT</span>
<span class="hljs-attr">Homepage:</span> [<span class="hljs-string">homepage</span> <span class="hljs-string">url</span>]
<span class="hljs-attr">Description:</span> <span class="hljs-string">My</span> <span class="hljs-string">deb</span> <span class="hljs-string">package.</span>
</code></pre><p>Step 6: Create a file <code>my-app_1.0.0/usr/share/applications/my-app.desktop</code> and copy the following contents into it.  </p>
<pre><code><span class="hljs-section">[Desktop Entry]</span>
<span class="hljs-attr">Type</span>=Application
<span class="hljs-attr">Exec</span>=/my_app/app
<span class="hljs-attr">Hidden</span>=<span class="hljs-literal">false</span>
<span class="hljs-attr">NoDisplay</span>=<span class="hljs-literal">false</span>
<span class="hljs-attr">Name</span>=My app
<span class="hljs-attr">Comment</span>=My app.
</code></pre><p>Step 7: Copy all files and folders from <code>my_app/dist</code> to <code>my-app_1.0.0/my_app</code><br />Step 8: navigate to the parent directory of <code>my-app_1.0.0</code> and execute the following command:  </p>
<pre><code>dpkg<span class="hljs-operator">-</span>deb <span class="hljs-operator">-</span><span class="hljs-operator">-</span>build my<span class="hljs-operator">-</span>app_1<span class="hljs-number">.0</span><span class="hljs-number">.0</span>
</code></pre><p>Step 9: Wait for it to complete and done! You will find a deb package named <code>my-app_1.0.0.deb</code></p>
<h3 id="heading-about-me">About me:</h3>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://jothin.tech/">https://jothin.tech/</a></div>
<p><strong>Thank you!</strong></p>
]]></content:encoded></item></channel></rss>