<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rajnish Raj</title>
    <description>The latest articles on DEV Community by Rajnish Raj (@rajnish_raj_7cd820516cd0d).</description>
    <link>https://dev.to/rajnish_raj_7cd820516cd0d</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1690202%2Fe7bd2605-9566-4869-9da0-07c41236d286.png</url>
      <title>DEV Community: Rajnish Raj</title>
      <link>https://dev.to/rajnish_raj_7cd820516cd0d</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rajnish_raj_7cd820516cd0d"/>
    <language>en</language>
    <item>
      <title>Slot Game Math: Probability, Payouts, and RTP Explained</title>
      <dc:creator>Rajnish Raj</dc:creator>
      <pubDate>Fri, 19 Jun 2026 18:17:57 +0000</pubDate>
      <link>https://dev.to/rajnish_raj_7cd820516cd0d/slot-game-math-probability-payouts-and-rtp-explained-36h2</link>
      <guid>https://dev.to/rajnish_raj_7cd820516cd0d/slot-game-math-probability-payouts-and-rtp-explained-36h2</guid>
      <description>&lt;p&gt;Hello Everyone!&lt;/p&gt;

&lt;p&gt;For the past few weeks, I was working on a slot game, from the mathematical model to the backend to the frontend, everything.&lt;/p&gt;

&lt;p&gt;So, in this blog, I am going to teach you how to develop a mathematical model of a very simple slot game, and finally we gonna calculate the theoretical RTP(Return to Player).&lt;/p&gt;

&lt;p&gt;So, Let's begin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define Game rules
&lt;/h2&gt;

&lt;p&gt;Before going into math, we need to define the game's pay rules, so Let's define it first.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There will be 3 reels; each reel has 3 rows.&lt;/li&gt;
&lt;li&gt;There will be a total of 9 symbols, including the wild.&lt;/li&gt;
&lt;li&gt;Wild symbols can be replaced by the 8 other symbols.&lt;/li&gt;
&lt;li&gt;There will be 5 payout lines: two diagonals and all the rows.&lt;/li&gt;
&lt;li&gt;The player bets X amount; then the bet per line will be X.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3cvo8qs3k9c44psjp04o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3cvo8qs3k9c44psjp04o.png" alt="Slot Game" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is RTP?
&lt;/h2&gt;

&lt;p&gt;RTP (Return to Player) is the average percentage of money a game gives back to players over a very large number of plays.&lt;/p&gt;

&lt;p&gt;General formula for RTP : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1udyb2jxe0y3to1hpaaf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1udyb2jxe0y3to1hpaaf.png" alt="RTP Formula" width="421" height="86"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw2e8pyadhycl3rjzbafd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw2e8pyadhycl3rjzbafd.png" alt="Variable description" width="428" height="26"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mathematical model
&lt;/h2&gt;

&lt;p&gt;We know that there are 3 reels and 3 rows, so we can think of it like a 3x3 board, where the probability of symbols occupying a cell is given.&lt;/p&gt;

&lt;p&gt;There are a total of 5 payout lines; let's analyze a single payout line.&lt;/p&gt;

&lt;p&gt;There will be 2 cases :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Matching symbols without wild&lt;/li&gt;
&lt;li&gt;Matching symbols with the wild.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And in the 2nd case, there will be two more cases :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Matching symbols with one wild&lt;/li&gt;
&lt;li&gt;Matching symbols with two wild&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If all the 3 symbols are wild,  we gonna treat it as a normal symbol.&lt;/p&gt;

&lt;p&gt;Let's go into math now.&lt;/p&gt;

&lt;p&gt;We need to provide the probability and payout of symbols, but we can change it to reach our desired RTP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbm30i40ua9h6k3yvh6mc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbm30i40ua9h6k3yvh6mc.png" alt="Variable" width="336" height="23"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feo8xj2bcal4bmxxknxcm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feo8xj2bcal4bmxxknxcm.png" alt="Variable" width="445" height="23"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 1 (Matching symbol in a single payout line without wild.)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0q8xe8mssl4m178km48p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0q8xe8mssl4m178km48p.png" alt=" " width="468" height="19"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 2 (Matching symbol in a single payout line with wild.)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq1c3426tzrxw5rdgrphl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq1c3426tzrxw5rdgrphl.png" alt="Matching symbol in a single payout line with wild." width="798" height="47"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RTP contribution of a single payout line is&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4dh7ipulrnx2qzdn98m1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4dh7ipulrnx2qzdn98m1.png" alt=" " width="800" height="49"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, now we have to multiply this contribution by 5 to get the theoretical RTP of the game.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fesdhkbkdn3jks0o3wo25.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fesdhkbkdn3jks0o3wo25.png" alt=" " width="209" height="19"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Calculating Theoretical RTP
&lt;/h2&gt;



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

const SYMBOLS = {
  "SEVEN": 5 ,
  "BELL": 8 , 
  "GRAPE": 8 , 
  "WATERMELON": 9  ,
  "ORANGE"    : 8 ,
  "BLUEBERRY" : 8 ,
  "LEMON": 7 ,
  "RASPBERRY" : 6,  
  "WILD"      : 5  
}

const REEL_SIZE = 64;
const PAYOUT_LINES = 5;

const PAYOUTS = {
    "WILD" : 10,
    "SEVEN" : 15,
    "BELL" : 8,
    "GRAPE" : 6,
    "WATERMELON" : 1,
    "ORANGE" : 0.5,
    "BLUEBERRY" : 0.5,
    "LEMON" : 0.5,
    "RASPBERRY" : 0.5,
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function clacuateRTP() {
  let rtp = 0;

  Object.keys(SYMBOLS).forEach((symbol) =&amp;gt; {
    const symbol_prob = SYMBOLS[symbol] / REEL_SIZE;
    const wildProb = SYMBOLS["WILD"] / REEL_SIZE;

    if(symbol == "WILD") {
      const prob_wild = Math.pow(symbol_prob, 3);
      const payout_wild = PAYOUTS[symbol];

      const contribution = prob_wild * payout_wild;

      rtp += contribution * PAYOUT_LINES;

      return
    };

    const prob_without_wild = Math.pow(symbol_prob, 3)
    const prob_with_wild = 3 * wildProb * Math.pow(symbol_prob, 2) +  3 * Math.pow(wildProb, 2) * symbol_prob

    const payout_without_wild = prob_without_wild * PAYOUTS[symbol]
    const payout_with_wild =  prob_with_wild * PAYOUTS[symbol]

    const contribution = (payout_with_wild + payout_without_wild) 

    rtp += contribution * PAYOUT_LINES
  })

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"================================================================="
"symbol    ", "symbol prob    ", "contribution    "
"================================================================="
"SEVEN     ", "7.813          ", "0.0500679016    "
"BELL      ", "12.500         ", "0.0632324219    "
"GRAPE     ", "12.500         ", "0.0474243164    "
"WATERMELON", "14.063         ", "0.0099906921    "
"ORANGE    ", "12.500         ", "0.0039520264    "
"BLUEBERRY ", "12.500         ", "0.0039520264    "
"LEMON     ", "10.938         ", "0.0030574799    "
"RASPBERRY ", "9.375          ", "0.0023002625    "
"================================================================="
"TOTAL RTP = ", "94.37274932861328%"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;So, that's it for the mathematical model of a simple slot game!&lt;/p&gt;

&lt;p&gt;We defined the game rules, broke down the probability calculations for both cases, with and without wilds across all 5 payout lines, and finally calculated a theoretical RTP of ~94.37%.&lt;/p&gt;

&lt;p&gt;The best part? &lt;br&gt;
You can tweak the symbol counts and payouts to hit any RTP you want. That's the power of having a proper mathematical model before writing a single line of game code.&lt;/p&gt;

&lt;p&gt;Thank you :)&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How Casinos Control Randomness: Building Plinko with React and HTML Canvas</title>
      <dc:creator>Rajnish Raj</dc:creator>
      <pubDate>Thu, 18 Jun 2026 14:53:39 +0000</pubDate>
      <link>https://dev.to/rajnish_raj_7cd820516cd0d/how-casinos-control-randomness-building-plinko-with-react-and-html-canvas-1o8m</link>
      <guid>https://dev.to/rajnish_raj_7cd820516cd0d/how-casinos-control-randomness-building-plinko-with-react-and-html-canvas-1o8m</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;During an internship in an igaming service-based company, I developed the frontend for a lot of crash games and Arcade Casino games. One of the first games I built was Plinko.&lt;br&gt;
I learnt a lot of things during the development period of that game, which I am going to share with you in this post.&lt;/p&gt;

&lt;p&gt;So, Let's begin.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Our goal&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Our goal is to build Plinko, an Arcade Casino Game using HTML Canvas and React.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;What is Plinko?&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Plinko is a game of chance in which a ball or puck is dropped from the top of a vertical board filled with pegs. As the ball falls, it randomly bounces left or right at each peg until it lands in one of several slots at the bottom, each associated with a different prize or payout.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpg19vrt6j5f93cxezhah.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpg19vrt6j5f93cxezhah.png" alt="Plinko" width="800" height="358"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Plinko working mechanism&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The player drops a ball from the top, and it collides with obstacles positioned as a Pascal triangle; then it reaches the bottom level, where it collides with one of the multiplier blocks with multiplier X.&lt;/p&gt;

&lt;p&gt;The player won &lt;strong&gt;betAmount * X&lt;/strong&gt; money.&lt;/p&gt;

&lt;p&gt;We cannot randomly drop a ball from any X position from top because casinos need a fixed RTP (Return to Player). To achieve that fixed RTP, we need to control the ball so it collides with a predetermined multiplier block.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to control the ball?&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;The answer is simple. We map the initial x position, or you can say the dropping x position of the ball, to the multiplier blocks by running a lot of simulation.&lt;br&gt;
In the simulation, we drop a ball from random x position from the top, track it to see which multiplier block it is going to collide with, and we repeat it for 5-10 thousand times until we map every multiplier block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;canvasWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;canvasHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;records&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;initialX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;362.0786996500253&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;initialY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;multiplier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;},],&lt;/span&gt;
      &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;initialX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;357.44116222657084&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;initialY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;multiplier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;130&lt;/span&gt;&lt;span class="p"&gt;},],&lt;/span&gt;
      &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;initialX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;351.58243647873775&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;initialY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;multiplier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;},],&lt;/span&gt;


      &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Plinko Physic&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We are going to use the following physics concept : &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Collision&lt;/li&gt;
&lt;li&gt;Gravity&lt;/li&gt;
&lt;li&gt;Friction&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Collision&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the ball collides with an obstacle, it will bounce off. There are two steps in this collision detection and bounce-back physics.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgmbx79cum3eu3l2qjec5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgmbx79cum3eu3l2qjec5.jpg" alt="Collision between two balls" width="518" height="339"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Collision detection physic&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ball&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;obstacle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ball&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;obstacle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hypot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;ball&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;obstacle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Collision&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bounce back physic&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;atan2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ball&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;ball&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ball&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vy&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;ball&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nx"&gt;ball&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;horizontalFriction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nx"&gt;ball&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;verticalFriction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Gravity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We add gravity only for the ball not for obstacles, obstacles should be fixed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gravity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;ball&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ball&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vy&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;gravity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Friction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As you already noticed, we used horizontal and vertical friction in bounce-back physics. Friction is  crucial physics for this game because if we do not add friction, the ball will never loses it energy and it will eventually bounce off the canvas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;horizontalFriction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;verticalFriction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Development&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I divided the whole game into two parts: Game Panel and Betting Panel&lt;br&gt;
Game Panel has the HTML Canvas element, and the Betting Panel controls the bet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;gameContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GamePanel&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
       &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BettingPanel&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;gameContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Context API is used to share state between components, and a custom-made EventEmitter is used to trigger events and share data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="nx"&gt;eventEmitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ballDropEnd&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
   &lt;span class="nx"&gt;eventEmitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ballDropStart&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
   &lt;span class="nx"&gt;eventEmitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ballObstacleCollision&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;obstacle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;obstacle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;more&lt;/span&gt; &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Building Plinko taught me that arcade casino games are far more engineered than they appear. What looks like a simple ball-dropping game involves a careful balance of physics simulation, RTP control, and canvas rendering working together seamlessly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://plinko-sooty-one.vercel.app/" rel="noopener noreferrer"&gt;live link for demo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Dask : Search through 2943 DSA problem using natural language</title>
      <dc:creator>Rajnish Raj</dc:creator>
      <pubDate>Sat, 26 Jul 2025 05:19:41 +0000</pubDate>
      <link>https://dev.to/rajnish_raj_7cd820516cd0d/dask-search-through-2943-dsa-problem-using-natural-language-59gi</link>
      <guid>https://dev.to/rajnish_raj_7cd820516cd0d/dask-search-through-2943-dsa-problem-using-natural-language-59gi</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/algolia-2025-07-09"&gt;Algolia MCP Server Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built an AI-powered search engine that search through a database of about 3,000 DSA problems using natural language queries. Used Gemini API for AI responses and Algolia JavaScript API for fast, relevant search results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Search with a natural language query, not keywords&lt;/li&gt;
&lt;li&gt;automatic filter selection from query.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Live - &lt;a href="https://dask-omega.vercel.app/" rel="noopener noreferrer"&gt;https://dask-omega.vercel.app/&lt;/a&gt;&lt;br&gt;
Github - &lt;a href="https://github.com/Rajnish8292/dask" rel="noopener noreferrer"&gt;https://github.com/Rajnish8292/dask&lt;/a&gt;&lt;br&gt;
&lt;iframe src="https://player.vimeo.com/video/1104666226" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Utilized the Algolia MCP Server
&lt;/h2&gt;

&lt;p&gt;Algolia helps to filter search results based on facets and facetFilter and provide fast result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;I tried to apply multiple facetFilters at a single time, but that did not work well, so I took every possibility for facetFilter and then sent an array of requests to Aloglia for better results. &lt;br&gt;
E.g&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// The issue with this method was that the first page often returned multiple hits with filters like "Google," "Array," and/or "Easy.
facetFilters = [['google', 'zomato'], ['array', 'graph'], ['easy', hard]]

// To overcome this problem, I break a single request into multiple requests
facetFilterArray = [
   [['google'], ['array'], ['easy']],
   [['google'], ['graph'], ['easy']],
   [['google'], ['array'], ['hard']],
   [['google'], ['graph'], ['hard']],
   [['Zomato'], ['array'], ['easy']],
   [['Zomato'], ['graph'], ['easy']],
   [['Zomato'], ['array'], ['hard']],
   [['Zomato'], ['graph'], ['hard']],
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>devchallenge</category>
      <category>algoliachallenge</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
