You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

30 lines
12 KiB

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Minesweeper Bomb Generation And Tile Revealing | tait.tech</title> <link rel="stylesheet" href="/assets/css/style.css"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="author" content="Tait Hoyem"> <meta name="keywords" content=""> <meta name="description" content=""><link rel="stylesheet" href="/assets/css/katex.css"> </head> <body> <div id="wrapper"> <header> <nav> <input type="checkbox" id="menu"> <label for="menu">&#9776;</label> <div class="menu-content"> <a href="/" class="nav-link">Home</a> <a href="/blog/" class="nav-link">Blog</a> <a href="https://github.com/TTWNO/" class="nav-link" target="_blank" rel="noopener noreferrer">Github</a> </div> </nav> </header> <main> <article> <header> <h1 class="post-title">Minesweeper Bomb Generation And Tile Revealing</h1> <time datetime="20-09-12" class="post-date">Saturday, September 12 2020</time> </header> <hr> <p>When I was creating a little Minesweeper game, I got confused at some points. My bomb generation didnt look quite right, and I for sure didnt quite get the whole cascading tile reveal thing. With a bit of internet research, I found what I was looking for. Ill explain it all in one place for my own research purposes.</p> <h2 id="bomb-generation">Bomb Generation</h2> <p>When I started this project I attempted to use a random bomb generator. By this I mean on each square, before it gets generated, give it a one in 15 change of being a bomb. Personally, Im not sure why this never looked right. Something about the layout of the bombs did not mimic the classic Minesweeper game.</p> <p>After looking at some open source Minesweeper examples, I started to get the idea. I wrote some mathematical statements describing the generation of bombs and how to get their x,y position from an appropriate number. For those non-mathy people, dont leave just yet; there will be code equivalents to the math.</p> <p>W and H are the width and height of the board respectively.</p> <p><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn mathvariant="italic">0</mn><mo></mo><mi>r</mi><mo></mo><mtext>W</mtext><mo>×</mo><mtext>H</mtext></mrow><annotation encoding="application/x-tex"> \it 0 \leq r \leq \text W \times \text H </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8193em;vertical-align:-0.13597em;"></span><span class="mord"><span class="mord mathit">0</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mord mathit">r</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mord text"><span class="mord">W</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord text"><span class="mord">H</span></span></span></span></span></span></span> <span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>=</mo><mi>r</mi><mtext></mtext><mo lspace="0.22em" rspace="0.22em"><mrow><mi mathvariant="normal">m</mi><mi mathvariant="normal">o</mi><mi mathvariant="normal">d</mi></mrow></mo><mtext></mtext><mtext>W</mtext></mrow><annotation encoding="application/x-tex"> \it x = r \bmod \text W </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord"><span class="mord mathit">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"
<span class="c1"># r &lt;= 0 &lt;= W*H
</span><span class="n">r</span> <span class="o">=</span> <span class="n">random</span><span class="p">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">W</span><span class="o">*</span><span class="n">H</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span>
<span class="c1"># x = r mod W
</span><span class="n">x</span> <span class="o">=</span> <span class="n">r</span> <span class="o">%</span> <span class="n">W</span>
<span class="c1"># y = floor(r/H); note the special syntax python has for this operation
</span><span class="n">y</span> <span class="o">=</span> <span class="n">r</span> <span class="o">//</span> <span class="n">H</span>
</code></pre></div></div> <p>So thats that, we can put this in a big ol for loop and generate an arbitrary <em>n</em> number of bombs given a width and height of a Minesweeper board.</p> <h2 id="cascading-tile-revealing">Cascading Tile Revealing</h2> <p>This one is hard to describe; I am adapting this from <a href="https://leetcode.com/problems/minesweeper/">leetcode.com</a>. Whenever a player clicks a tile, the following logic should be used:</p> <ol> <li>If a mine is revealed, the game is over. (obviously)</li> <li>If a tile with <em>no</em> adjacent mines is revealed, recursively reveal all eight adjacent tiles.</li> <li>If a tile with one or more adjacent mines is revealed, display the number of mines next to it.</li> </ol> <p>Here is the code in Python for this algorithm.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">reveal_square</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">board</span><span class="p">,</span> <span class="n">alread_revealed</span><span class="p">):</span>
<span class="c1"># if already checked
</span> <span class="k">if</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="ow">in</span> <span class="n">already_revealed</span><span class="p">:</span>
<span class="k">return</span>
<span class="c1"># if it's a bomb
</span> <span class="k">if</span> <span class="n">board</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="n">y</span><span class="p">]</span> <span class="o">==</span> <span class="s">'B'</span><span class="p">:</span>
<span class="n">you_lose</span><span class="p">()</span>
<span class="k">return</span>
<span class="c1"># if the bomb number is more than 0
</span> <span class="n">already_revealed</span><span class="p">.</span><span class="n">append</span><span class="p">((</span><span class="n">nx</span><span class="p">,</span> <span class="n">ny</span><span class="p">))</span>
<span class="c1"># from -1 to 1
</span> <span class="k">for</span> <span class="n">xd</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">):</span>
<span class="k">for</span> <span class="n">yd</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">):</span>
<span class="c1"># skip if it is this the center tile
</span> <span class="k">if</span> <span class="n">x</span><span class="o">+</span><span class="n">xd</span> <span class="o">==</span> <span class="n">x</span> <span class="ow">and</span> <span class="n">y</span><span class="o">+</span><span class="n">yd</span> <span class="o">==</span> <span class="n">y</span><span class="p">:</span>
<span class="k">continue</span>
<span class="c1"># recursively check the adjacent square
</span> <span class="n">reveal</span><span class="p">(</span><span class="n">x</span><span class="o">+</span><span class="n">xd</span><span class="p">,</span> <span class="n">y</span><span class="o">+</span><span class="n">yd</span><span class="p">,</span> <span class="n">board</span><span class="p">,</span> <span class="n">already_revealed</span><span class="p">)</span>
<span class="k">return</span> <span class="n">already_revealed</span>
</code></pre></div></div> <p>This has no checks for valid squares, but its the general idea. This function returns an array of tile coordinates which should be revealed.</p> <h2 id="conclusion">Conclusion</h2> <p>I wrote this because in the first place because I was writing my own Minesweeper game. I hope that this helps you with getting the general idea of a Minesweeper game. The completed version of this game is available on my <a href="https://lamegames.tait.tech/">lamegames</a> site. Let me know what you think!</p> <p>Happy hacking!</p> </article> </main> <hr> <footer> This page is mirrored on <a href="https://beta.tait.tech/2020/09/12/minesweeper.html">beta.tait.tech</a>. </footer> </div> </body> </html>