Sunday, 16 August 2026

Web Tutorial: Pill Puzzle (Part 1/4)

During some audio Social Media dialogue on the Clubhouse app, I overheard someone describe a puzzle. Something along the lines of - you've been poisoned and about to die. There are eight pills, and any one could be the cure. One is deadly poison. It's the lightest pill, but only by a fraction. You have a weighing scale you can use twice.

I thought about it, and I wanted to make this game. Except that I would switch things around a bit. One of the pills is the cure and the rest are poison. Now that would make things more deadly. And exciting!

We will be using jQuery for this, because I've come a long way the last ten years and sometimes I can't be arsed to deal with vanilla JavaScript. This is one of those times.

We start off with this HTML, ensuring that the jQuery library is included, and setting font size and background color to black. div tags will be outlined in red while we built the interface.
<!DOCTYPE html>
<html>
  <head>
    <title>Pill Puzzle</title>

    <style>
      body
      {
        font-size: 12px;
        font-family: verdana;
        text-align: center;
        background-color: rgb(0, 0, 0);
        color: rgb(200, 200, 200);
      }

      div {outline: 1px solid red;}
    </style>

    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>

    <script>

    </script>
  </head>

  <body>

  </body>
</html>


We'll divide the interface into three divs and style them accordingly.
<body>
    <div class="topContainer">

    </div>

    <div class="middleContainer">

    </div>

    <div class="bottomContainer">

    </div>

</body>


The top is 400 pixels wide, the middle 600, and the bottom 500. All of them use the margin property to center themselves.
<style>
body
{
    font-size: 12px;
    font-family: verdana;
    text-align: center;
    background-color: rgb(0, 0, 0);
    color: rgb(200, 200, 200);
}

div {outline: 0px solid red;}

.topContainer
{
    width: 400px;
    margin: 0 auto 0 auto;
}

.middleContainer
{
    width: 600px;
    margin: 0 auto 0 auto;
}      

.bottomContainer
{
    width: 500px;
    margin: 0 auto 0 auto;
}

</style>


Part of this exercise is my current flirtation with grid and flexbox, as you'll soon see. I want this div to contain three columns, the middle one widest.
<div class="topContainer">
    <div>

    </div>

    <div>

    </div>

    <div>

    </div>

</div>


And if we do this, we ensure the middle column is the biggest, with a 20 pixel space between all three.
.topContainer
{
    display: grid;
    grid-template-columns: 1fr 2fr 1fr;
    gap: 20px;

    width: 400px;
    margin: 0 auto 0 auto;
}


In the first div, we go to its center div and add three more divs inside. In the first one, we have the scale symbol. The second one is used to display how many times the scale has been used. And the last one contains a button used for weighing.
<div class="topContainer">
  <div>
  
  </div>

  <div>
    <div>&#x2696;</div>
    <div>Times Used: </div>
    <div><button>WEIGH</button></div>

  </div>

  <div>
  
  </div>
</div>


This is just the start.

Now for the sides. Each of these will contain another div, and in turn will contain 9 more divs! These are placeholders for the pills. There are going to be 8 pills, so theoretically, there's a maximum of 8 placeholders on each side. The ninth one is the scale bowl at the bottom!
<div class="topContainer">
  <div>
    <div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </div>

  </div>

  <div>
    <div>&#x2696;</div>
    <div>Times Used: </div>
    <div><button>WEIGH</button></div>
  </div>

  <div>
    <div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </div>

  </div>
</div>


To really hammer home the visuals, we're going to do some styling here. The left and right divs will be styled using pnlWeighPillsContainer. The first immediate div within will be styled using pnlWeighPills. The middle div is styled using scaleContainer, and that first div within is styled using pnlScale.
<div class="topContainer">
  <div class="pnlWeighPillsContainer">
    <div class="pnlWeighPills">
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </div>
  </div>

  <div class="scaleContainer">
    <div class="pnlScale">&#x2696;</div>
    <div>Times Used: </div>
    <div><button>WEIGH</button></div>
  </div>

  <div class="pnlWeighPillsContainer">
    <div class="pnlWeighPills">
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </div>
  </div>
</div>


Now for the CSS. scaleContainer is a grid container that divides its content into three rows, with the top row getting the most space. pnlScale neccessitates that because we've set the font size to a large one. pnlWeighPillsContainer is a flexbox container where the alignment is vertical and by default, content is set to the middle. However, its immediate child, pnlWeightPills, is a grid with nine rows, each having equal billing.
body
{
  font-size: 12px;
  font-family: verdana;
  text-align: center;
  background-color: rgb(0, 0, 0);
  color: rgb(200, 200, 200);
}

div {outline: 1px solid red;}

.topContainer
{
  display: grid;
  grid-template-columns: 1fr 2fr 1fr;
  gap: 20px;
  width: 400px;
  margin: 0 auto 0 auto;
}

.middleContainer
{
  width: 600px;
  margin: 0 auto 0 auto;
}      

.bottomContainer
{
  width: 500px;
  margin: 0 auto 0 auto;
}  

.scaleContainer
{
  display: grid;
  grid-template-rows: 8fr 1fr 1fr;
  gap: 0px;
}

.pnlScale
{
  font-size: 12em;
}

.pnlWeighPillsContainer
{
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.pnlWeighPills
{
  display: grid;
  grid-template-rows: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
  gap: 1px;
}


Here you see the scale! The left and right divs have a mess of divs bunched right in the middle. We'll work on that next.

In the last div of the divs inside each div styled using pnlWeighPills, insert a div with the CSS class bowl.
<div class="topContainer">
  <div class="pnlWeighPillsContainer">
    <div class="pnlWeighPills">
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div><div class="bowl"></div></div>
    </div>
  </div>

  <div class="scaleContainer">
    <div class="pnlScale">&#x2696;</div>
    <div>Times Used: </div>
    <div><button>WEIGH</button></div>
  </div>

  <div class="pnlWeighPillsContainer">
    <div class="pnlWeighPills">
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div><div class="bowl"></div></div>
    </div>
  </div>
</div>


This is bowl. It's a light grey div that has rounded corners at the bottom, with a fixed width and height.
.pnlWeighPills
{
  display: grid;
  grid-template-rows: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
  gap: 1px;
}  

.bowl
{
  width: 60px;
  height: 20px;
  background-color: rgb(200, 200, 200);
  border-top: none;
  border-radius: 0 0 10px 10px;
  margin: 0 auto 0 auto;
}


And now that one of the divs in the grid contains content that has fixed height and width, the rest of the divs follow suit!

We can leave the top portion alone for now. Let's work on the middle portion. We first have one div with the id pillsContainer. It in turn contains 8 div tags, one for each pill.
<div class="middleContainer">
  <div id="pillsContainer">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
  </div>

</div>


After that, have two more divs on new lines - ids playerFace and playerMessage.
<div class="middleContainer">
  <div id="pillsContainer">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
  </div>
  <br />
  <div id="playerFace"></div>
  <br />
  <div id="playerMessage"></div>

</div>


pillsContainer is another grid display, with 8 columns all with equal weight. For playerFace and playerMessage, I specified font size. For playerFace, the cursor property has been set to pointer because this is clickable.
.pnlScale
{
  font-size: 12em;
}

#pillsContainer
{
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
  gap: 5px;
  height: 100px;
}

#playerFace
{
  font-size: 7em;
  cursor: pointer;
}

#playerMessage
{
  font-size: 3em;
}


.pnlWeighPillsContainer
{
  display: flex;
  flex-direction: column;
  justify-content: center;
}


Speaking of clickable, let's also get this out of the way. All the div tags inside pillsContainer should be styled using the pillsSlot CSS class.
<div id="pillsContainer">
  <div class="pillSlot"></div>
  <div class="pillSlot"></div>
  <div class="pillSlot"></div>
  <div class="pillSlot"></div>
  <div class="pillSlot"></div>
  <div class="pillSlot"></div>
  <div class="pillSlot"></div>
  <div class="pillSlot"></div>
</div>


Same for these inside the divs styled using the pnlWeighPills CSS class. Just the first eight, not the last one.
<div class="pnlWeighPills">
  <div class="pillSlot"></div>
  <div class="pillSlot"></div>
  <div class="pillSlot"></div>
  <div class="pillSlot"></div>
  <div class="pillSlot"></div>
  <div class="pillSlot"></div>
  <div class="pillSlot"></div>
  <div class="pillSlot"></div>
  <div><div class="bowl"></div></div>
</div>


In the CSS, just set pillSlot to be clickable.
#pillsContainer div.selected
{
  color: rgb(255, 0, 0);
}

.pillSlot
{
  cursor: pointer;
}


#playerFace
{
  font-size: 7em;
  cursor: pointer;
}


In any case, your middle portion should be taking shape now.


Now for the bottom part! This part is the easiest. You add some instructions, and then add a button that the user clicks when they're ready to play.
<div class="bottomContainer">
  <p>You are slowly dying. There are eight pills. One of them is the cure. The rest are lethal poison and will kill you instantly. They are all identical in size and shape, and color. However, the cure is slightly lighter than the rest. You may use the scale exactly two times before it breaks.</p>

  <p>Once you have decided which pill to take, select the pill and click on the face at the bottom. Good luck!</p>

  <button>START</button>

</div>


And here we go, that's basically the UI. There's more to it, of course, but we have the skeleton upon which the rest can be filled in.


Next

Populating with pills.

No comments:

Post a Comment