<?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" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Coding Papa]]></title><description><![CDATA[I am a software engineer based in Seattle, WA. This is my corner of the web where I write about my programming experience, reading and software tinkering.]]></description><link>https://www.codingpapa.net</link><image><url>https://substackcdn.com/image/fetch/$s_!q93X!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F83867b8e-ee49-49c4-b93f-8c7c7d8ebdfd_1280x1280.png</url><title>Coding Papa</title><link>https://www.codingpapa.net</link></image><generator>Substack</generator><lastBuildDate>Tue, 21 Apr 2026 10:59:59 GMT</lastBuildDate><atom:link href="https://www.codingpapa.net/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Rohit Agarwal]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[codingpapa@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[codingpapa@substack.com]]></itunes:email><itunes:name><![CDATA[Rohit]]></itunes:name></itunes:owner><itunes:author><![CDATA[Rohit]]></itunes:author><googleplay:owner><![CDATA[codingpapa@substack.com]]></googleplay:owner><googleplay:email><![CDATA[codingpapa@substack.com]]></googleplay:email><googleplay:author><![CDATA[Rohit]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Horse Race Game, Part 3]]></title><description><![CDATA[Finishing up the conversion of the old BASIC game to modern SwiftUI]]></description><link>https://www.codingpapa.net/p/horse-race-game-part-3</link><guid isPermaLink="false">https://www.codingpapa.net/p/horse-race-game-part-3</guid><dc:creator><![CDATA[Rohit]]></dc:creator><pubDate>Sun, 21 Sep 2025 22:49:41 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Tc0q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa4ca7d7-e042-4a82-98bf-b6eb01f2cd28_1024x608.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Tc0q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa4ca7d7-e042-4a82-98bf-b6eb01f2cd28_1024x608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Tc0q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa4ca7d7-e042-4a82-98bf-b6eb01f2cd28_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!Tc0q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa4ca7d7-e042-4a82-98bf-b6eb01f2cd28_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!Tc0q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa4ca7d7-e042-4a82-98bf-b6eb01f2cd28_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!Tc0q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa4ca7d7-e042-4a82-98bf-b6eb01f2cd28_1024x608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Tc0q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa4ca7d7-e042-4a82-98bf-b6eb01f2cd28_1024x608.png" width="1024" height="608" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fa4ca7d7-e042-4a82-98bf-b6eb01f2cd28_1024x608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:608,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Tc0q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa4ca7d7-e042-4a82-98bf-b6eb01f2cd28_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!Tc0q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa4ca7d7-e042-4a82-98bf-b6eb01f2cd28_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!Tc0q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa4ca7d7-e042-4a82-98bf-b6eb01f2cd28_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!Tc0q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa4ca7d7-e042-4a82-98bf-b6eb01f2cd28_1024x608.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Introduction</h2><p>In <a href="https://www.codingpapa.net/p/horse-race-game-part-2">Part 2</a>, we were half way done with our SwiftUI implementation of the Horse Race game. Let&#8217;s finish it up in this last part. This is how the UI looked on the old BASIC computer. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ksdA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17c2a6b5-cfd0-4f04-89c9-7c402fdaedd6_2080x928.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ksdA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17c2a6b5-cfd0-4f04-89c9-7c402fdaedd6_2080x928.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ksdA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17c2a6b5-cfd0-4f04-89c9-7c402fdaedd6_2080x928.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ksdA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17c2a6b5-cfd0-4f04-89c9-7c402fdaedd6_2080x928.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ksdA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17c2a6b5-cfd0-4f04-89c9-7c402fdaedd6_2080x928.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ksdA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17c2a6b5-cfd0-4f04-89c9-7c402fdaedd6_2080x928.jpeg" width="1456" height="650" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/17c2a6b5-cfd0-4f04-89c9-7c402fdaedd6_2080x928.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:650,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:444079,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/173584451?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17c2a6b5-cfd0-4f04-89c9-7c402fdaedd6_2080x928.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ksdA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17c2a6b5-cfd0-4f04-89c9-7c402fdaedd6_2080x928.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ksdA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17c2a6b5-cfd0-4f04-89c9-7c402fdaedd6_2080x928.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ksdA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17c2a6b5-cfd0-4f04-89c9-7c402fdaedd6_2080x928.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ksdA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17c2a6b5-cfd0-4f04-89c9-7c402fdaedd6_2080x928.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>1. Choosing Horse</h2><p>We ended the previous part where we were showing the odds on horses. Next we show the prompt to the player to choose one of these horses. </p><pre><code>extension FX790...
    private func promptChooseHorse(for player: Player) -&gt; Int {
        while true {
            <strong>let choice: Int = INPUT("P \(player.id)-&gt;")
            if (0...4).contains(choice) {
                return choice
            }</strong>
        }
    }</code></pre><p>The new state is &#8211;</p><pre><code><code>enum GameState...
    </code><strong>case chooseHorse(Player)</strong></code></pre><p>The displayText is &#8211;</p><pre><code>class HorseRaceViewModel...
   var displayText...
       case .chooseHorse(let p): 
          <strong>"P \(p.id)&#8594; \(horses.map(\.oddsLabel).joined(separator: " "))"</strong>
       }
   }</code></pre><p>And moving to this state is &#8211;</p><pre><code>class HorseRaceViewModel...
    private func moveToNextState...
        case .displayOdds(let player):
            <strong>state = .chooseHorse(player)</strong></code></pre><p>This shows &#8211; </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XA96!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bc635e5-e538-4800-8421-02386cfb6d66_890x152.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XA96!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bc635e5-e538-4800-8421-02386cfb6d66_890x152.png 424w, https://substackcdn.com/image/fetch/$s_!XA96!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bc635e5-e538-4800-8421-02386cfb6d66_890x152.png 848w, https://substackcdn.com/image/fetch/$s_!XA96!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bc635e5-e538-4800-8421-02386cfb6d66_890x152.png 1272w, https://substackcdn.com/image/fetch/$s_!XA96!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bc635e5-e538-4800-8421-02386cfb6d66_890x152.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XA96!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bc635e5-e538-4800-8421-02386cfb6d66_890x152.png" width="514" height="87.78426966292135" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6bc635e5-e538-4800-8421-02386cfb6d66_890x152.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:152,&quot;width&quot;:890,&quot;resizeWidth&quot;:514,&quot;bytes&quot;:15511,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/173584451?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bc635e5-e538-4800-8421-02386cfb6d66_890x152.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XA96!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bc635e5-e538-4800-8421-02386cfb6d66_890x152.png 424w, https://substackcdn.com/image/fetch/$s_!XA96!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bc635e5-e538-4800-8421-02386cfb6d66_890x152.png 848w, https://substackcdn.com/image/fetch/$s_!XA96!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bc635e5-e538-4800-8421-02386cfb6d66_890x152.png 1272w, https://substackcdn.com/image/fetch/$s_!XA96!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bc635e5-e538-4800-8421-02386cfb6d66_890x152.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>I did not make this an actual prompt with the blinking cursor, because we will just need the user to press a number from 0-5 and that will move to the next screen, without needing to press the RETURN key. </p><h2>2. Capturing User Input</h2><p>We need to capture the key press of 0-5 from the user. This is what we had from old game. </p><pre><code>let choice = promptChooseHorse(for: player)
if choice == 0 { continue }  <em>// 0 means pass</em>
player.choose(horse: horses[choice - 1])</code></pre><p>First we need to capture user input without the RETURN key press. For this we will modify the <strong>handleUserInput </strong>method. </p><pre><code>class HorseRaceViewModel...
    private func handleUserInput(_ char: Character) {
        switch state {
        case .promptNumPlayers:
            userInput.append(char)
        <strong>case .chooseHorse:
            userInput.append(char)
            moveToNextState()</strong>
        default: return
        }
    }</code></pre><p>In the previous <strong>promptNumPlayers</strong> state we were waiting for user to press the RETURN before processing their input. In <strong>chooseHorse</strong> state we do <strong>moveToNextState</strong> after one key press. </p><pre><code>class HorseRaceViewModel...
    private func moveToNextState...
        case .chooseHorse(let player):
            <strong>if chooseHorse(player)</strong> {
                state = ... // next state
            }
        }
    }

    private func <strong>chooseHorse</strong>(_ player: Player) -&gt; Bool {
       guard let choice = Int(readInput()) else { return false }
       guard choice &gt;= 0 &amp;&amp; choice &lt;= horses.count else { return false }
       if choice == 0 { return true }  <em>// 0 means pass</em>
       player.choose(horse: horses[choice - 1])
       return true
    }</code></pre><h2>3. Placing Bet</h2><p>After choosing a horse, the game immediately takes the user to place a bet. </p><pre><code>extension FX790...
    private func promptBetMoney(for player: Player) -&gt; Int {
        BEEP()
        PRINT()
        while true {
            let bet: Int = 
<strong>INPUT("PLAYER \(player.id) \(player.chosenHorse!.symbol) MONEY ")</strong>
            if bet &gt;= 0 &amp;&amp; bet &lt;= player.money {
                return bet
            }
        }
    }</code></pre><p>Let&#8217;s create the new prompt state. </p><pre><code>enum GameState...
    <strong>case promptBetMoney(Player)</strong>
    
    var isPrompt: Bool {
        switch self {
        case .promptNumPlayers: return true
        <strong>case .promptBetMoney: return true</strong>
        default : return false
        }
    }
}</code></pre><p>The <strong>displayText</strong> and moving to this state becomes &#8211;</p><pre><code>class HorseRaceViewModel...
    var displayText...
        case .promptBetMoney(let p): 
           <strong>"PLAYER \(p.id) \(p.chosenHorse!.symbol) MONEY? \(userInput)"</strong>
        }
    }

    private func moveToNextState...
        case .chooseHorse(let player):
            if chooseHorse(player) {
                <strong>state = .promptBetMoney(player)</strong>
            }</code></pre><p>This returns in below screen where it shows the chosen horse and user can input money. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ojnD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8898acf-6f05-4678-ba71-0f1420faded8_886x154.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ojnD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8898acf-6f05-4678-ba71-0f1420faded8_886x154.png 424w, https://substackcdn.com/image/fetch/$s_!ojnD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8898acf-6f05-4678-ba71-0f1420faded8_886x154.png 848w, https://substackcdn.com/image/fetch/$s_!ojnD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8898acf-6f05-4678-ba71-0f1420faded8_886x154.png 1272w, https://substackcdn.com/image/fetch/$s_!ojnD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8898acf-6f05-4678-ba71-0f1420faded8_886x154.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ojnD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8898acf-6f05-4678-ba71-0f1420faded8_886x154.png" width="472" height="82.04063205417607" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d8898acf-6f05-4678-ba71-0f1420faded8_886x154.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:154,&quot;width&quot;:886,&quot;resizeWidth&quot;:472,&quot;bytes&quot;:17949,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/173584451?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8898acf-6f05-4678-ba71-0f1420faded8_886x154.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ojnD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8898acf-6f05-4678-ba71-0f1420faded8_886x154.png 424w, https://substackcdn.com/image/fetch/$s_!ojnD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8898acf-6f05-4678-ba71-0f1420faded8_886x154.png 848w, https://substackcdn.com/image/fetch/$s_!ojnD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8898acf-6f05-4678-ba71-0f1420faded8_886x154.png 1272w, https://substackcdn.com/image/fetch/$s_!ojnD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8898acf-6f05-4678-ba71-0f1420faded8_886x154.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>To process the bet, we need to add a new <strong>betMoney</strong> method. </p><pre><code>class HorseRaceViewModel...
    private func <strong>betMoney</strong>(_ player: Player) -&gt; Bool {
        guard let betAmount = Int(readInput()) else { return false }
        return player.placeBet(betAmount)
    }

class Player...
    func <strong>placeBet</strong>(_ bet: Int) -&gt; Bool {
        guard bet &gt;= 0 &amp;&amp; bet &lt;= money else { return false }
        self.bet = bet
        self.money -= bet
        return true
    }</code></pre><p>Now we can handle the <strong>moveToNextState</strong>. </p><pre><code>class HorseRaceViewModel...
    private func moveToNextState...
        case .promptBetMoney(let player):
<strong>            if betMoney(player) {
                state = players.next(after: player)
                    .map { .displayPlayerHoldings($0) }
                    .orElse(...) </strong><em>// Go to race start</em><strong>
            }</strong>
        }</code></pre><p>Notice that after a player has placed a bed, we need to move to the next player, and take them back to the displayPlayerHoldings. If no players remain, then we go to race start. </p><h2>4.  Display Race Start</h2><p>All the bets have been placed. Lets start the race. </p><pre><code>extension FX790...
    private func displayRaceStart() {
        PRINT()
        <strong>PRINT(" &lt; START! &gt;")</strong>
        for _ in 1...10 {
            BEEP()
        }
        PRINT()
    }</code></pre><p>This is a simple display only screen. </p><pre><code>enum GameState...
    <strong>case displayRaceStart</strong>

class HorseRaceViewModel...
    var displayText...
        <strong>case .displayRaceStart: " &lt; START! &gt;"
</strong>
    private func moveToNextState...
        case .promptBetMoney(let player):
            if betMoney(player) {
                state = players.next(after: player)
                    .map { .displayPlayerHoldings($0) }
                    .orElse(<strong>.displayRaceStart</strong>) 
            }
        }</code></pre><p>Just 3 lines of code change, and the display is done. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ldQv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5eee4274-2b32-4e6b-9f40-f76d917612f8_882x146.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ldQv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5eee4274-2b32-4e6b-9f40-f76d917612f8_882x146.png 424w, https://substackcdn.com/image/fetch/$s_!ldQv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5eee4274-2b32-4e6b-9f40-f76d917612f8_882x146.png 848w, https://substackcdn.com/image/fetch/$s_!ldQv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5eee4274-2b32-4e6b-9f40-f76d917612f8_882x146.png 1272w, https://substackcdn.com/image/fetch/$s_!ldQv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5eee4274-2b32-4e6b-9f40-f76d917612f8_882x146.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ldQv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5eee4274-2b32-4e6b-9f40-f76d917612f8_882x146.png" width="492" height="81.4421768707483" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5eee4274-2b32-4e6b-9f40-f76d917612f8_882x146.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:146,&quot;width&quot;:882,&quot;resizeWidth&quot;:492,&quot;bytes&quot;:13148,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/173584451?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5eee4274-2b32-4e6b-9f40-f76d917612f8_882x146.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ldQv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5eee4274-2b32-4e6b-9f40-f76d917612f8_882x146.png 424w, https://substackcdn.com/image/fetch/$s_!ldQv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5eee4274-2b32-4e6b-9f40-f76d917612f8_882x146.png 848w, https://substackcdn.com/image/fetch/$s_!ldQv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5eee4274-2b32-4e6b-9f40-f76d917612f8_882x146.png 1272w, https://substackcdn.com/image/fetch/$s_!ldQv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5eee4274-2b32-4e6b-9f40-f76d917612f8_882x146.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h2>5. The Actual Race! </h2><p>Finally we have come to the most exciting part of game, where the race will actually take place. I am hoping we will get to do some animation here. Here&#8217;s the old implementation - </p><pre><code>extension FX790...
    private func race...
        <strong>repeat {
            for horse in horses {
                if horses.hasNoWinner {
                    clearHorsePosition(horse)
                    horse.move()
                }
                displayHorsePosition(horse)
            }
        } while horses.hasNoWinner</strong>

    private func clearHorsePosition(_ horse: Horse) {
        PRINT(csr: Int(horse.position), " ")
    }

    private func displayHorsePosition(_ horse: Horse) {
        PRINT(csr: horse.position, "\(horse.symbol)")
    }</code></pre><p>This code is running a little race loop. It keeps repeating as long as no horse has reached the finish line. For each horse, it first checks again if the race still has no winner, and if so, it clears the horse&#8217;s old spot and moves it forward. It then shows the horse&#8217;s position on the track. Once a winner is found the loop ends.</p><p>Lets create a new state. </p><pre><code>enum GameState {
    <strong>case race(Horse)</strong></code></pre><p>We have a Horse as an associated value, since I want to move one horse at a time. So the state <strong>race(Horse)</strong> will be for that particular horse movement. </p><p>Next, we need to display the horses position in this view. </p><pre><code>class HorseRaceViewModel...
    <strong>var raceTrackString: String = ""</strong>
    var displayText...
        <strong>case .race: "\(raceTrackString)"</strong></code></pre><p>This creates a string <strong>raceTrackString</strong>, which will show each horses position. As the horses move, their positions will change, and we will redraw that string. The view is observing the <strong>HorseRaceViewModel</strong>, and every time this string <strong>raceTrackString </strong>updates, the view will be updated. That will give the illusion of them moving right in the string. </p><p>Now we implement the horse movement. </p><pre><code>class HorseRaceViewModel...
    private func moveToNextState...
        case .displayRaceStart: 
            <strong>state = .race(horses[0])</strong>
        case .race(let horse):
            if horses.hasNoWinner {
                <strong>moveHorse(horse)</strong>
                state = .race(<strong>horses.next</strong>(after: horse))
            } else {
                state = ... // go to race end state
            }
        }

    private func <strong>moveHorse</strong>(_ horse: Horse) {
        guard horses.hasNoWinner else { return }
        horse.move()
        redrawRaceTrack()
    }
    
    private func <strong>redrawRaceTrack</strong>() {
        var track = 
            [String](repeating: " ", count: GameConfig.goalPosition + 1)
        horses.forEach { track[$0.position] = $0.symbol }
        raceTrackString = track.joined()
    }</code></pre><p>On every RETURN key press, the <strong>moveHorse()</strong> method will be called for each horse in turn. And it will remain in the <strong>race</strong> state, until a winner is reached. I created a helper <strong>next(:Horse)</strong> method, that will loop around picking one horse at a time. </p><pre><code>extension Array where Element == Horse...    
    func <strong>next</strong>(after horse: Horse) -&gt; Horse {
        let index = firstIndex(where: { $0.id == horse.id })!
        let nextIndex = (index + 1) % count
        return self[nextIndex]
    }
}</code></pre><p>This is how it looks &#8211;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1-Db!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb63baf1a-5a6e-4383-bbaa-dcb075bca2b8_920x144.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1-Db!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb63baf1a-5a6e-4383-bbaa-dcb075bca2b8_920x144.png 424w, https://substackcdn.com/image/fetch/$s_!1-Db!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb63baf1a-5a6e-4383-bbaa-dcb075bca2b8_920x144.png 848w, https://substackcdn.com/image/fetch/$s_!1-Db!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb63baf1a-5a6e-4383-bbaa-dcb075bca2b8_920x144.png 1272w, https://substackcdn.com/image/fetch/$s_!1-Db!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb63baf1a-5a6e-4383-bbaa-dcb075bca2b8_920x144.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1-Db!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb63baf1a-5a6e-4383-bbaa-dcb075bca2b8_920x144.png" width="502" height="78.57391304347826" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b63baf1a-5a6e-4383-bbaa-dcb075bca2b8_920x144.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:144,&quot;width&quot;:920,&quot;resizeWidth&quot;:502,&quot;bytes&quot;:10664,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/173584451?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb63baf1a-5a6e-4383-bbaa-dcb075bca2b8_920x144.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1-Db!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb63baf1a-5a6e-4383-bbaa-dcb075bca2b8_920x144.png 424w, https://substackcdn.com/image/fetch/$s_!1-Db!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb63baf1a-5a6e-4383-bbaa-dcb075bca2b8_920x144.png 848w, https://substackcdn.com/image/fetch/$s_!1-Db!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb63baf1a-5a6e-4383-bbaa-dcb075bca2b8_920x144.png 1272w, https://substackcdn.com/image/fetch/$s_!1-Db!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb63baf1a-5a6e-4383-bbaa-dcb075bca2b8_920x144.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h2>6. Auto Horse Movement</h2><p>We obviously don&#8217;t want to be pressing RETURN to move the horses. Lets implement a ticker that will move the horse automatically. I implemented that in the <strong>HorseRaceView</strong>.</p><pre><code> struct HorseRaceView...
    <strong>let timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect()</strong>
    
    var body: some View...
        ...
        <strong>.onReceive(timer) { _ in
            viewModel.handleTick()
        }
        .animation(.easeInOut(duration: 0.1), 
                   value: viewModel.raceTrackString)</strong>
    
class HorseRaceViewModel...
    func <strong>handleTick</strong>() {
        switch state {
        case .race: moveToNextState()
        default: return
        }
    }</code></pre><p>The handleTick() method is called every 0.1 seconds, and it moves the horse. I also added a little <strong>animation </strong>property to show smoother transition. </p><h2>7. Display Goal</h2><p>When the race ends, the UI displays &#8220;GOAL!&#8221;. This is the old code. </p><pre><code>extension FX790...
    private func displayGoal() {
        <strong>PRINT(csr: 0, "GOAL!")</strong>
        for _ in 1...7 {
            BEEP()
            BEEP(1)
        }
        TIMER()
    }</code></pre><p>Lets create a new state and move there when the race ends. </p><pre><code>enum GameState...
    <strong>case displayGoal

</strong>class HorseRaceViewModel...
    var displayText...
        case .displayGoal: 
            <strong>"\(raceTrackString.replaceFirst(with: "GOAL!"))"</strong>

    private func moveToNextState...
        case .race(let horse):
            if horses.hasNoWinner {
                moveHorse(horse)
                state = .race(horses.next(after: horse))
            } else {
                state = <strong>.displayGoal</strong>
            }</code></pre><p>I created a helper String extension <strong>replaceFirst</strong>. </p><pre><code>extension String {
    func replaceFirst(with replacement: String) -&gt; String {
        let cutIndex = index(startIndex, offsetBy: replacement.count)
        return replacement + self[cutIndex...]
    }
}</code></pre><p>And now it displays &#8211;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QSPx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce083c21-e86f-4f09-8511-71e850893559_916x150.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QSPx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce083c21-e86f-4f09-8511-71e850893559_916x150.png 424w, https://substackcdn.com/image/fetch/$s_!QSPx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce083c21-e86f-4f09-8511-71e850893559_916x150.png 848w, https://substackcdn.com/image/fetch/$s_!QSPx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce083c21-e86f-4f09-8511-71e850893559_916x150.png 1272w, https://substackcdn.com/image/fetch/$s_!QSPx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce083c21-e86f-4f09-8511-71e850893559_916x150.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QSPx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce083c21-e86f-4f09-8511-71e850893559_916x150.png" width="458" height="75" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ce083c21-e86f-4f09-8511-71e850893559_916x150.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:150,&quot;width&quot;:916,&quot;resizeWidth&quot;:458,&quot;bytes&quot;:14586,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/173584451?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce083c21-e86f-4f09-8511-71e850893559_916x150.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QSPx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce083c21-e86f-4f09-8511-71e850893559_916x150.png 424w, https://substackcdn.com/image/fetch/$s_!QSPx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce083c21-e86f-4f09-8511-71e850893559_916x150.png 848w, https://substackcdn.com/image/fetch/$s_!QSPx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce083c21-e86f-4f09-8511-71e850893559_916x150.png 1272w, https://substackcdn.com/image/fetch/$s_!QSPx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce083c21-e86f-4f09-8511-71e850893559_916x150.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h2>8. Winners Collect Prize</h2><p>Next we distribute prizes to all the winner. This is from old code. </p><pre><code>extension FX790...
    private func race...
        for player in players {
            if player.madeAnyBet() {
                let M = player.collectPrize(if: horses.winningHorse!)
                displayPlayerPrize(player, prize: M)
            }
            displayPlayerHoldings(player)
        }</code></pre><p>This code intermingles the collecting prize and displaying total money. I will break it up into 2 states  &#8211;</p><pre><code>enum GameState...
    case <strong>displayPrize</strong>(Player, Int)
    case <strong>displayTotal</strong>(Player)

class HorseRaceViewModel...
    var displayText...
        case .<strong>displayPrize</strong>(let p, let prize): 
             "Player \(p.id) &#8594; PRIZE $\(<strong>prize</strong>)"
        case .<strong>displayTotal</strong>(let p): "Player \(p.id) has $\(p.money)"</code></pre><p>Next we loop though each player, collecting prizes, and displaying total. </p><pre><code>class HorseRaceViewModel...
  private func moveToNextState...
        case .displayGoal:
            <strong>if let player = players.first() {
                state = player.madeAnyBet
                    ? .displayPrize(player, collectPrize(player))
                    : .displayTotal(player)
            }</strong>
        case .displayPrize(let player, _):
            state = .displayTotal(player)
        case .displayTotal(let player):
            <strong>if let nextPlayer = players.next(after: player) {
                state = next.madeAnyBet
                    ? .displayPrize(next, collectPrize(next))
                    : .displayTotal(next)</strong>
            } else { <em>// next</em> }

    private func collectPrize(_ player: Player) {
        player.collectPrize(if: horses.winningHorse!)
    }</code></pre><p>This will display the following - </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rvI0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F796f43d2-59b5-4581-92bf-92c272723480_920x144.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rvI0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F796f43d2-59b5-4581-92bf-92c272723480_920x144.png 424w, https://substackcdn.com/image/fetch/$s_!rvI0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F796f43d2-59b5-4581-92bf-92c272723480_920x144.png 848w, https://substackcdn.com/image/fetch/$s_!rvI0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F796f43d2-59b5-4581-92bf-92c272723480_920x144.png 1272w, https://substackcdn.com/image/fetch/$s_!rvI0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F796f43d2-59b5-4581-92bf-92c272723480_920x144.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rvI0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F796f43d2-59b5-4581-92bf-92c272723480_920x144.png" width="482" height="75.44347826086957" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/796f43d2-59b5-4581-92bf-92c272723480_920x144.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:144,&quot;width&quot;:920,&quot;resizeWidth&quot;:482,&quot;bytes&quot;:18330,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/173584451?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F796f43d2-59b5-4581-92bf-92c272723480_920x144.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rvI0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F796f43d2-59b5-4581-92bf-92c272723480_920x144.png 424w, https://substackcdn.com/image/fetch/$s_!rvI0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F796f43d2-59b5-4581-92bf-92c272723480_920x144.png 848w, https://substackcdn.com/image/fetch/$s_!rvI0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F796f43d2-59b5-4581-92bf-92c272723480_920x144.png 1272w, https://substackcdn.com/image/fetch/$s_!rvI0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F796f43d2-59b5-4581-92bf-92c272723480_920x144.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>And the total is &#8211;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aNY6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29cb7351-d2b5-4598-9471-f009b7dfa3f3_918x150.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aNY6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29cb7351-d2b5-4598-9471-f009b7dfa3f3_918x150.png 424w, https://substackcdn.com/image/fetch/$s_!aNY6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29cb7351-d2b5-4598-9471-f009b7dfa3f3_918x150.png 848w, https://substackcdn.com/image/fetch/$s_!aNY6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29cb7351-d2b5-4598-9471-f009b7dfa3f3_918x150.png 1272w, https://substackcdn.com/image/fetch/$s_!aNY6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29cb7351-d2b5-4598-9471-f009b7dfa3f3_918x150.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aNY6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29cb7351-d2b5-4598-9471-f009b7dfa3f3_918x150.png" width="482" height="78.75816993464052" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/29cb7351-d2b5-4598-9471-f009b7dfa3f3_918x150.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:150,&quot;width&quot;:918,&quot;resizeWidth&quot;:482,&quot;bytes&quot;:17076,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/173584451?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29cb7351-d2b5-4598-9471-f009b7dfa3f3_918x150.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aNY6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29cb7351-d2b5-4598-9471-f009b7dfa3f3_918x150.png 424w, https://substackcdn.com/image/fetch/$s_!aNY6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29cb7351-d2b5-4598-9471-f009b7dfa3f3_918x150.png 848w, https://substackcdn.com/image/fetch/$s_!aNY6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29cb7351-d2b5-4598-9471-f009b7dfa3f3_918x150.png 1272w, https://substackcdn.com/image/fetch/$s_!aNY6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29cb7351-d2b5-4598-9471-f009b7dfa3f3_918x150.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h2>9. Replay</h2><p>The next screen is prompt to ask player if they want to replay. </p><pre><code>extension FX790...
    private func promptReplay() -&gt; Bool {
        PRINT()
        BEEP()
        while true {
            let ans: String = <strong>INPUT("REPLAY (Y/N)?")</strong>
            if ans == "Y" { return true }
            if ans == "N" { return false }
        }
    } </code></pre><p>Lets create a prompt state. </p><pre><code>enum GameState...
    case chooseReplay

class HorseRaceViewModel...
    var displayText...
        case .chooseReplay: <strong>"Replay (Y/N)?"</strong></code></pre><p>This is like when choosing a horse, there is no blinking cursor, and a single key press moves to next state. </p><pre><code>class HorseRaceViewModel...
    private func handleUserInput...
        case .chooseHorse, .<strong>chooseReplay</strong>:
            userInput.append(char)
            moveToNextState()

    private func moveToNextState...
        case .displayTotal(let player):
            if let next = players.next(after: player) {
                state = next.madeAnyBet
                    ? .displayPrize(next, collectPrize(next))
                    : .displayTotal(next)
            } else {
                <strong>state = .chooseReplay</strong>
            }</code></pre><p>Now we implement the processing of the replay &#8211;</p><pre><code>class HorseRaceViewModel...
    private func moveToNextState...
        <strong>case .promptReplay:
            if let replay = replay() {
                if replay {
                    state = .displayRaceNumber  </strong><em>// New Race</em><strong>
                } 
            }</strong>

    private func replay() -&gt; Bool? {
        let response = readInput().uppercased()
        if response == "Y" {
            <strong>raceNumber += 1</strong>
            return true
        }
        if response == "N" {
            return false
        }
        return nil
    }</code></pre><p>This will show the replay prompt &#8211;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sBOs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f04389d-ce79-47b9-a921-7bd2cfc8e2b3_920x148.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sBOs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f04389d-ce79-47b9-a921-7bd2cfc8e2b3_920x148.png 424w, https://substackcdn.com/image/fetch/$s_!sBOs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f04389d-ce79-47b9-a921-7bd2cfc8e2b3_920x148.png 848w, https://substackcdn.com/image/fetch/$s_!sBOs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f04389d-ce79-47b9-a921-7bd2cfc8e2b3_920x148.png 1272w, https://substackcdn.com/image/fetch/$s_!sBOs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f04389d-ce79-47b9-a921-7bd2cfc8e2b3_920x148.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sBOs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f04389d-ce79-47b9-a921-7bd2cfc8e2b3_920x148.png" width="460" height="74" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7f04389d-ce79-47b9-a921-7bd2cfc8e2b3_920x148.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:148,&quot;width&quot;:920,&quot;resizeWidth&quot;:460,&quot;bytes&quot;:16808,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/173584451?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f04389d-ce79-47b9-a921-7bd2cfc8e2b3_920x148.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sBOs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f04389d-ce79-47b9-a921-7bd2cfc8e2b3_920x148.png 424w, https://substackcdn.com/image/fetch/$s_!sBOs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f04389d-ce79-47b9-a921-7bd2cfc8e2b3_920x148.png 848w, https://substackcdn.com/image/fetch/$s_!sBOs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f04389d-ce79-47b9-a921-7bd2cfc8e2b3_920x148.png 1272w, https://substackcdn.com/image/fetch/$s_!sBOs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f04389d-ce79-47b9-a921-7bd2cfc8e2b3_920x148.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>And if the user pressed &#8220;y&#8221; it will increment the race number and restart the race with new odds. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!z6Gt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fec73b1-ce42-4825-b471-68644ee8a404_920x152.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!z6Gt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fec73b1-ce42-4825-b471-68644ee8a404_920x152.png 424w, https://substackcdn.com/image/fetch/$s_!z6Gt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fec73b1-ce42-4825-b471-68644ee8a404_920x152.png 848w, https://substackcdn.com/image/fetch/$s_!z6Gt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fec73b1-ce42-4825-b471-68644ee8a404_920x152.png 1272w, https://substackcdn.com/image/fetch/$s_!z6Gt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fec73b1-ce42-4825-b471-68644ee8a404_920x152.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!z6Gt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fec73b1-ce42-4825-b471-68644ee8a404_920x152.png" width="454" height="75.00869565217391" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7fec73b1-ce42-4825-b471-68644ee8a404_920x152.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:152,&quot;width&quot;:920,&quot;resizeWidth&quot;:454,&quot;bytes&quot;:13438,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/173584451?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fec73b1-ce42-4825-b471-68644ee8a404_920x152.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!z6Gt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fec73b1-ce42-4825-b471-68644ee8a404_920x152.png 424w, https://substackcdn.com/image/fetch/$s_!z6Gt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fec73b1-ce42-4825-b471-68644ee8a404_920x152.png 848w, https://substackcdn.com/image/fetch/$s_!z6Gt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fec73b1-ce42-4825-b471-68644ee8a404_920x152.png 1272w, https://substackcdn.com/image/fetch/$s_!z6Gt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fec73b1-ce42-4825-b471-68644ee8a404_920x152.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h2>10. Game Over</h2><p>There are two ways a game can be over. If all players have $0 remaining or user presses &#8220;n&#8221; on the replay prompt. </p><pre><code>extension FX790...
    private func race...
        if players.remaining &gt; 0, promptReplay() {
            race(num: R+1, horses: horses, players: players)
        } else {
            displayGameOver()
        }

    private func displayGameOver() {
        PRINT()
        PRINT("GAME OVER")
    }</code></pre><p>So our final state is going to be &#8211;</p><pre><code>enum GameState...
    case displayGameOver

class HorseRaceViewModel...
    var displayText...
        case .displayGameOver: "GAME OVER"</code></pre><p>And <strong>moveToNextState()</strong> becomes &#8211;</p><pre><code>class HorseRaceViewModel...
    private func moveToNextState
        case .displayTotal(let player):
            if let next = players.next(after: player) {
                state = next.madeAnyBet
                    ? .displayPrize(next, collectPrize(next))
                    : .displayTotal(next)
            } else {
                <strong>state = players.remaining 
                    ? .promptReplay 
                    : .displayGameOver</strong>
            }
        case .promptReplay:
            if let replay = replay() {
                <strong>state = replay ? .displayRaceNumber : .displayGameOver</strong>
            }
            clearUserInput()
        <strong>case .displayGameOver: break</strong></code></pre><p>And we are done. Here&#8217;s the final screen. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tAvC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f08085e-9611-4def-9396-517c4c3e18b6_914x152.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tAvC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f08085e-9611-4def-9396-517c4c3e18b6_914x152.png 424w, https://substackcdn.com/image/fetch/$s_!tAvC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f08085e-9611-4def-9396-517c4c3e18b6_914x152.png 848w, https://substackcdn.com/image/fetch/$s_!tAvC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f08085e-9611-4def-9396-517c4c3e18b6_914x152.png 1272w, https://substackcdn.com/image/fetch/$s_!tAvC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f08085e-9611-4def-9396-517c4c3e18b6_914x152.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tAvC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f08085e-9611-4def-9396-517c4c3e18b6_914x152.png" width="462" height="76.83150984682713" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6f08085e-9611-4def-9396-517c4c3e18b6_914x152.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:152,&quot;width&quot;:914,&quot;resizeWidth&quot;:462,&quot;bytes&quot;:14486,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/173584451?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f08085e-9611-4def-9396-517c4c3e18b6_914x152.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tAvC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f08085e-9611-4def-9396-517c4c3e18b6_914x152.png 424w, https://substackcdn.com/image/fetch/$s_!tAvC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f08085e-9611-4def-9396-517c4c3e18b6_914x152.png 848w, https://substackcdn.com/image/fetch/$s_!tAvC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f08085e-9611-4def-9396-517c4c3e18b6_914x152.png 1272w, https://substackcdn.com/image/fetch/$s_!tAvC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f08085e-9611-4def-9396-517c4c3e18b6_914x152.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h2>Conclusion</h2><p>This is how far I will go with this game. Its fully done. Its looks and behave very much like the old BASIC program. I wanted to see how much things have changed with UI programming. The biggest change I would say is how we are doing MVVM pattern. Plus, game programming in this pattern leads to to Finite State Machine. The whole <strong>moveToNextState</strong> method is exactly like the old BASIC, except that its changing states at every step, rather than being procedural program. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!10nC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe73bc062-fbbe-4c55-a4b9-a060d556afc1_1360x2400.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!10nC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe73bc062-fbbe-4c55-a4b9-a060d556afc1_1360x2400.png 424w, https://substackcdn.com/image/fetch/$s_!10nC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe73bc062-fbbe-4c55-a4b9-a060d556afc1_1360x2400.png 848w, https://substackcdn.com/image/fetch/$s_!10nC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe73bc062-fbbe-4c55-a4b9-a060d556afc1_1360x2400.png 1272w, https://substackcdn.com/image/fetch/$s_!10nC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe73bc062-fbbe-4c55-a4b9-a060d556afc1_1360x2400.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!10nC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe73bc062-fbbe-4c55-a4b9-a060d556afc1_1360x2400.png" width="1360" height="2400" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e73bc062-fbbe-4c55-a4b9-a060d556afc1_1360x2400.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2400,&quot;width&quot;:1360,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:537140,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/173584451?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe73bc062-fbbe-4c55-a4b9-a060d556afc1_1360x2400.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!10nC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe73bc062-fbbe-4c55-a4b9-a060d556afc1_1360x2400.png 424w, https://substackcdn.com/image/fetch/$s_!10nC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe73bc062-fbbe-4c55-a4b9-a060d556afc1_1360x2400.png 848w, https://substackcdn.com/image/fetch/$s_!10nC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe73bc062-fbbe-4c55-a4b9-a060d556afc1_1360x2400.png 1272w, https://substackcdn.com/image/fetch/$s_!10nC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe73bc062-fbbe-4c55-a4b9-a060d556afc1_1360x2400.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p>]]></content:encoded></item><item><title><![CDATA[Horse Race Game, Part 2]]></title><description><![CDATA[Continuing from previous part, I converted the old BASIC game from Casio FX-790P into SwiftUI.]]></description><link>https://www.codingpapa.net/p/horse-race-game-part-2</link><guid isPermaLink="false">https://www.codingpapa.net/p/horse-race-game-part-2</guid><dc:creator><![CDATA[Rohit]]></dc:creator><pubDate>Sun, 14 Sep 2025 15:29:41 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!_QNo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6de2dbe1-384e-4585-9f5a-8b62a20770f2_1024x608.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_QNo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6de2dbe1-384e-4585-9f5a-8b62a20770f2_1024x608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_QNo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6de2dbe1-384e-4585-9f5a-8b62a20770f2_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!_QNo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6de2dbe1-384e-4585-9f5a-8b62a20770f2_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!_QNo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6de2dbe1-384e-4585-9f5a-8b62a20770f2_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!_QNo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6de2dbe1-384e-4585-9f5a-8b62a20770f2_1024x608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_QNo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6de2dbe1-384e-4585-9f5a-8b62a20770f2_1024x608.png" width="1024" height="608" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6de2dbe1-384e-4585-9f5a-8b62a20770f2_1024x608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:608,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_QNo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6de2dbe1-384e-4585-9f5a-8b62a20770f2_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!_QNo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6de2dbe1-384e-4585-9f5a-8b62a20770f2_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!_QNo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6de2dbe1-384e-4585-9f5a-8b62a20770f2_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!_QNo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6de2dbe1-384e-4585-9f5a-8b62a20770f2_1024x608.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Introduction</h2><p>In <a href="https://www.codingpapa.net/p/horse-race-game-part-1">Part 1</a>, I converted an old BASIC game from <a href="https://www.rskey.org/fx790p">Casio FX-790P</a> into Swift programing language. By the end of that part, I had the beginnings of a MVVM app. The <strong>Horse</strong> and <strong>Player</strong> classes were the <strong>Models</strong>, the <strong>horseRaceGame</strong>() method was the <strong>ViewModel</strong>, and the <strong>16</strong> <strong>display</strong> and <strong>prompt</strong> messages were the <strong>Views</strong>. In this part, I am going to put it all together in a proper SwiftUI application.</p><p>Here is the original game description. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jeG8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3789587d-53f7-41a7-a63e-a2df2381d06e_1564x806.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jeG8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3789587d-53f7-41a7-a63e-a2df2381d06e_1564x806.png 424w, https://substackcdn.com/image/fetch/$s_!jeG8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3789587d-53f7-41a7-a63e-a2df2381d06e_1564x806.png 848w, https://substackcdn.com/image/fetch/$s_!jeG8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3789587d-53f7-41a7-a63e-a2df2381d06e_1564x806.png 1272w, https://substackcdn.com/image/fetch/$s_!jeG8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3789587d-53f7-41a7-a63e-a2df2381d06e_1564x806.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jeG8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3789587d-53f7-41a7-a63e-a2df2381d06e_1564x806.png" width="602" height="310.09615384615387" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3789587d-53f7-41a7-a63e-a2df2381d06e_1564x806.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:750,&quot;width&quot;:1456,&quot;resizeWidth&quot;:602,&quot;bytes&quot;:265546,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/171816002?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3789587d-53f7-41a7-a63e-a2df2381d06e_1564x806.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jeG8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3789587d-53f7-41a7-a63e-a2df2381d06e_1564x806.png 424w, https://substackcdn.com/image/fetch/$s_!jeG8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3789587d-53f7-41a7-a63e-a2df2381d06e_1564x806.png 848w, https://substackcdn.com/image/fetch/$s_!jeG8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3789587d-53f7-41a7-a63e-a2df2381d06e_1564x806.png 1272w, https://substackcdn.com/image/fetch/$s_!jeG8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3789587d-53f7-41a7-a63e-a2df2381d06e_1564x806.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We are going to try to stick to this as much as possible. The goal is not to improve the game or the UI, but to see how far and different modern languages and UI frameworks have become since the 90s. </p><h2>1. Start Game</h2><p>Our very first view is the display of the game title. Here&#8217;s the code from part 1. </p><pre><code>extension FX790...
    private func displayGameTitle() {
        <strong>PRINT("&lt; Horse Race &gt;")</strong>
        for _ in 1...5 {
            BEEP()
            BEEP(1)
        }
    }</code></pre><p>To convert this to SwiftUI, we need to start with the <strong>@main</strong> App. </p><pre><code><strong>@main</strong>
struct <strong>HorseRaceApp: App</strong> {
    var body: some Scene {
        WindowGroup {
            <strong>HorseRaceView()</strong>
        }
    }
}</code></pre><p>All our game display logic will go inside <strong>HorseRaceView. </strong>I wanted to create same view as original monospaced, single line, text display. </p><pre><code>struct HorseRaceView: View {
    var body: some View {
        Text(<strong>"&lt; Horse Race &gt;"</strong>)
            .font(.system(size: 28, <strong>design: .monospaced</strong>))
            .frame(<strong>width: 400</strong>, alignment: .leading)
            .padding()
            .background(Color.white)
            .border(Color.gray, width: 1)
    }
}</code></pre><p>The width of 400 will fit 23 characters, as our original game. Here&#8217;s what is rendered. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QZry!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bcad7cd-14a9-4d9f-ba1b-c2e2dca3d7ab_1132x230.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QZry!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bcad7cd-14a9-4d9f-ba1b-c2e2dca3d7ab_1132x230.png 424w, https://substackcdn.com/image/fetch/$s_!QZry!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bcad7cd-14a9-4d9f-ba1b-c2e2dca3d7ab_1132x230.png 848w, https://substackcdn.com/image/fetch/$s_!QZry!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bcad7cd-14a9-4d9f-ba1b-c2e2dca3d7ab_1132x230.png 1272w, https://substackcdn.com/image/fetch/$s_!QZry!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bcad7cd-14a9-4d9f-ba1b-c2e2dca3d7ab_1132x230.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QZry!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bcad7cd-14a9-4d9f-ba1b-c2e2dca3d7ab_1132x230.png" width="524" height="106.46643109540636" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9bcad7cd-14a9-4d9f-ba1b-c2e2dca3d7ab_1132x230.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:230,&quot;width&quot;:1132,&quot;resizeWidth&quot;:524,&quot;bytes&quot;:20272,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/171816002?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bcad7cd-14a9-4d9f-ba1b-c2e2dca3d7ab_1132x230.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QZry!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bcad7cd-14a9-4d9f-ba1b-c2e2dca3d7ab_1132x230.png 424w, https://substackcdn.com/image/fetch/$s_!QZry!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bcad7cd-14a9-4d9f-ba1b-c2e2dca3d7ab_1132x230.png 848w, https://substackcdn.com/image/fetch/$s_!QZry!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bcad7cd-14a9-4d9f-ba1b-c2e2dca3d7ab_1132x230.png 1272w, https://substackcdn.com/image/fetch/$s_!QZry!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bcad7cd-14a9-4d9f-ba1b-c2e2dca3d7ab_1132x230.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>All our displays will happen inside this box. So I decided to take this box and make it a base view called <strong>TrackView</strong>, (as in a &#8220;horse track&#8221;)</p><pre><code>struct <strong>TrackView</strong>&lt;Content: View&gt;: View {
    let fontSize: CGFloat = 28
    let content: () -&gt; Content
    
    init(@ViewBuilder content: @escaping () -&gt; Content) {
        self.content = content
    }
    
    var body: some View {
        <strong>content()</strong>
            .font(.system(size: fontSize, design: .monospaced))
            .frame(width: <strong>trackWidth()</strong>, alignment: .leading)
            .padding()
            .background(Color.white)
            .border(Color.gray, width: 1)
    }
}</code></pre><p>And then our <strong>HorseRaceView</strong> can use this base view &#8211;</p><pre><code>struct HorseRaceView: View {
    var body: some View {
        <strong>TrackView</strong> {
            Text("&lt; Horse Race &gt;")
        }
    }
}</code></pre><p>Also notice that that I make the width of the track dynamic with a function <strong>trackWidth() &#8211;</strong></p><pre><code>struct TrackView...
    private func trackWidth() -&gt; CGFloat {
        let font = NSFont.monospacedSystemFont(
                       ofSize: <strong>fontSize</strong>, 
                       weight: .regular)
        let charWidth = "X".size(withAttributes: [.font: font]).width
        return charWidth * CGFloat(<strong>GameConfig.goalPosition</strong>)
    }</code></pre><p><strong>"X".size(withAttributes:) </strong>calculates the width of a single character, which we multiply by the number of characters (<strong>GameConfig.goalPosition</strong>) to get the total track width in pixels. The <strong>frame(width:) </strong>now dynamically fits our 23-character track.</p><h2>2. Display Horses</h2><p>The next display is the horses description &#8212;</p><pre><code>extension FX790...
    private func displayHorses(_ horses: [Horse]) {
        PRINT() // clear screen
        <strong>PRINT("HORSE")
        for horse in horses {
            PRINT(" \(horse.id)\(horse.symbol)")
        }</strong>
        TIMER()
        TIMER()
    }</code></pre><p>We don&#8217;t need a whole new <strong>View</strong> type every time the text changes. SwiftUI encourages <strong>state-driven UIs</strong>, not manually swapping whole views. The view&#8217;s body automatically re-renders when its state changes. That&#8217;s the natural way to do timed or gesture changes. In our game, the new display message is just a different state of the same <strong>HorseRaceView</strong>. This is much easier to animate, control timing, or even loop messages later.  </p><p>So we will keep everything inside the <strong>HorseRaceView</strong> and just drive it with <strong>@State</strong>. The state will be driven by a <strong>HorseRaceViewModel</strong>. In BASIC, the code was very procedural, which we cannot do in SwiftUI. So we will have to do some state management. We will need an enum to track the current state. </p><pre><code><strong>enum GameState</strong> {
    case displayTitle
    case describeHorses
} </code></pre><p>The current state will be maintained by the view model. </p><pre><code><strong>@Observable</strong>
class <strong>HorseRaceViewModel</strong>  {
    private var <strong>state</strong>: GameState = .displayGameTitle
    private var <strong>horses</strong>: [Horse] = <strong>Horse.all()</strong>

    var <strong>displayText</strong>: String {
        return switch state {
        case .displayTitle: "&lt; Horse Race &gt;"
        case .describeHorses: 
            <strong>"HORSES \(horses.map(\.label).joined(separator: " "))"</strong>
        }
    }
    
    func moveToNextState() {
        switch state {
        case .displayTitle: state = .displayHorses
        case .displayHorses: state = break
        }
    }
}</code></pre><p>The <strong>horses</strong> are obtained from the static method <strong>all()</strong> in the <strong>Horse</strong> model, and the <strong>label</strong> is extension property. </p><pre><code>extension Horse {
    var <strong>label</strong>: String { "\(id)\(symbol)" }

    static func <strong>all()</strong> -&gt; [Horse] {
        [
            Horse(id: 1, symbol: "&#9824;"),
            Horse(id: 2, symbol: "&#9829;"),
            Horse(id: 3, symbol: "&#9830;"),
            Horse(id: 4, symbol: "&#9827;")
        ]
    }
}</code></pre><p>And finally, our view is &#8212;</p><pre><code>struct HorseRaceView: View {
    <strong>@State private var viewModel = HorseRaceViewModel()</strong>
    
    var body: some View {
        TrackView {
            Text(viewModel.displayText)
        }
        <strong>.onKeyPress(.return) {
            viewModel.moveToNextState()
            return .handled
        }</strong>
    }
}</code></pre><p>On pressing RETURN, our state is moved to the next state. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cxLY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb223122-e6fd-4a15-a726-506a7673c7b5_1090x194.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cxLY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb223122-e6fd-4a15-a726-506a7673c7b5_1090x194.png 424w, https://substackcdn.com/image/fetch/$s_!cxLY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb223122-e6fd-4a15-a726-506a7673c7b5_1090x194.png 848w, https://substackcdn.com/image/fetch/$s_!cxLY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb223122-e6fd-4a15-a726-506a7673c7b5_1090x194.png 1272w, https://substackcdn.com/image/fetch/$s_!cxLY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb223122-e6fd-4a15-a726-506a7673c7b5_1090x194.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cxLY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb223122-e6fd-4a15-a726-506a7673c7b5_1090x194.png" width="492" height="87.56697247706423" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/db223122-e6fd-4a15-a726-506a7673c7b5_1090x194.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:194,&quot;width&quot;:1090,&quot;resizeWidth&quot;:492,&quot;bytes&quot;:20196,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/171816002?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb223122-e6fd-4a15-a726-506a7673c7b5_1090x194.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cxLY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb223122-e6fd-4a15-a726-506a7673c7b5_1090x194.png 424w, https://substackcdn.com/image/fetch/$s_!cxLY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb223122-e6fd-4a15-a726-506a7673c7b5_1090x194.png 848w, https://substackcdn.com/image/fetch/$s_!cxLY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb223122-e6fd-4a15-a726-506a7673c7b5_1090x194.png 1272w, https://substackcdn.com/image/fetch/$s_!cxLY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb223122-e6fd-4a15-a726-506a7673c7b5_1090x194.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>We need to capture the key press, and for that the view must be in focus. So I made the entire <strong>TrackView</strong> focusable. </p><pre><code>struct TrackView...
    @FocusState private var isFocused: Bool
    
    var body: some View {
        content()
            .font(.system(size: fontSize, design: .monospaced))
            .frame(width: trackWidth(), alignment: .leading)
            .padding()
            .background(Color.white)
            .border(Color.gray, width: 1)
            <strong>.focusable()
            .focused($isFocused)
            .focusEffectDisabled()
            .onAppear {
                isFocused = true
            }</strong>
    }</code></pre><h2>3. Number of Players</h2><p>Next is the prompt to get the user input for number of players. </p><pre><code>extension FX790...
  private func <strong>promptNumPlayers()</strong> -&gt; Int {
    PRINT()
    BEEP()
    while true {
      let p: Int = INPUT("How many players ")
       if (GameConfig.minPlayers...GameConfig.maxPlayers).contains(p) {
         return p
       }
    }
  }</code></pre><p>Let&#8217;s add a new state for this. </p><pre><code>enum GameState {
    case displayTitle
    case displayHorses
    <strong>case promptNumPlayers</strong>
}</code></pre><p>Our <strong>displayText</strong> and <strong>moveToNextState</strong>() needs a new case statement for the <strong>promptNumPlayers</strong>. </p><pre><code>class HorseRaceViewModel...
    var displayText: String {
        return switch state {
        ...
        <strong>case .promptNumPlayers: "How many players?"</strong>
        }
    }

    private func moveToNextState() {
        switch state {
        case .displayTitle: state = .displayHorses
        case .displayHorses: state = <strong>.promptNumPlayers</strong>
        <strong>case .promptNumPlayers: break</strong>
    }</code></pre><p>That&#8217;s it. Just couple lines of code, and now our prompt shows up. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Dgag!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F124fe8a5-94de-4dfb-9258-7151a7e7811b_926x156.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Dgag!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F124fe8a5-94de-4dfb-9258-7151a7e7811b_926x156.png 424w, https://substackcdn.com/image/fetch/$s_!Dgag!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F124fe8a5-94de-4dfb-9258-7151a7e7811b_926x156.png 848w, https://substackcdn.com/image/fetch/$s_!Dgag!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F124fe8a5-94de-4dfb-9258-7151a7e7811b_926x156.png 1272w, https://substackcdn.com/image/fetch/$s_!Dgag!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F124fe8a5-94de-4dfb-9258-7151a7e7811b_926x156.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Dgag!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F124fe8a5-94de-4dfb-9258-7151a7e7811b_926x156.png" width="468" height="78.84233261339092" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/124fe8a5-94de-4dfb-9258-7151a7e7811b_926x156.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:156,&quot;width&quot;:926,&quot;resizeWidth&quot;:468,&quot;bytes&quot;:17630,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/171816002?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F124fe8a5-94de-4dfb-9258-7151a7e7811b_926x156.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Dgag!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F124fe8a5-94de-4dfb-9258-7151a7e7811b_926x156.png 424w, https://substackcdn.com/image/fetch/$s_!Dgag!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F124fe8a5-94de-4dfb-9258-7151a7e7811b_926x156.png 848w, https://substackcdn.com/image/fetch/$s_!Dgag!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F124fe8a5-94de-4dfb-9258-7151a7e7811b_926x156.png 1272w, https://substackcdn.com/image/fetch/$s_!Dgag!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F124fe8a5-94de-4dfb-9258-7151a7e7811b_926x156.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h2>4. Blinking Cursor</h2><p>Next we need to figure out how do we capture user input. We could add a <strong>TextField</strong> after the question mark. But I want to make it as close as the single line console display. I want to show a blinking underscore to tell the user that an input is expected after the question mark, just like in a console. The simplest approach is to append a <code>_</code> that blinks on and off. We can simulate a <strong>blinking cursor</strong> in SwiftUI 5 using a <strong>Timer</strong> with a simple toggle state. </p><pre><code>struct <strong>BlinkingCursorText</strong>: View {
    @State private var showCursor = true
    let text: String
    <strong>let timer = Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()</strong>
    
    init(_ content: String) {
        self.text = content
    }

    var body: some View {
        <strong>Text(text + (showCursor ? "_" : ""))</strong>
            .font(.system(size: 28, design: .monospaced))
            <strong>.onReceive(timer) { _ in
                showCursor.toggle()
            }</strong>
    }
}</code></pre><p>We can use this for only those <strong>displayText</strong> which are prompts. I added a helper field in <strong>GameState</strong> enum, because I know there are 3 more prompts coming later. </p><pre><code>struct HorseRaceView...
    var body...
        TrackView {
            <strong>if viewModel.state.isPrompt {
                BlinkingCursorText(viewModel.displayText)
            }</strong> else {
                Text(viewModel.displayText)
            }
        }

enum GameState...
    var <strong>isPrompt</strong>: Bool {
        switch self {
        case .promptNumPlayers: return true
        default : return false
        }
    }
}</code></pre><p>The <code>_</code> toggles every 0.5s, giving the classic blinking cursor effect. This works nicely with &#8220;console-style&#8221; layout without needing a real <strong>TextField</strong>.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!beLY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1dc3851-323b-4ba6-8522-433100ac7e0d_906x156.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!beLY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1dc3851-323b-4ba6-8522-433100ac7e0d_906x156.png 424w, https://substackcdn.com/image/fetch/$s_!beLY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1dc3851-323b-4ba6-8522-433100ac7e0d_906x156.png 848w, https://substackcdn.com/image/fetch/$s_!beLY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1dc3851-323b-4ba6-8522-433100ac7e0d_906x156.png 1272w, https://substackcdn.com/image/fetch/$s_!beLY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1dc3851-323b-4ba6-8522-433100ac7e0d_906x156.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!beLY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1dc3851-323b-4ba6-8522-433100ac7e0d_906x156.png" width="480" height="82.64900662251655" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e1dc3851-323b-4ba6-8522-433100ac7e0d_906x156.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:156,&quot;width&quot;:906,&quot;resizeWidth&quot;:480,&quot;bytes&quot;:17428,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/171816002?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1dc3851-323b-4ba6-8522-433100ac7e0d_906x156.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!beLY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1dc3851-323b-4ba6-8522-433100ac7e0d_906x156.png 424w, https://substackcdn.com/image/fetch/$s_!beLY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1dc3851-323b-4ba6-8522-433100ac7e0d_906x156.png 848w, https://substackcdn.com/image/fetch/$s_!beLY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1dc3851-323b-4ba6-8522-433100ac7e0d_906x156.png 1272w, https://substackcdn.com/image/fetch/$s_!beLY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1dc3851-323b-4ba6-8522-433100ac7e0d_906x156.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h2>5. Capturing User Input</h2><p>Next, we need to capture key presses from the users. We already have a way to capture user input of RETURN key. Instead of just that one key, we need to open it up for any key, and then have a <strong>Switch</strong> statement for the key pressed. So I created a <strong>handleKeyPress(:KeyPress)</strong> method in the view model. </p><pre><code>struct HorseRaceView...
    var body: some View {
        TrackView...
        .onKeyPress<strong>(action: viewModel.handleKeyPress)</strong>
    }

class HorseRaceViewModel...    
    func <strong>handleKeyPress</strong>(_ keyPress: KeyPress) -&gt; KeyPress.Result {
        <strong>switch keyPress.key.character</strong> {
        <strong>case "\r":</strong> moveToNextState()
        <strong>case let char:</strong> handleUserInput(char)
        }
        return .handled
    }</code></pre><p>The <strong>handleUserInput()</strong> method will need to store the input. I added a field <strong>userInput</strong> which will be used the track the input from the user. </p><pre><code>class HorseRaceViewModel...
    private var <strong>userInput</strong>: String = ""

    var displayText...
        case .promptNumPlayers: "How many players? \(<strong>userInput</strong>)"
    
    private func <strong>handleUserInput</strong>(_ char: Character) {
        guard state.isPrompt else { return }
        userInput.append(char)
    }</code></pre><p>Now we can see user input when I press &#8216;4&#8217; and &#8216;5&#8217;. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UQYo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f11b443-8287-447a-a23f-61e37e1a93ef_908x158.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UQYo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f11b443-8287-447a-a23f-61e37e1a93ef_908x158.png 424w, https://substackcdn.com/image/fetch/$s_!UQYo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f11b443-8287-447a-a23f-61e37e1a93ef_908x158.png 848w, https://substackcdn.com/image/fetch/$s_!UQYo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f11b443-8287-447a-a23f-61e37e1a93ef_908x158.png 1272w, https://substackcdn.com/image/fetch/$s_!UQYo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f11b443-8287-447a-a23f-61e37e1a93ef_908x158.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UQYo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f11b443-8287-447a-a23f-61e37e1a93ef_908x158.png" width="456" height="79.34801762114537" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2f11b443-8287-447a-a23f-61e37e1a93ef_908x158.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:158,&quot;width&quot;:908,&quot;resizeWidth&quot;:456,&quot;bytes&quot;:13844,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/171816002?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75ea57df-dc36-459e-943a-e7cb721605a3_908x158.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UQYo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f11b443-8287-447a-a23f-61e37e1a93ef_908x158.png 424w, https://substackcdn.com/image/fetch/$s_!UQYo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f11b443-8287-447a-a23f-61e37e1a93ef_908x158.png 848w, https://substackcdn.com/image/fetch/$s_!UQYo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f11b443-8287-447a-a23f-61e37e1a93ef_908x158.png 1272w, https://substackcdn.com/image/fetch/$s_!UQYo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f11b443-8287-447a-a23f-61e37e1a93ef_908x158.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>But what if user made a mistake and delete the input. Like here I want to delete &#8216;5&#8217;. We need to handle backspace. That&#8217;s just another case in <strong>handleKeyPress</strong>. </p><pre><code>class HorseRaceViewModel...
    func handleKeyPress(_ keyPress: KeyPress) -&gt; KeyPress.Result {
        switch keyPress.key.character {
        case Keys.returnKey: moveToNextState()
        <strong>case Keys.backspace, Keys.delete: handleBackspace()</strong>
        case let char: handleUserInput(char)
        }
        return .handled
    }

    private func <strong>handleBackspace</strong>() {
        guard state.isPrompt else { return }
        guard !userInput.isEmpty else { return }
        userInput.removeLast()
    }

enum Keys {
    static let returnKey: Character = "\r"
    static let backspace: Character = "\u{8}"
    static let delete: Character = "\u{7F}"
}</code></pre><p><strong>Keys</strong> is as an enum with no cases, it&#8217;s an <em>uninstantiable namespace</em>. This prevents someone from ever making a <strong>Keys()</strong> instance, which is nice when we only want constants.</p><h2>6. Instantiating Players</h2><p>Now after the user is satisfied with their input, they will press RETURN, which will call <strong>moveToNextState(). </strong>We need to read the <strong>userInput</strong>, convert it to Int, do validations, and create <strong>Players</strong>. </p><pre><code>class HorseRaceViewModel  {
    private var <strong>players</strong>:<strong> [Player] = []</strong>
    
    private func moveToNextState() {
        switch state {
        case .displayTitle: state = .displayHorses
        case .displayHorses: state = .promptNumPlayers
        <strong>case .promptNumPlayers:
            if addPlayers() {
                state = ... </strong>// <em>Move to next state</em> <strong>
            } 
        }</strong>
    }

    private func readInput() -&gt; String {
        let returnVal = userInput
        userInput = ""  <em>// Clear the input after reading</em>
        return returnVal
    }

    private func <strong>addPlayers() -&gt; Bool</strong> {
        guard let numPlayers = Int(readInput()) else { return false }
        guard numPlayers &gt;= GameConfig.minPlayers else { return false }
        guard numPlayers &lt;= GameConfig.maxPlayers else { return false }
        players.removeAll()
        for p in 1...numPlayers {
            players.append(Player(id: p))
        }
        return true
    }</code></pre><p>We are done with this step. We have laid some good groundwork for capturing and processing user input. This will help us in upcoming stages. I think they will go fast. </p><h2>7. Initial Player Holdings </h2><p>Next is displaying initial player holdings. </p><pre><code>extension FX790...
    private func displayInitialHoldings() {
        <strong>PRINT("ALL PLAYERS HAVE $\(GameConfig.startingMoney)")</strong>
        TIMER()
    }</code></pre><p>This requires just 4 lines of code change. </p><pre><code>enum GameState...
    <strong>case displayInitialHoldings</strong>

class HorseRaceViewModel...
    var displayText...
        <strong>case .displayInitialHoldings: 
            "All players have $\(GameConfig.startingMoney)"</strong>

    private func moveToNextState...
        case .promptNumPlayers:
            if addPlayers() {
                <strong>state = .displayInitialHoldings</strong>
            }</code></pre><p>This displays &#8212; </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hjgK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83eb661-9642-46b7-827b-57a3dcf05e36_902x156.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hjgK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83eb661-9642-46b7-827b-57a3dcf05e36_902x156.png 424w, https://substackcdn.com/image/fetch/$s_!hjgK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83eb661-9642-46b7-827b-57a3dcf05e36_902x156.png 848w, https://substackcdn.com/image/fetch/$s_!hjgK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83eb661-9642-46b7-827b-57a3dcf05e36_902x156.png 1272w, https://substackcdn.com/image/fetch/$s_!hjgK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83eb661-9642-46b7-827b-57a3dcf05e36_902x156.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hjgK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83eb661-9642-46b7-827b-57a3dcf05e36_902x156.png" width="472" height="81.63192904656319" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c83eb661-9642-46b7-827b-57a3dcf05e36_902x156.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:156,&quot;width&quot;:902,&quot;resizeWidth&quot;:472,&quot;bytes&quot;:18881,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/171816002?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83eb661-9642-46b7-827b-57a3dcf05e36_902x156.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hjgK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83eb661-9642-46b7-827b-57a3dcf05e36_902x156.png 424w, https://substackcdn.com/image/fetch/$s_!hjgK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83eb661-9642-46b7-827b-57a3dcf05e36_902x156.png 848w, https://substackcdn.com/image/fetch/$s_!hjgK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83eb661-9642-46b7-827b-57a3dcf05e36_902x156.png 1272w, https://substackcdn.com/image/fetch/$s_!hjgK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83eb661-9642-46b7-827b-57a3dcf05e36_902x156.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h2>8. Race Number</h2><p>Next we need to display the race number. </p><pre><code>    private func displayRaceNumber(_ R: Int) {
        PRINT()
        print("&lt;RACE \(R)&gt;")
        TIMER()
    }</code></pre><p>We add a new state and a new field to keep track of race numbers. This is the state we will come back to on replay. </p><pre><code>enum GameState...
    <strong>case displayRaceNumber</strong>

class HorseRaceViewModel...
    <strong>private var raceNumber: Int = 1</strong>
    
    var displayText...
        <strong>case .displayRaceNumber: "&lt;Race \(raceNumber)&gt;"</strong>
                
    private func moveToNextState...
        case .displayInitialHoldings:
            <strong>state = .displayRaceNumber</strong></code></pre><p>This displays &#8212;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!p58t!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452ab5dc-0622-499f-8dde-353b1ce66b82_896x154.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!p58t!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452ab5dc-0622-499f-8dde-353b1ce66b82_896x154.png 424w, https://substackcdn.com/image/fetch/$s_!p58t!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452ab5dc-0622-499f-8dde-353b1ce66b82_896x154.png 848w, https://substackcdn.com/image/fetch/$s_!p58t!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452ab5dc-0622-499f-8dde-353b1ce66b82_896x154.png 1272w, https://substackcdn.com/image/fetch/$s_!p58t!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452ab5dc-0622-499f-8dde-353b1ce66b82_896x154.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!p58t!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452ab5dc-0622-499f-8dde-353b1ce66b82_896x154.png" width="458" height="78.71875" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/452ab5dc-0622-499f-8dde-353b1ce66b82_896x154.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:154,&quot;width&quot;:896,&quot;resizeWidth&quot;:458,&quot;bytes&quot;:12925,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/171816002?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452ab5dc-0622-499f-8dde-353b1ce66b82_896x154.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!p58t!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452ab5dc-0622-499f-8dde-353b1ce66b82_896x154.png 424w, https://substackcdn.com/image/fetch/$s_!p58t!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452ab5dc-0622-499f-8dde-353b1ce66b82_896x154.png 848w, https://substackcdn.com/image/fetch/$s_!p58t!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452ab5dc-0622-499f-8dde-353b1ce66b82_896x154.png 1272w, https://substackcdn.com/image/fetch/$s_!p58t!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452ab5dc-0622-499f-8dde-353b1ce66b82_896x154.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h2>9. Individual Player holdings</h2><p>Next, we reset horses and players for a new race, and showing each individual player&#8217;s remaining money before they choose their horse and bet money on it. </p><pre><code>extension FX790...
    private func displayPlayerHoldings(_ player: Player) {
        PRINT()
        BEEP()
        <strong>PRINT("PLAYER \(player.id) HAS $\(player.money)")</strong>
        TIMER()
    }</code></pre><p>So we introduce a new state. </p><pre><code>enum GameState...
    <strong>case displayPlayerHoldings(Player)</strong></code></pre><p>We need the <strong>Player</strong> as the associative value to know which player to show the holdings for. Let&#8217;s implement this new state &#8212;</p><pre><code>class HorseRaceViewModel...
    var displayText...
        case .displayPlayerHoldings(let p): 
             <strong>"Player \(p.id) has $\(p.money)"</strong>
        }
    }

    private func moveToNextState...
        case .displayRaceNumber:
            <strong>resetForNewRace()</strong>
            <strong>if let player = players.first() {
                state = .displayPlayerHoldings(player)
            }
   </strong>     case .displayPlayerHoldings(let player):<strong>
            state = players.next(after: player)
                .map { .displayPlayerHoldings($0) }
                .orElse(</strong>...<strong>)     </strong>// move to next state


    private func <strong>resetForNewRace</strong>() {
        horses.forEach { $0.reset() }
        players.forEach { $0.reset() }
    }</code></pre><p>I implemented a couple of helpers <strong>first()</strong> and <strong>next(after:)</strong> on the player collection. This way I can loop through each player. In the BASIC code it had skipped the players who had $0 money. </p><pre><code>class Player...
    <strong>var isActive: Bool { self.money &gt; 0 || self.madeAnyBet }</strong>

extension Array where Element == Player...
    func <strong>first</strong>() -&gt; Player? {
        first(where: \.isActive)
    }
    
    func <strong>next</strong>(after player: Player) -&gt; Player? {
        guard let curr = firstIndex(of: player) else { return nil }
        return self[(curr + 1)...].first(where: \.isActive)
    }
}</code></pre><p>Now we can show each individual players holdings. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2uWz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec3dd8d-7708-4560-ad83-5e271b649b28_904x164.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2uWz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec3dd8d-7708-4560-ad83-5e271b649b28_904x164.png 424w, https://substackcdn.com/image/fetch/$s_!2uWz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec3dd8d-7708-4560-ad83-5e271b649b28_904x164.png 848w, https://substackcdn.com/image/fetch/$s_!2uWz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec3dd8d-7708-4560-ad83-5e271b649b28_904x164.png 1272w, https://substackcdn.com/image/fetch/$s_!2uWz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec3dd8d-7708-4560-ad83-5e271b649b28_904x164.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2uWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec3dd8d-7708-4560-ad83-5e271b649b28_904x164.png" width="440" height="79.82300884955752" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aec3dd8d-7708-4560-ad83-5e271b649b28_904x164.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:164,&quot;width&quot;:904,&quot;resizeWidth&quot;:440,&quot;bytes&quot;:17754,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/171816002?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec3dd8d-7708-4560-ad83-5e271b649b28_904x164.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2uWz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec3dd8d-7708-4560-ad83-5e271b649b28_904x164.png 424w, https://substackcdn.com/image/fetch/$s_!2uWz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec3dd8d-7708-4560-ad83-5e271b649b28_904x164.png 848w, https://substackcdn.com/image/fetch/$s_!2uWz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec3dd8d-7708-4560-ad83-5e271b649b28_904x164.png 1272w, https://substackcdn.com/image/fetch/$s_!2uWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec3dd8d-7708-4560-ad83-5e271b649b28_904x164.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h2>10. Horse Odds</h2><p>Next we need to show the odds of winning per horse, so the player can choose their horse. </p><pre><code>extension FX790...
    private func displayHorseOdds(_ horses: [Horse]) {
        PRINT()
        <strong>PRINT("RATE ")
        for horse in horses {
            PRINT(csr: (horse.id)*5, " \(horse.symbol) \(horse.odds)")
        }</strong>
        TIMER()
        BEEP()
    }</code></pre><p>We add the new state. </p><pre><code><code>enum GameState...
    case displayOdds(Player)</code></code></pre><p>We need the <strong>Player</strong> since we are looping through the player context. And we will pass this player to the next state. Next we implement this new state. </p><pre><code>class HorseRaceViewModel...
    var displayText...
        case .displayOdds: 
            <strong>"RATE \(horses.map(\.oddsLabel).joined(separator: " "))"</strong>
        }

extension Horse...
    var oddsLabel: String { "\(symbol) \(odds)" }</code></pre><p>And finally the moving to this state &#8211;</p><pre><code>class HorseRaceViewModel...
    private func moveToNextState...
        case .displayPlayerHoldings(let player):
            <strong>state = .displayOdds(player)
        case .displayOdds(let player):
            state = players.next(after: player)
                .map { .displayPlayerHoldings($0) }
                .orElse(...)     // move to next state</strong></code></pre><p>This will display the odds to the player &#8211;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!G8Xo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3602a861-1d6d-4ad3-9c4b-ffa401492f9f_888x156.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!G8Xo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3602a861-1d6d-4ad3-9c4b-ffa401492f9f_888x156.png 424w, https://substackcdn.com/image/fetch/$s_!G8Xo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3602a861-1d6d-4ad3-9c4b-ffa401492f9f_888x156.png 848w, https://substackcdn.com/image/fetch/$s_!G8Xo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3602a861-1d6d-4ad3-9c4b-ffa401492f9f_888x156.png 1272w, https://substackcdn.com/image/fetch/$s_!G8Xo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3602a861-1d6d-4ad3-9c4b-ffa401492f9f_888x156.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!G8Xo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3602a861-1d6d-4ad3-9c4b-ffa401492f9f_888x156.png" width="484" height="85.02702702702703" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3602a861-1d6d-4ad3-9c4b-ffa401492f9f_888x156.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:156,&quot;width&quot;:888,&quot;resizeWidth&quot;:484,&quot;bytes&quot;:17105,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/171816002?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3602a861-1d6d-4ad3-9c4b-ffa401492f9f_888x156.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!G8Xo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3602a861-1d6d-4ad3-9c4b-ffa401492f9f_888x156.png 424w, https://substackcdn.com/image/fetch/$s_!G8Xo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3602a861-1d6d-4ad3-9c4b-ffa401492f9f_888x156.png 848w, https://substackcdn.com/image/fetch/$s_!G8Xo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3602a861-1d6d-4ad3-9c4b-ffa401492f9f_888x156.png 1272w, https://substackcdn.com/image/fetch/$s_!G8Xo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3602a861-1d6d-4ad3-9c4b-ffa401492f9f_888x156.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h2>End of Part 2</h2><p>We have come have about half way in our SwiftUI implementation of this game. Lets pause here for a minute and see how the game is shaping up. We can see that this <strong>moveToNextState</strong> is turning out to be orchestrator of this whole game. The logic here is matching the original game. It is the core game flow driver. </p><pre><code>class HorseRaceViewModel...
    private func moveToNextState() {
        switch state {
        case .displayTitle: state = .describeHorses
        case .describeHorses: state = .promptNumPlayers
        case .promptNumPlayers:
            if addPlayers() {
                state = .displayInitialHoldings
            }
        case .displayInitialHoldings:
            resetForNewRace()
            state = .displayRaceNumber
        case .displayRaceNumber:
            if let player = players.first() {
                state = .displayPlayerHoldings(player)
            }
        case .displayPlayerHoldings(let player):
            state = .displayOdds(player)
        case .displayOdds(let player):
            state = players.next(after: player)
                .map { .displayPlayerHoldings($0) }
                .orElse(.displayTitle)
        }
    }</code></pre><p>Games have different architecture traditions than MVVM. A very common one is <strong>Finite State Machine (FSM)</strong>. This is exactly what this method doing now. Each game state (e.g. displayTitle, describeHorses, promptNumPlayers, etc.) has logic for transitions which is often implemented with enums and switch statements (like we have), or as a <strong>State pattern</strong>, which is the <strong>OO version of FSM, </strong>where each state has its own object/class with enter(), update(), exit() methods. Small/indie games often use FSM (like we&#8217;re doing). Bigger games use OO State Pattern or Entity-Component-System (ECS). ECS is popular in larger games (Unity, Bevy, etc.), where logic is separated into <strong>components</strong> (data, like Health or Position) and <strong>systems</strong> (logic, like MovementSystem or RenderSystem). ECS is more complex but very scalable for simulation-heavy games.</p><p>We will continue the rest of the game development in <a href="https://www.codingpapa.net/p/horse-race-game-part-3">Part 3</a>. There we will also see if we should refactor <strong>moveToNextState </strong>to a FSM. </p><h2></h2><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Horse Race Game, Part 1]]></title><description><![CDATA[My first programming computer had a single line display and 8KB of memory. I converted an old 100-line game in BASIC to Swift to see how far we&#8217;ve come. This was a fun journey though nostalgia.]]></description><link>https://www.codingpapa.net/p/horse-race-game-part-1</link><guid isPermaLink="false">https://www.codingpapa.net/p/horse-race-game-part-1</guid><dc:creator><![CDATA[Rohit]]></dc:creator><pubDate>Tue, 19 Aug 2025 04:11:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!2vRL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4faf1d2d-e35b-4a90-ac4b-02eca383f59c_1600x1069.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2vRL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4faf1d2d-e35b-4a90-ac4b-02eca383f59c_1600x1069.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2vRL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4faf1d2d-e35b-4a90-ac4b-02eca383f59c_1600x1069.jpeg 424w, https://substackcdn.com/image/fetch/$s_!2vRL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4faf1d2d-e35b-4a90-ac4b-02eca383f59c_1600x1069.jpeg 848w, https://substackcdn.com/image/fetch/$s_!2vRL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4faf1d2d-e35b-4a90-ac4b-02eca383f59c_1600x1069.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!2vRL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4faf1d2d-e35b-4a90-ac4b-02eca383f59c_1600x1069.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2vRL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4faf1d2d-e35b-4a90-ac4b-02eca383f59c_1600x1069.jpeg" width="1456" height="973" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4faf1d2d-e35b-4a90-ac4b-02eca383f59c_1600x1069.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:973,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1052096,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/170306009?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4faf1d2d-e35b-4a90-ac4b-02eca383f59c_1600x1069.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2vRL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4faf1d2d-e35b-4a90-ac4b-02eca383f59c_1600x1069.jpeg 424w, https://substackcdn.com/image/fetch/$s_!2vRL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4faf1d2d-e35b-4a90-ac4b-02eca383f59c_1600x1069.jpeg 848w, https://substackcdn.com/image/fetch/$s_!2vRL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4faf1d2d-e35b-4a90-ac4b-02eca383f59c_1600x1069.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!2vRL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4faf1d2d-e35b-4a90-ac4b-02eca383f59c_1600x1069.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The <strong><a href="https://www.rskey.org/fx790p">Casio FX-790P</a></strong> was my first computer where I learned programming back in the 90s. It was a blend between a scientific calculator and a BASIC-programmable handheld computer. It featured a single line, 24-character LCD display, 83 keys, and 8KB of internal memory. It had scientific functions, the ability to calculate square roots, and it ran on a BASIC interpreter, allowing for the storage and execution of up to 10 programs!</p><p>This device came with pretty great <a href="http://pocketcomputerworld.free.fr/Manuals/FX-785P-790P.pdf">owner&#8217;s manual</a>, which had an extensive chapter on BASIC programing language. I wrote so many programs on this, mostly simple 10-50 lines long. The owner&#8217;s manual had two sample programs&#8212; Bubble Sort and a Horse Race Game. The game was by far the largest, most complex program I had ever seen. It was 102 lines long and took 1.3KB of memory. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!30nt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd02ffd56-09aa-4417-a6e9-52e5ff1b7bfa_1600x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!30nt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd02ffd56-09aa-4417-a6e9-52e5ff1b7bfa_1600x800.png 424w, https://substackcdn.com/image/fetch/$s_!30nt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd02ffd56-09aa-4417-a6e9-52e5ff1b7bfa_1600x800.png 848w, https://substackcdn.com/image/fetch/$s_!30nt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd02ffd56-09aa-4417-a6e9-52e5ff1b7bfa_1600x800.png 1272w, https://substackcdn.com/image/fetch/$s_!30nt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd02ffd56-09aa-4417-a6e9-52e5ff1b7bfa_1600x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!30nt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd02ffd56-09aa-4417-a6e9-52e5ff1b7bfa_1600x800.png" width="1456" height="728" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d02ffd56-09aa-4417-a6e9-52e5ff1b7bfa_1600x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:728,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:326940,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/170306009?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd02ffd56-09aa-4417-a6e9-52e5ff1b7bfa_1600x800.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!30nt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd02ffd56-09aa-4417-a6e9-52e5ff1b7bfa_1600x800.png 424w, https://substackcdn.com/image/fetch/$s_!30nt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd02ffd56-09aa-4417-a6e9-52e5ff1b7bfa_1600x800.png 848w, https://substackcdn.com/image/fetch/$s_!30nt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd02ffd56-09aa-4417-a6e9-52e5ff1b7bfa_1600x800.png 1272w, https://substackcdn.com/image/fetch/$s_!30nt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd02ffd56-09aa-4417-a6e9-52e5ff1b7bfa_1600x800.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>That&#8217;s some unreadable code! I just typed this in blindly and hoped that I didn&#8217;t make any typos, without really understanding the logic. So for nostalgic reasons, I thought I would convert this program to Swift, and see how a modern programing language compares to this old BASIC code. Can it be done in less than 100 lines? I will start with a line-by-line mirroring of the original code. Then I will refactor to see if I can make it readable. </p><h2>Step 1: Convert to Swift</h2><p>Before I can convert this code, it has some commands that I would like to use as-is to preserve the original code. So I wrote a protocol for them. I don&#8217;t want to implement these methods, so <strong>protocol</strong> gives me a nice way to defer the implementation. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VZ4z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5316faca-45a7-4897-a915-463eb30a5c09_1360x544.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VZ4z!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5316faca-45a7-4897-a915-463eb30a5c09_1360x544.png 424w, https://substackcdn.com/image/fetch/$s_!VZ4z!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5316faca-45a7-4897-a915-463eb30a5c09_1360x544.png 848w, https://substackcdn.com/image/fetch/$s_!VZ4z!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5316faca-45a7-4897-a915-463eb30a5c09_1360x544.png 1272w, https://substackcdn.com/image/fetch/$s_!VZ4z!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5316faca-45a7-4897-a915-463eb30a5c09_1360x544.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VZ4z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5316faca-45a7-4897-a915-463eb30a5c09_1360x544.png" width="1360" height="544" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5316faca-45a7-4897-a915-463eb30a5c09_1360x544.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:544,&quot;width&quot;:1360,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:106489,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/170306009?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5316faca-45a7-4897-a915-463eb30a5c09_1360x544.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VZ4z!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5316faca-45a7-4897-a915-463eb30a5c09_1360x544.png 424w, https://substackcdn.com/image/fetch/$s_!VZ4z!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5316faca-45a7-4897-a915-463eb30a5c09_1360x544.png 848w, https://substackcdn.com/image/fetch/$s_!VZ4z!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5316faca-45a7-4897-a915-463eb30a5c09_1360x544.png 1272w, https://substackcdn.com/image/fetch/$s_!VZ4z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5316faca-45a7-4897-a915-463eb30a5c09_1360x544.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Now I convert the whole program, line by line, keeping even the variable names same. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uEtE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83fdf50-38cd-4e31-b138-88cd7e67dde8_1389x5052.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uEtE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83fdf50-38cd-4e31-b138-88cd7e67dde8_1389x5052.png 424w, https://substackcdn.com/image/fetch/$s_!uEtE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83fdf50-38cd-4e31-b138-88cd7e67dde8_1389x5052.png 848w, https://substackcdn.com/image/fetch/$s_!uEtE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83fdf50-38cd-4e31-b138-88cd7e67dde8_1389x5052.png 1272w, https://substackcdn.com/image/fetch/$s_!uEtE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83fdf50-38cd-4e31-b138-88cd7e67dde8_1389x5052.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uEtE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83fdf50-38cd-4e31-b138-88cd7e67dde8_1389x5052.png" width="1389" height="5052" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c83fdf50-38cd-4e31-b138-88cd7e67dde8_1389x5052.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:5052,&quot;width&quot;:1389,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:840646,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/170306009?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83fdf50-38cd-4e31-b138-88cd7e67dde8_1389x5052.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uEtE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83fdf50-38cd-4e31-b138-88cd7e67dde8_1389x5052.png 424w, https://substackcdn.com/image/fetch/$s_!uEtE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83fdf50-38cd-4e31-b138-88cd7e67dde8_1389x5052.png 848w, https://substackcdn.com/image/fetch/$s_!uEtE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83fdf50-38cd-4e31-b138-88cd7e67dde8_1389x5052.png 1272w, https://substackcdn.com/image/fetch/$s_!uEtE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83fdf50-38cd-4e31-b138-88cd7e67dde8_1389x5052.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This is 138 lines, not quite 102. However, the BASIC program had multiple statements on single line. I counted them and it too came out to be 138 lines! </p><p>Time to refactor. </p><h2>Step 2: Arrays to Classes</h2><p>Notice the following 2D arrays - </p><pre><code>var A: [[Double]] = DIM(3, 4)
var X : [[Int]] = DIM(2, P) </code></pre><p>&#8220;A&#8221; represent Horses, and &#8220;X&#8221; represent Players. The rows are the properties, and the column represent the instance. </p><pre><code>A[1][j] = Position of the horse j
A[2][j] = Random number of the horse j
A[3][j] = Odds on the horse j

X[1][j] = Bet amount for player j
X[2][j] = Money remaining for player j</code></pre><p>This is very interesting. This shows that even before Object Oriented languages, there was a need for <em>grouping of data </em>under a single variable. But since there were no classes or structs in BASIC, people used 2D arrays. Today we can convert them to proper classes. Lets start with <strong>Horse</strong>.  </p><pre><code>class Horse {
    var position: Int = 0
    var randomizer: Double = 0.0
    var odds: Int = 0
}</code></pre><p>When we use the <strong>Horse</strong> class, this becomes, </p><pre><code>func horseRaceGame()...
    var horses: [Horse] = Array(repeating: Horse(), count: 4)
    ...
    for horse in horses {
        horse.position = 0
        horse.randomizer = Double.random(in: 0...1)
        horse.odds = 1 + Int(pow(10.0, 1.2 - horse.randomizer))
    }</code></pre><p>I can create an <strong>initialize()</strong> method in Horse, and move this code in there. </p><pre><code>class Horse...
    func initialize() {
        self.position = 0
        self.randomizer = Double.random(in: 0...1)
        self.odds = 1 + Int(pow(10.0, 1.2 - self.randomizer))
    }

func horseRaceGame()...
    horses.forEach { $0.initialize() }</code></pre><p>Next I create the <strong>Player</strong> class. </p><pre><code>class Player {
    var money: Int
    var bet: Int = 0
    var chosenHorse: String = ""
    
    init(startingMoney: Int = 20) {
        self.money = startingMoney
    }
    
    func initialize() {
        self.bet = 0
        self.chosenHorse = ""
    }
}</code></pre><p>There was an array <strong>Y$[j] </strong>that was tracking the chosen horse for the player j. I don&#8217;t know why the original program didn&#8217;t make it as <strong>X[3][j]</strong>, since its part of the player data. I moved it with Player. Now I can use this class in the code, replacing all X and Y variables. </p><pre><code>func horseRaceGame()...
    var players = Array(repeating: Player(), count: P)
    ...
    // bet money
    for (j, player) in players.enumerated() {
        ...
        <strong>player.initialize()</strong>
        if <strong>player.money</strong> == 0 { continue }
        PRINT("PLAYER \(j) HAS $\(<strong>player.money</strong>)")
        ...
        <strong>player.chosenHorse</strong> = S$[A$-1] 
        repeat {
            ...
            <strong>player.bet</strong> = INPUT("PLAYER\(j) \(<strong>player.chosenHorse</strong>) MONEY")
        } while <strong>player.money</strong> &lt; <strong>player.bet</strong>
        <strong>player.money</strong> = <strong>player.money</strong> - <strong>player.bet</strong>
    }   </code></pre><h2>Step 3: Horse Symbols</h2><p>Next, I want to move the horse symbols within the Horse class. </p><pre><code>let S$ = ["&#9824;", "&#9829;", "&#9830;", "&#9827;"]</code></pre><p>This could be an enum, but for now let&#8217;s just make it a string field of the class. </p><pre><code>class Horse {
    var position: Int = 0
    var randomizer: Double = 0.0
    var odds: Int = 0
    <strong>var symbol: String</strong>
    
    init(with symbol: String) {
        self.symbol = symbol
    }
}</code></pre><p>The <strong>initialize()</strong> method is separate from <strong>init()</strong> because it will be called again and again on replays. But the symbol of the horse will remain the same.  I plan to change its name later to something like &#8220;newRace()&#8221; or &#8220;reset()&#8221;. </p><p>The code changes to: </p><pre><code>func horseRaceGame()...
    var horses: [Horse] = []
    for symbol in ["&#9824;", "&#9829;", "&#9830;", "&#9827;"] {
        horses.append(<strong>Horse(with: symbol)</strong>)
    }</code></pre><p>And the rest of the code where we were using <strong>S$[j]</strong>, we just use <strong>horses[j].symbol</strong>. But even better, I can remove all index j references. </p><pre><code>// Before
    for j in 1...4 {
        if Int(horses[j-1].position) == 23 {
            H = horses[j-1].odds
            A$ = horses[j-1].symbol
        }
    }

// After
    for horse in horses {
        if Int(horse.position) == 23 {
            H = horse.odds
            A$ = horse.symbol
        }
    }</code></pre><p>This, I believe, is another strength of classes over arrays. It reduces the amount of times we have to use the indices, which results in reduced bugs due to <em>off-by-one</em> errors.  </p><h2>Step 4: Horse reference in Player</h2><p>There are few things I want to move to the player class. First I want to change the chosenHorse in player from String to actual Horse instance. </p><pre><code>class Player...
    var chosenHorse: Horse?</code></pre><p>Its optional because there a state when a player hasn&#8217;t made a choice of a horse. Also a player can choose to sit out a race, in which case <strong>chosenHorse</strong> will be <strong>nil</strong>. Now, anywhere we have,</p><pre><code>player.chosenHorse</code></pre><p>We can replace with,</p><pre><code>player.chosenHorse?.symbol</code></pre><h2>Step 5: Player helper methods</h2><p>Next, I want to create some encapsulations around player data of <strong>money</strong> and <strong>bet</strong>, so that I can make them private to player. I want to apply the principle of <em>Tell Don&#8217;t Ask,</em> so that the <strong>horseRaceGame</strong> doesn&#8217;t need to read or assign the money or bet data. </p><pre><code>class Player...
    <strong>private</strong> var money: Int
    <strong>private</strong> var bet: Int = 0</code></pre><p>That gave me a total of 13 errors. So I am going to work on fixing each of them one by one, until I am left with ones that cannot be fixed. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!o2JI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbba6983-936b-43b9-9332-4c6e1cf41143_540x1098.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!o2JI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbba6983-936b-43b9-9332-4c6e1cf41143_540x1098.png 424w, https://substackcdn.com/image/fetch/$s_!o2JI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbba6983-936b-43b9-9332-4c6e1cf41143_540x1098.png 848w, https://substackcdn.com/image/fetch/$s_!o2JI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbba6983-936b-43b9-9332-4c6e1cf41143_540x1098.png 1272w, https://substackcdn.com/image/fetch/$s_!o2JI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbba6983-936b-43b9-9332-4c6e1cf41143_540x1098.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!o2JI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbba6983-936b-43b9-9332-4c6e1cf41143_540x1098.png" width="260" height="528.6666666666666" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bbba6983-936b-43b9-9332-4c6e1cf41143_540x1098.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1098,&quot;width&quot;:540,&quot;resizeWidth&quot;:260,&quot;bytes&quot;:231167,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/170306009?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbba6983-936b-43b9-9332-4c6e1cf41143_540x1098.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!o2JI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbba6983-936b-43b9-9332-4c6e1cf41143_540x1098.png 424w, https://substackcdn.com/image/fetch/$s_!o2JI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbba6983-936b-43b9-9332-4c6e1cf41143_540x1098.png 848w, https://substackcdn.com/image/fetch/$s_!o2JI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbba6983-936b-43b9-9332-4c6e1cf41143_540x1098.png 1272w, https://substackcdn.com/image/fetch/$s_!o2JI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbba6983-936b-43b9-9332-4c6e1cf41143_540x1098.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>First, is the &#8220;<strong>if player.money == 0&#8221; </strong>check that is done in two place. I created a <strong>isBroke() </strong>method. </p><pre><code>class Player...
    func isBroke() -&gt; Bool {
        self.money == 0
    }</code></pre><p>We are down to 11 errors. Next is the betting loop. </p><pre><code>betting loop...
    repeat {
        <strong>player.bet</strong> = INPUT("PLAYER \(j) ... MONEY ")
    } while <strong>player.money &lt; player.bet</strong>
    <strong>player.money = player.money - player.bet</strong></code></pre><p>We can simplify this with: </p><pre><code>class Player...
    func <strong>placeBet</strong>(_ bet: Int) -&gt; Bool {
        guard bet &lt;= money else { return false }
        self.bet = bet
        self.money -= bet
        return true
    }
}

betting loop...
    var bet: Int
    repeat {
        bet = INPUT("PLAYER \(j) ... MONEY ")
    } while <strong>!player.placeBet(bet)</strong></code></pre><p>This cleaned up 6 more issues! Plus I think this better since before the bet was assigned to player and then the check for <strong>&#8220;money &gt; bet&#8221;</strong> was done. Now we only assign the bet and money after everything checks out. </p><p>Next is the winnings calculations loop. </p><pre><code>winning calculation...
    var M = 0 // money won
    if <strong>player.bet &gt; 0</strong> { // if player made any bets
        if player.chosenHorse?.symbol == A$ {
            M = <strong>player.bet * H</strong>
        }
        PRINT("PLAYER \(j+1) -&gt;PRIZE $\(M)")
    }
    <strong>player.money += M</strong></code></pre><p>This is another great spot to push responsibility into the <strong>Player</strong> class. Right now the outside code is &#8220;reaching in&#8221; to check bets, horses, and money &#8212; which makes it harder to change the logic later. We can simplify this as: </p><pre><code>winning calculation...
    if <strong>player.madeAnyBet()</strong> {
        var M = <strong>player.collectPrize(if: winningHorse)</strong>
        PRINT("PLAYER \(j+1) -&gt;PRIZE $\(M)")
    }</code></pre><p>This requires couple methods in Player. </p><pre><code>class Player...    
    func <strong>madeAnyBet()</strong> -&gt; Bool {
        self.bet &gt; 0
    }

    func <strong>collectPrize</strong>(if winningHorse: Horse) -&gt; Int {
        guard
            let myhorse = self.chosenHorse,
            myhorse.<strong>equals</strong>(winningHorse)
        else {
            return 0
        }
        
        let prize = myhorse.<strong>calculatePrize</strong>(for: self.bet)
        self.money += prize
        return prize
    }
}</code></pre><p>Here we are chaining the guard conditions with a comma. In Swift, commas inside a guard mean &#8220;all of these must hold&#8221;. Also notice that we created two methods on <strong>Horse</strong> class as well - <strong>equals</strong> and <strong>calculatePrize</strong>. </p><pre><code>class Horse...
    func <strong>equals</strong>(_ other: Horse) -&gt; Bool {
        self.symbol == other.symbol
    }
    
    func <strong>calculatePrize</strong>(for bet: Int) -&gt; Int {
        self.odds * bet
    }
}</code></pre><p>We no longer need H, since the odds of the winning horse is obtained by the players chosen horse, if its the winner. So we can further simplify this code: </p><pre><code>winning calculation...
    var H = 0 // odds on winning horse
    var A$ = "" // winning horse
    for horse in horses {
        if Int(horse.position) == 23 {
            H = horse.odds
            A$ = horse.symbol
        }
    }</code></pre><p>We can make this just one liner. </p><pre><code>let winningHorse = horses.<strong>last</strong> { $0.position == 23 }!</code></pre><p>Better, I can make this a computed property for <strong>horses</strong>. in the We can add an extension on <strong>Array</strong> constrained to <strong>Horse</strong> like this:</p><pre><code>extension Array where Element == Horse {
    var winningHorse: Horse? {
        <strong>last { $0.position == 23 }</strong>
    }
}

winning calculation...
    if player.madeAnyBet() {
        var M = player.collectPrize(if: <strong>horses.winningHorse!</strong>)
        PRINT("PLAYER \(j+1) -&gt;PRIZE $\(M)")
    }</code></pre><p>Notice I am using &#8216;last&#8217; since that is what the above for loop would have given. Now we are down to just 2 errors. Both for the exact print statements. </p><pre><code>PRINT("PLAYER \(j+1) HAS $\(<strong>player.money</strong>)")</code></pre><p>I am not ready to tackle print statements. So let me just create a <strong>remainingMoney</strong>() method on Player. </p><pre><code>class Player...
    func remainingMoney() -&gt; Int {
        self.money
    }</code></pre><p>All errors gone! I can also quickly make <strong>chosenHorse</strong> as private as well. </p><pre><code>class Player...
    <strong>private</strong> var chosenHorse: Horse?</code></pre><p>This results in 2 errors. Both when a player chooses a horse:</p><pre><code>choose horse...
    <strong>player.chosenHorse</strong> = horses[A$-1] 
    bet = INPUT("PLAYER\(j) \(<strong>player.chosenHorse?.symbol</strong>) MONEY")</code></pre><p>I can create a <strong>choose()</strong> method in Player. And for the second, I can just use the local <strong>horses[A$-1]. </strong></p><pre><code>class Player...
    func <strong>choose</strong>(horse: Horse) {
        self.chosenHorse = horse
    }

choose horse...
    player.<strong>choose</strong>(horse: horses[A$-1])
    bet = INPUT("PLAYER \(j) \(<strong>horses[A$-1].symbol</strong>) MONEY ")</code></pre><h2>Step 6: Horse helper methods</h2><p>Lets do the same exercise with Horse. We will try to make each of its property as private, starting with <strong>randomizer</strong>.</p><pre><code>class Horse {
    var position: Int = 0
    <strong>private</strong> var randomizer: Double = 0.0
    var odds: Int = 0
    var symbol: String</code></pre><p>Only 1 error. </p><pre><code>if Double.random(in: 0...1) * (0.9 + <strong>horse.randomizer</strong> / 10.0) &gt; 0.7 {
    horse.position += 1
}</code></pre><p>We can extract this to a <strong>move()</strong> method in <strong>Horse</strong>. </p><pre><code>class Horse...
    func <strong>move()</strong> {
        if Double.random(in: 0...1) * (0.9 + randomizer / 10.0) &gt; 0.7 {
            self.position += 1
        }
    }
}</code></pre><p>Next we tackle this winning condition which is used in couple of places:</p><pre><code>horse.position == 23</code></pre><p>Which can be made a method. </p><pre><code>class Horse...
    func <strong>reachedGoal()</strong> -&gt; Bool {
        self.position == 23
    }
}</code></pre><p>Next, there is this weird logic of moving horses - </p><pre><code>main loop...
    var G = 0
    repeat {
        for horse in horses {
            // As soon as somebody wins we stop moving horses
            if G &lt; 1 {
                PRINT(csr: Int(horse.position), " ")
                horse.move()
            }
            if horse.reachedGoal() {
                G += 1
            }
            PRINT(csr: horse.position, "\(horse.symbol)")
        }
    } while G &lt; 2</code></pre><p>Here, G is the winners count. This loop can be made much cleaner by getting rid of the manual G counter and instead asking the collection how many horses have finished. We don&#8217;t need to manually increment and check G, since we can calculate it each round. Secondly, in the original logic, as soon as one horse reaches the goal, the others stop moving. That means <em>only one horse ever actually finishes</em>, so G will never reach 2. The original BASIC trick was: Keep looping until <strong>the first horse finishes</strong>, then stop moving horses but still <strong>draw all horses</strong> once more, then exit after every horse has been drawn in that final round. However, the redraw was at the exact same position. The equivalent Swift can be written much more directly, like this:</p><pre><code>var noWinner = true
repeat {
    for horse in horses {
        if noWinner {
            PRINT(csr: Int(horse.position), " ")
            horse.move()
        }
        if horse.reachedGoal() {
            noWinner = false
        }
        PRINT(csr: horse.position, "\(horse.symbol)")
    }
} while noWinner</code></pre><p>Now it reads almost like English: <em>while there is no winner</em> &#8594; move horses, <em>once a winner appears</em> &#8594; stop moving, but still finish drawing. We can make <strong>noWinner</strong> derived from the horses array instead of mutating a flag variable. We add another property to the extension on <strong>Array</strong> for <strong>Horse</strong> like this:</p><pre><code>extension Array where Element == Horse {
    var winningHorse: Horse? {
        last { $0.<strong>reachedGoal()</strong> }
    }
    
    var <strong>hasNoWinner</strong>: Bool {
        <strong>winningHorse == nil</strong>
    }
}</code></pre><p>Then the loop looks even cleaner:</p><pre><code>repeat {
    for horse in horses {
        if horses.<strong>hasNoWinner</strong> {
            PRINT(csr: Int(horse.position), " ")
            horse.move()
        }
        PRINT(csr: horse.position, "\(horse.symbol)")
    }
} while horses.<strong>hasNoWinner</strong></code></pre><h2>Step 7: Fixing Replay</h2><p>When converting the program to Swift I had intentionally made wrong implementation of the replay logic. In the BASIC code, it had a GOTO statement, which took the program, not to the very top, but to the middle after all the horses and players were created. This preserved the remaining money of the players, while re-setting everything else (horse position, odds, player bets, etc.). But in Swift, since its a one long method, and there is no GOTO in Swift, I just recalled the <strong>horseRaceGame() </strong>from the top. That will reset the race number back to 1 and player money back to $20. </p><pre><code>replay...
    var F = 0 // Num players with 0 money
    if player.isBroke() { F += 1 }
    if F &lt; P {
        repeat {
            var A$: String = INPUT("REPLAY (Y/N)?")
            if A$ == "Y" {
                R += 1
                <strong>horseRaceGame()</strong> // GOTO Initialize
            }
            if A$ == "N" { break }
        } while true
    }
    PRINT()
    PRINT("GAME OVER")</code></pre><p>The way to fix this is to break the single method into two methods &#8212; the top part with horses and players initialization, and the race part with odds and bets. Later we will break into even smaller methods, but for now lets start with two. </p><pre><code>func horseRaceGame() {
    <s>var R = 1</s>
    ...
    <strong>race(num: 1, horses: horses, players: players)
</strong>}

private func <strong>race</strong>(num R: Int, horses: [Horse], players: [Player]) {
    ...
    if F &lt; <strong>players.count</strong> { 
        repeat {
            var A$: String = INPUT("REPLAY (Y/N)?")
            if A$ == "Y" {
                <strong>race(num: R+1, horses: horses, players: players)</strong> 
            }
            if A$ == "N" { break }
        } while true
    }
    PRINT()
    PRINT("GAME OVER")
}</code></pre><p>We don&#8217;t need number of players, P, variable anymore. I also want to get rid of F, which is the number of players who have $0. That was to test the game-end scenario. I created a <strong>remaining</strong> property on <strong>Players</strong> array.  </p><pre><code>extension Array where Element == Player {
    var <strong>remaining</strong>: Int {
        count { !$0.isBroke() }
    }
}</code></pre><p>I can also separate the prompt and the replay and keep the loop only responsible for validating input, separating <strong>input phase</strong> from <strong>action phase</strong>.</p><pre><code>replay...
    var replay = false
    if <strong>players.remaining</strong> &gt; 0 {
        repeat {
            let ans: String = INPUT("REPLAY (Y/N)?")
            if ans == "Y" { replay = true; break }
            if ans == "N" { break }
        } while true
    }

    if replay {
        race(num: R+1, horses: horses, players: players)
    } else {
        PRINT()
        PRINT("GAME OVER")
    }</code></pre><p>I plan to move all prompts to their own helper methods later, so this code will further clean up. Last thing I want to do in this step is rename the <strong>initialize()</strong> methods on Player and Horse to <strong>reset()</strong>, which communicates better that we are resetting for a new race. </p><pre><code>class Horse...
    func <strong>reset()</strong> {
        self.position = 0
        self.randomizer = Double.random(in: 0...1)
        self.odds = 1 + Int(pow(10.0, 1.2 - self.randomizer))
    }

class Player...
    func <strong>reset()</strong> {
        self.bet = 0
        self.chosenHorse = nil
    }</code></pre><h2>Step 8: Player and Horse IDs</h2><p>One thing I noticed that in 4 loops we are still using indices. </p><pre><code>func horseRaceGame...
    <strong>for (j, horse)</strong> in horses.enumerated() {
        PRINT(" \<strong>(j+1)</strong>\(horse.symbol)")
    }

func race... 
    <strong>for (j, player)</strong> in players.enumerated() {
        PRINT("PLAYER \<strong>(j+1)</strong> HAS $\(player.remainingMoney())")
        ...
        <strong>for (k, horse)</strong> in horses.enumerated() {
            PRINT(csr: <strong>(k+1)</strong>*5, " \(horse.symbol) \(horse.odds)")
        }
        ...
        var A$ = 0
        repeat {
            A$ = INPUT("P \<strong>(player.id)</strong>-&gt;")
        } while A$ &lt; 0 || A$ &gt; 4 
        ...
        var bet: Int
        repeat {
            bet = INPUT("PLAYER \<strong>(j+1)</strong> \(horses[A$-1].symbol) MONEY ")
        } while !player.placeBet(bet)
    }
    ...
    <strong>for (j, player)</strong> in players.enumerated() {
        if player.madeAnyBet() {
            PRINT("PLAYER \<strong>(j+1)</strong> -&gt;PRIZE $\(M)")
        }
        PRINT("PLAYER \<strong>(j+1)</strong> HAS $\(player.remainingMoney())")
    }</code></pre><p>I actually had bugs where I just put <strong>j</strong>, and not <strong>j+1</strong>. So these indices really do cause <em>off-by-one</em> errors. Let&#8217;s add an <strong>Id</strong> property to <strong>Horse</strong> and <strong>Player</strong>. </p><pre><code>class Horse...
    <strong>private(set) var id: Int</strong>
    
    init(<strong>id: Int</strong>, symbol: String) {
        self.id = id
        self.symbol = symbol
    }

class Player...
    <strong>private(set) var id: Int</strong>
    
    init(<strong>id: Int</strong>, startingMoney: Int = 20) {
        self.id = id
        self.money = startingMoney
    }</code></pre><p>And the construction is only place we need the index. </p><pre><code>func horseRaceGame...
    var horses: [Horse] = []
    for (j, symbol) in ["&#9824;", "&#9829;", "&#9830;", "&#9827;"].enumerated() {
        horses.append(Horse(<strong>id: j+1</strong>, symbol: symbol))
    }

    var players: [Player] = []
    for p in 1...P {
        players.append(Player(<strong>id: p</strong>))
    }</code></pre><p>Now we don&#8217;t need indices everywhere and the rest of the code is simplified with no off-by-one bugs. </p><pre><code>PRINT(" \(<strong>horse.id</strong>)\(horse.symbol)")
PRINT("PLAYER \(<strong>player.id</strong>) HAS $\(player.money)")
PRINT(csr: (<strong>horse.id</strong>)*5, " \(horse.symbol) \(horse.odds)")
INPUT("P \(<strong>player.id</strong>)-&gt;")
INPUT("PLAYER \(<strong>player.id</strong>) \(horses[A$-1].symbol) MONEY ")
PRINT("PLAYER \(<strong>player.id</strong>) -&gt;PRIZE $\(M)")
PRINT("PLAYER \(<strong>player.id</strong>) HAS $\(player.remainingMoney())")</code></pre><h2>Step 9: Magic numbers</h2><p>We have a lot of magic numbers through out the game that we can collect in one place under a struct <strong>GameConfig</strong>. </p><pre><code>struct GameConfig {
    static let minPlayers = 1
    static let maxPlayers = 5
    static let goalPosition = 23
    static let startingMoney = 20
}</code></pre><p>Then there are numbers which are used in calculating odds on a horse and how fast they move. These numbers are buried assumptions in our game logic. Lets look at them separately. First the odds &#8212;</p><pre><code>class Horse.reset()... 
    self.randomizer = Double.random(in: 0...1)
    self.odds = 1 + Int(pow(<strong>10.0</strong>, <strong>1.2</strong> - self.randomizer))</code></pre><p>This is exponential decay formula which is often used in <strong>Sports betting</strong> models, where odds drop steeply as winning probability rises. The 10.0 is the <strong>odds base multiplier</strong>. It sets the overall curve steepness when computing odds. 1.2 is the <strong>odds exponent offset</strong>. It shifts the curve so that horses with higher/lower randomizer values don&#8217;t become too extreme. </p><p>Next we look at move &#8212;</p><pre><code>class Horse.move()
    if Double.random(in: 0...1) * (<strong>0.9</strong> + self.randomizer / <strong>10.0</strong>) &gt; <strong>0.7</strong> {
        self.position += 1
    }</code></pre><p>This is essentially <strong>threshold sampling from a uniform distribution</strong>, a very common way to implement &#8220;chance of success.&#8221; It&#8217;s a typical <em>ad-hoc tuning pattern</em> we see in game code: multiplying a random number, then comparing to a constant. 0.9 is the <strong>base speed factor</strong>. It sets how fast horses move on average. 10.0 is used as a <strong>randomizer divisor</strong>. It reduces the effect of the randomizer. 0.7 is the <strong>movement threshold</strong>. It determines how &#8220;hard&#8221; it is for a horse to actually move forward on a tick. The 0.7 is acting like a <strong>difficulty threshold</strong>. The (0.9 + r/10) is a scaling factor that makes the threshold easier to beat as <strong>r</strong> gets larger. </p><p>With the current values, the <strong>Odds </strong>ranges<strong> </strong>from 2:1 (best horse) to 16:1 (worst horse). And the <strong>Move probability </strong>ranges from ~22% to ~30% per turn. So horses move forward about once every 3&#8211;5 turns, and their odds can swing quite a bit depending on the randomizer. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kWE_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcaf1e22-6146-48f0-80ba-f8d25fa4c840_1253x947.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kWE_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcaf1e22-6146-48f0-80ba-f8d25fa4c840_1253x947.png 424w, https://substackcdn.com/image/fetch/$s_!kWE_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcaf1e22-6146-48f0-80ba-f8d25fa4c840_1253x947.png 848w, https://substackcdn.com/image/fetch/$s_!kWE_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcaf1e22-6146-48f0-80ba-f8d25fa4c840_1253x947.png 1272w, https://substackcdn.com/image/fetch/$s_!kWE_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcaf1e22-6146-48f0-80ba-f8d25fa4c840_1253x947.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kWE_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcaf1e22-6146-48f0-80ba-f8d25fa4c840_1253x947.png" width="465" height="351.4405426975259" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bcaf1e22-6146-48f0-80ba-f8d25fa4c840_1253x947.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:947,&quot;width&quot;:1253,&quot;resizeWidth&quot;:465,&quot;bytes&quot;:96266,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/170306009?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcaf1e22-6146-48f0-80ba-f8d25fa4c840_1253x947.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kWE_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcaf1e22-6146-48f0-80ba-f8d25fa4c840_1253x947.png 424w, https://substackcdn.com/image/fetch/$s_!kWE_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcaf1e22-6146-48f0-80ba-f8d25fa4c840_1253x947.png 848w, https://substackcdn.com/image/fetch/$s_!kWE_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcaf1e22-6146-48f0-80ba-f8d25fa4c840_1253x947.png 1272w, https://substackcdn.com/image/fetch/$s_!kWE_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcaf1e22-6146-48f0-80ba-f8d25fa4c840_1253x947.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Putting it all together. </p><pre><code>struct GameConfig {
    <strong>// Player settings</strong>
    static let maxPlayers = 5
    static let minPlayers = 1
    static let startingMoney = 20

    <strong>// Race settings</strong>
    static let goalPosition = 23

    <strong>// Odds calculation. Range 2-16</strong>
    static let oddsBase: Double = 10.0
    static let oddsWinningDampner: Double = 1.2

    <strong>// Horse movement. Move probability range 22% to 30%</strong>
    static let moveBaseSpeed: Double = 0.9
    static let moveDampner: Double = 10.0
    static let moveThreshold: Double = 0.7
}</code></pre><h2>Step 10: Prompt helpers</h2><p>Next I want to move all user input prompts to their own methods. We have 4 places were we ask for user inputs. </p><pre><code>func horseRaceGame...
    var P = 0
    repeat {
        P = INPUT(<strong>"How many players "</strong>)
    } while P &gt; 5 || P &lt; 1

func race...
    var A$ = 0
    repeat {
        A$ = INPUT(<strong>"P \(j)-&gt;"</strong>)
    } while A$ &lt; 0 || A$ &gt; 4 // 0 means pass
    if A$ == 0 { continue }

    var bet: Int
    repeat {
        BEEP()
        PRINT()
        bet = INPUT(<strong>"PLAYER \(j) \(horses[A$-1].symbol) MONEY "</strong>)
    } while !player.placeBet(bet)

    // Replay
    var replay = false
    if players.remaining &gt; 0 {
        repeat {
            let ans: String = INPUT(<strong>"REPLAY (Y/N)?"</strong>)
            if ans == "Y" { replay = true; break }
            if ans == "N" { break }
        } while true
    }</code></pre><p>Lets tackle them one at a time. First getting number of players. </p><pre><code>extension FX790...
    private func <strong>promptNumPlayers()</strong> -&gt; Int {
        while true {
            let p: Int = INPUT("How many players ")
            if (1...5).contains(p) {
                return p
            }
        }
    }

func horseRaceGame...
    for p in 1...<strong>promptNumPlayers()</strong> { ... }</code></pre><p>Next, choose horse. </p><pre><code>extension FX790...
    private func <strong>promptChooseHorse</strong>(for player: Player) -&gt; Int {
        while true {
            let choice: Int = INPUT("P \(player.id)-&gt;")
            if (0...4).contains(choice) {
                return choice
            }
        }
    }

func race...
    let choice = <strong>promptChooseHorse</strong>(for: player)
    if choice == 0 { continue }  // 0 means pass
    player.choose(horse: horses[choice - 1])</code></pre><p>Next, placing bet. </p><pre><code>extension FX790...
    func <strong>promptBetMoney</strong>(for player: Player) -&gt; Int {
        while true {
            let bet: Int = INPUT(
              "PLAYER \(player.id) \(player.chosenHorse!.symbol) MONEY "
            )
            if bet &gt;= 0 &amp;&amp; bet &lt;= player.money {
                return bet
            }
        }
    }

func race...
    let bet = <strong>promptBetMoney</strong>(for: player)
    player.placeBet(bet)</code></pre><p>Lastly, replay. </p><pre><code>extension FX790...
    private func <strong>promptReplay()</strong> -&gt; Bool {
        while true {
            let ans: String = INPUT("REPLAY (Y/N)?")
            if ans == "Y" { return true }
            if ans == "N" { return false }
        }
    }

func race...
    if players.remaining &gt; 0, <strong>promptReplay()</strong> {
        race(num: R+1, horses: horses, players: players)
    }</code></pre><h2>Step 11: Prints, Beeps and Timers</h2><p>This will be the final step in this refactoring session. The code is littered with PRINT and BEEP and  TIMER statement. I want to extract them out as well. In total I extracted out 12 display messages. Along with 4 prompt messages, the total comes to 16.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!S82W!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141486de-1fc3-40d5-ae13-0a800ea58674_1696x640.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!S82W!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141486de-1fc3-40d5-ae13-0a800ea58674_1696x640.png 424w, https://substackcdn.com/image/fetch/$s_!S82W!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141486de-1fc3-40d5-ae13-0a800ea58674_1696x640.png 848w, https://substackcdn.com/image/fetch/$s_!S82W!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141486de-1fc3-40d5-ae13-0a800ea58674_1696x640.png 1272w, https://substackcdn.com/image/fetch/$s_!S82W!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141486de-1fc3-40d5-ae13-0a800ea58674_1696x640.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!S82W!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141486de-1fc3-40d5-ae13-0a800ea58674_1696x640.png" width="1456" height="549" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/141486de-1fc3-40d5-ae13-0a800ea58674_1696x640.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:549,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:348076,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/170306009?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141486de-1fc3-40d5-ae13-0a800ea58674_1696x640.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!S82W!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141486de-1fc3-40d5-ae13-0a800ea58674_1696x640.png 424w, https://substackcdn.com/image/fetch/$s_!S82W!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141486de-1fc3-40d5-ae13-0a800ea58674_1696x640.png 848w, https://substackcdn.com/image/fetch/$s_!S82W!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141486de-1fc3-40d5-ae13-0a800ea58674_1696x640.png 1272w, https://substackcdn.com/image/fetch/$s_!S82W!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141486de-1fc3-40d5-ae13-0a800ea58674_1696x640.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>If we think of modern UI based applications, for instance SwiftUI, then they follow a MVVM pattern. I want to head into that direction next, where <strong>Horse</strong> and <strong>Player</strong> will become <strong>Models</strong>, The current <strong>horseRaceGame</strong>() method will become <strong>ViewModel</strong>, and these 16 <strong>display</strong> and <strong>prompt</strong> messages will turn into <strong>Views</strong>. However, this post is already too long, so we will tackle the MVVM refactoring in the next part. </p><h2>End of Part 1</h2><p>We have come a long way. This is how the program looks at the end of part one. I think this is, at the very least, <strong>readable</strong>. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!449F!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f4219d1-ac0d-4587-8090-533e9126495f_1352x2536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!449F!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f4219d1-ac0d-4587-8090-533e9126495f_1352x2536.png 424w, https://substackcdn.com/image/fetch/$s_!449F!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f4219d1-ac0d-4587-8090-533e9126495f_1352x2536.png 848w, https://substackcdn.com/image/fetch/$s_!449F!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f4219d1-ac0d-4587-8090-533e9126495f_1352x2536.png 1272w, https://substackcdn.com/image/fetch/$s_!449F!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f4219d1-ac0d-4587-8090-533e9126495f_1352x2536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!449F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f4219d1-ac0d-4587-8090-533e9126495f_1352x2536.png" width="1352" height="2536" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2f4219d1-ac0d-4587-8090-533e9126495f_1352x2536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2536,&quot;width&quot;:1352,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:506694,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/170306009?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f4219d1-ac0d-4587-8090-533e9126495f_1352x2536.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!449F!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f4219d1-ac0d-4587-8090-533e9126495f_1352x2536.png 424w, https://substackcdn.com/image/fetch/$s_!449F!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f4219d1-ac0d-4587-8090-533e9126495f_1352x2536.png 848w, https://substackcdn.com/image/fetch/$s_!449F!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f4219d1-ac0d-4587-8090-533e9126495f_1352x2536.png 1272w, https://substackcdn.com/image/fetch/$s_!449F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f4219d1-ac0d-4587-8090-533e9126495f_1352x2536.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The Horse class &#8212;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_cNI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbedbff70-4df4-48e6-ab58-0d5c4c4bcf83_1360x1836.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_cNI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbedbff70-4df4-48e6-ab58-0d5c4c4bcf83_1360x1836.png 424w, https://substackcdn.com/image/fetch/$s_!_cNI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbedbff70-4df4-48e6-ab58-0d5c4c4bcf83_1360x1836.png 848w, https://substackcdn.com/image/fetch/$s_!_cNI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbedbff70-4df4-48e6-ab58-0d5c4c4bcf83_1360x1836.png 1272w, https://substackcdn.com/image/fetch/$s_!_cNI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbedbff70-4df4-48e6-ab58-0d5c4c4bcf83_1360x1836.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_cNI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbedbff70-4df4-48e6-ab58-0d5c4c4bcf83_1360x1836.png" width="1360" height="1836" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bedbff70-4df4-48e6-ab58-0d5c4c4bcf83_1360x1836.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1836,&quot;width&quot;:1360,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:343151,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/170306009?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbedbff70-4df4-48e6-ab58-0d5c4c4bcf83_1360x1836.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_cNI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbedbff70-4df4-48e6-ab58-0d5c4c4bcf83_1360x1836.png 424w, https://substackcdn.com/image/fetch/$s_!_cNI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbedbff70-4df4-48e6-ab58-0d5c4c4bcf83_1360x1836.png 848w, https://substackcdn.com/image/fetch/$s_!_cNI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbedbff70-4df4-48e6-ab58-0d5c4c4bcf83_1360x1836.png 1272w, https://substackcdn.com/image/fetch/$s_!_cNI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbedbff70-4df4-48e6-ab58-0d5c4c4bcf83_1360x1836.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The Player class &#8212;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!J9vS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F923f17d3-d94d-4989-b8a2-f6f244a38310_1360x1988.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!J9vS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F923f17d3-d94d-4989-b8a2-f6f244a38310_1360x1988.png 424w, https://substackcdn.com/image/fetch/$s_!J9vS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F923f17d3-d94d-4989-b8a2-f6f244a38310_1360x1988.png 848w, https://substackcdn.com/image/fetch/$s_!J9vS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F923f17d3-d94d-4989-b8a2-f6f244a38310_1360x1988.png 1272w, https://substackcdn.com/image/fetch/$s_!J9vS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F923f17d3-d94d-4989-b8a2-f6f244a38310_1360x1988.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!J9vS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F923f17d3-d94d-4989-b8a2-f6f244a38310_1360x1988.png" width="1360" height="1988" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/923f17d3-d94d-4989-b8a2-f6f244a38310_1360x1988.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1988,&quot;width&quot;:1360,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:320896,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/170306009?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F923f17d3-d94d-4989-b8a2-f6f244a38310_1360x1988.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!J9vS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F923f17d3-d94d-4989-b8a2-f6f244a38310_1360x1988.png 424w, https://substackcdn.com/image/fetch/$s_!J9vS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F923f17d3-d94d-4989-b8a2-f6f244a38310_1360x1988.png 848w, https://substackcdn.com/image/fetch/$s_!J9vS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F923f17d3-d94d-4989-b8a2-f6f244a38310_1360x1988.png 1272w, https://substackcdn.com/image/fetch/$s_!J9vS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F923f17d3-d94d-4989-b8a2-f6f244a38310_1360x1988.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Increasing Vocabulary of a Software]]></title><description><![CDATA[What does it mean to increase the 'vocabulary' of a software? How does refactoring leads to increasing this vocabulary? And how does this increased vocabulary lead to better design?]]></description><link>https://www.codingpapa.net/p/increasing-vocabulary-of-a-software</link><guid isPermaLink="false">https://www.codingpapa.net/p/increasing-vocabulary-of-a-software</guid><dc:creator><![CDATA[Rohit]]></dc:creator><pubDate>Tue, 05 Aug 2025 01:45:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Ipj2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d517712-3e83-42c6-88d5-4a57f8d05b2c_1024x608.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ipj2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d517712-3e83-42c6-88d5-4a57f8d05b2c_1024x608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ipj2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d517712-3e83-42c6-88d5-4a57f8d05b2c_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!Ipj2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d517712-3e83-42c6-88d5-4a57f8d05b2c_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!Ipj2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d517712-3e83-42c6-88d5-4a57f8d05b2c_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!Ipj2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d517712-3e83-42c6-88d5-4a57f8d05b2c_1024x608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ipj2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d517712-3e83-42c6-88d5-4a57f8d05b2c_1024x608.png" width="1024" height="608" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6d517712-3e83-42c6-88d5-4a57f8d05b2c_1024x608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:608,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!Ipj2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d517712-3e83-42c6-88d5-4a57f8d05b2c_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!Ipj2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d517712-3e83-42c6-88d5-4a57f8d05b2c_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!Ipj2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d517712-3e83-42c6-88d5-4a57f8d05b2c_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!Ipj2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d517712-3e83-42c6-88d5-4a57f8d05b2c_1024x608.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>My all time favorite programing book is <em><a href="https://martinfowler.com/books/refactoring.html">Refactoring</a></em><a href="https://martinfowler.com/books/refactoring.html"> by </a><em><a href="https://martinfowler.com/books/refactoring.html">Martin Fowler</a></em>. When I first read it many many years ago, it was the very first chapter that hooked me. Before even introducing the various refactorings, Martin Fowler starts the book by giving a very powerful example of how applying just a few simple cleanups to a code can improve its structure. So, just to have some fun, I wanted to do it myself, but in my own favorite language - Swift. I want to see if the the Swift version is going to be different from Java, maybe even better when we apply idiomatic Swift. </p><p>I am going to go in a slightly different order of steps than the book. Additionally, I am going to apply a few of my own refactorings. In this process we are going to learn about this concept of <strong>&#8216;increasing vocabulary&#8217;</strong> of a software.</p><h2>The Starting Program</h2><p>I converted the program from Java to Swift. There are three main classes - Movie, Rental and Customer. </p><p><strong>Movie</strong> represents the class which contains its title and pricing code. </p><pre><code>class Movie {
    static let REGULAR = 0
    static let NEW_RELEASE = 1
    static let CHILDRENS = 2

    private var title: String
    private var priceCode: Int

    init(title: String, priceCode: Int) {
        self.title = title
        self.priceCode = priceCode
    }

    func getPriceCode() -&gt; Int {
        return priceCode
    }

    func setPriceCode(_ code: Int) {
        priceCode = code
    }

    func getTitle() -&gt; String {
        return title
    }
}</code></pre><p><strong>Rental</strong> class represents the number of days a movie was rented. </p><pre><code>class Rental {
    private var movie: Movie
    private var daysRented: Int

    init(movie: Movie, daysRented: Int) {
        self.movie = movie
        self.daysRented = daysRented
    }

    func getDaysRented() -&gt; Int {
        return daysRented
    }

    func getMovie() -&gt; Movie {
        return movie
    }
}</code></pre><p><strong>Customer</strong> has the array of all their rentals. </p><pre><code>class Customer {
    private var name: String
    private var rentals: [Rental] = []

    init(name: String) {
        self.name = name
    }

    func addRental(_ rental: Rental) {
        rentals.append(rental)
    }
    
    func getName() -&gt; String {
        return name
    }
}</code></pre><p>There is a method in the <strong>Customer</strong> class called <strong>statement()</strong>, which calculates and prints the rental amount and frequent renter points. </p><pre><code>func statement() -&gt; String {
    var totalAmount: Double = 0
    var frequentRenterPoints = 0
    var result = "Rental Record for \(name)\n"

    for rental in rentals {
        var thisAmount: Double = 0

        // Determine amounts for each line
        switch rental.getMovie().getPriceCode() {
        case Movie.REGULAR:
            thisAmount += 2
            if rental.getDaysRented() &gt; 2 {
                thisAmount += Double(rental<strong>.</strong>getDaysRented() - 2) * 1.5
            }
        case Movie.NEW_RELEASE:
            thisAmount += Double(rental.getDaysRented()) * 3
        case Movie.CHILDRENS:
            thisAmount += 1.5
            if rental.getDaysRented() &gt; 3 {
                thisAmount += Double(rental.getDaysRented() - 3) * 1.5
            }
        default:
            break
        }

        // Add frequent renter points
        frequentRenterPoints += 1
        if rental.getMovie().getPriceCode() == Movie.NEW_RELEASE &amp;&amp;
            rental.getDaysRented() &gt; 1 {
            frequentRenterPoints += 1
        }

        // Show figures for this rental
        result += "\t" + rental.getMovie().getTitle() + "\t" +
            String(format: "%.1f", thisAmount) + "\n"
        totalAmount += thisAmount
    }

    // Add footer lines
    result += "Amount owed is \(String(format: "%.1f", totalAmount))\n"
    result += "You earned " + String(frequentRenterPoints) +
        " frequent renter points"

    return result
}</code></pre><h2>Step 1: Convert to Struct</h2><p>Even before I use the first refactoring from book, I know I can convert <strong>Movie</strong> and <strong>Rental</strong> to <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/classesandstructures">Struct</a>, and clean up a lot of boilerplate code of constructors, getters and setters methods. I can also convert the <strong>var</strong> to <strong>let</strong>. </p><pre><code><strong>struct</strong> Movie {
    static let REGULAR = 0
    static let NEW_RELEASE = 1
    static let CHILDRENS = 2

    <strong>let</strong> title: String
    <strong>let</strong> priceCode: Int
}

<strong>struct</strong> Rental {
    <strong>let</strong> movie: Movie
    <strong>let</strong> daysRented: Int
}

class Customer {
    <strong>let</strong> name: String
    private var rentals: [Rental] = []

    init(name: String) {
        self.name = name
    }

    func addRental(_ rental: Rental) {
        rentals.append(rental)
    }
}</code></pre><p>Already the code is cleaned up nicely for the basic objects. 35 lines of boilerplate code is removed. Less code, which does the exact same thing, is always better. </p><h2>Step 2: Extract Method</h2><p>The best place to start a refactoring exercise are <strong>long methods</strong>. They are the ripest places for evolving our thinking on how to better design our software. We take a long method and breaks it up into smaller <em>helper methods</em>. This technique is called <em>Extract Method</em>, and it is the most powerful refactoring technique. In this step we apply this technique to the <strong>statement()</strong> method. </p><pre><code>func statement() -&gt; String {
    var totalAmount: Double = 0
    var frequentRenterPoints = 0
    var result = "Rental Record for \(name)\n"

    for rental in rentals {
        var thisAmount: Double = 0

        <strong>// Determine amounts for each line
        switch rental.movie.priceCode {
        case Movie.REGULAR:
            thisAmount += 2
            if rental.daysRented &gt; 2 {
                thisAmount += Double(rental.daysRented - 2) * 1.5
            }
        case Movie.NEW_RELEASE:
            thisAmount += Double(rental.daysRented) * 3
        case Movie.CHILDRENS:
            thisAmount += 1.5
            if rental.daysRented &gt; 3 {
                thisAmount += Double(rental.daysRented - 3) * 1.5
            }
        default:
            break
        }</strong>

        // Add frequent renter points
        frequentRenterPoints += 1
        if rental.movie.priceCode == Movie.NEW_RELEASE &amp;&amp;
            rental.daysRented &gt; 1 {
            frequentRenterPoints += 1
        }

        // Show figures for this rental
        result += "\t" + rental.movie.title + "\t" +
            String(format: "%.1f", thisAmount) + "\n"
        totalAmount += thisAmount
    }

    // Add footer lines
    result += "Amount owed is \(String(format: "%.1f", totalAmount))\n"
    result += "You earned " + String(frequentRenterPoints) +
        " frequent renter points"

    return result
}</code></pre><p>We extract the highlight code above to a new method <strong>getCharge(for:). </strong></p><pre><code>func statement() -&gt; String {
    var totalAmount: Double = 0
    var frequentRenterPoints = 0
    var result = "Rental Record for \(name)\n"

    for rental in rentals {
        var thisAmount = <strong>getCharge(for: rental)</strong>

        // Add frequent renter points
        frequentRenterPoints += 1
        if rental.movie.priceCode == Movie.NEW_RELEASE &amp;&amp;
            rental.daysRented &gt; 1 {
            frequentRenterPoints += 1
        }

        // Show figures for this rental
        result += "\t" + rental.movie.title + "\t" +
            String(format: "%.1f", thisAmount) + "\n"
        totalAmount += thisAmount
    }

    // Add footer lines
    result += "Amount owed is \(String(format: "%.1f", totalAmount))\n"
    result += "You earned " + String(frequentRenterPoints) +
        " frequent renter points"

    return result
}
    
private func <strong>getCharge(for aRental: Rental)</strong> -&gt; Double {
    var <strong>result</strong>: Double = 0
    switch <strong>aRental</strong>.movie.priceCode {
    case Movie.REGULAR:
        <strong>result</strong> += 2
        if <strong>aRental</strong>.daysRented &gt; 2 {
            result += Double(<strong>aRental</strong>.daysRented - 2) * 1.5
        }
    case Movie.NEW_RELEASE:
        <strong>result</strong> += Double(<strong>aRental</strong>.daysRented) * 3
    case Movie.CHILDRENS:
        <strong>result</strong> += 1.5
        if <strong>aRental</strong>.daysRented &gt; 3 {
            <strong>result</strong> += Double(<strong>aRental</strong>.daysRented - 3) * 1.5
        }
    default:
        break
    }
    return <strong>result</strong>
}</code></pre><p>One thing I like about Swift is how it lets you choose <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/functions#Specifying-Argument-Labels">argument labels</a> which reads like a sentence. In the book, the method was called <strong>getChargeFor(Rental aRental)</strong>. But in Swift, I made it <strong>getCharge(for aRental: Rental). </strong>Now I call it as:</p><pre><code>double thisAmount = getChargeFor(rental) // Java
var thisAmount = <strong>getCharge(for: rental) </strong>// Swift</code></pre><blockquote><p>The use of <em>argument labels</em> can allow a function to be called in an expressive, sentence-like manner, while still providing a function body that&#8217;s readable and clear in intent.</p></blockquote><h2>Step 3: Second Extract Method</h2><p>We can also extract a second method which calculates frequent renter points. </p><pre><code>class Customer...
func statement() -&gt; String {
    var totalAmount: Double = 0
    var frequentRenterPoints = 0
    var result = "Rental Record for \(name)\n"

    for rental in rentals {
        var thisAmount = getCharge(for: rental)
        frequentRenterPoints = <strong>getFrequentRenterPoints(for: rental)</strong>

        // Show figures for this rental
        result += "\t" + rental.movie.title + "\t" +
            String(format: "%.1f", thisAmount) + "\n"
        totalAmount += thisAmount
    }

    // Add footer lines
    result += "Amount owed is \(String(format: "%.1f", totalAmount))\n"
    result += "You earned " + String(frequentRenterPoints) +
        " frequent renter points"

    return result
}

func <strong>getFrequentRenterPoints(for aRental: Rental)</strong> -&gt; Int {
    if aRental.movie.priceCode == Movie.NEW_RELEASE 
       &amp;&amp; aRental.daysRented &gt; 1 {
        return 2
    }
    return 1
}</code></pre><h2>New Vocabulary Words</h2><p>As I wrote above, <em>Extract Method</em> is the most powerful of refactoring techniques. <em>Extract Method</em> gives new words to our design vocabulary. For instance, in the above example, we now have two new words - <strong>getCharge</strong> and <strong>getFrequentRenterPoints</strong>. <em>These new words are what we are after.</em> They are a way for the existing software to tell us how it wants to evolve. (Yes, software talks if you listen closely!). As we will see in the following steps, once we have these new words, ideas will emerge to design our software better. They are the raw material which will shape the next version of our software&#8217;s design. We need to collect, as much as possible, these raw material. </p><h2>Step 4: Move Method</h2><p>The question to ask about these new words is - <em>which object should these words belong to?</em> Look at the <strong>getCharge</strong> and <strong>getFrequentRenterPoints</strong> methods. These methods do not use any data from the <strong>Customer </strong>class. All the calculations in these methods are done on <strong>aRental</strong>. This is a pretty strong indication that these methods should move to <strong>Rental</strong>. </p><pre><code>struct Rental {
    var movie: Movie
    var daysRented: Int
    
    func <strong>getCharge()</strong> -&gt; Double {
        var result: Double = 0
        switch movie.priceCode {
        case Movie.REGULAR:
            result += 2
            if daysRented &gt; 2 {
                result += Double(daysRented - 2) * 1.5
            }
        case Movie.NEW_RELEASE:
            result += Double(daysRented) * 3
        case Movie.CHILDRENS:
            result += 1.5
            if daysRented &gt; 3 {
                result += Double(daysRented - 3) * 1.5
            }
        default:
            break
        }
        return result
    }

    func <strong>getFrequentRenterPoints()</strong> -&gt; Int {
        if movie.priceCode == Movie.NEW_RELEASE &amp;&amp; daysRented &gt; 1 {
            return 2
        }
        return 1
    }
}</code></pre><p>Then the <strong>statement() </strong>method becomes: </p><pre><code>class Customer...
func statement() -&gt; String {
    var totalAmount: Double = 0
    var frequentRenterPoints = 0
    var result = "Rental Record for \(name)\n"

    for rental in rentals {
        var thisAmount = <strong>rental.getCharge()</strong>
        frequentRenterPoints += <strong>rental.getFrequentRenterPoints()</strong>

        // Show figures for this rental
        result += "\t" + rental.movie.title + "\t" +
            String(format: "%.1f", thisAmount) + "\n"
        totalAmount += thisAmount
    }

    // Add footer lines
    result += "Amount owed is \(String(format: "%.1f", totalAmount))\n"
    result += "You earned " + String(frequentRenterPoints) +
        " frequent renter points"

    return result
}</code></pre><p>This has improved the design, however we are not done. We will go about finding more new words. </p><h2>Step 5: Replace Temp with Query Methods</h2><p>We have 3 temporary variables: <strong>thisAmount</strong>, <strong>frequentRenterPoints</strong>, and <strong>totalAmount</strong>. Our next step is to remove these temporary variables with methods knows as <em>Query Methods</em>. The idea is same as Extract Method - we are going to get more new words. Our vocabulary will increase. And increased vocabulary leads to better design.  </p><p>We apply <em>Replace Temp with Query </em>refactoring to remove <strong>thisAmount</strong> in the <strong>statement</strong> method. </p><pre><code>func statement() -&gt; String {
    var totalAmount: Double = 0
    var frequentRenterPoints = 0
    var result = "Rental Record for \(name)\n"

    for rental in rentals {
        <s>var thisAmount = rental.getCharge()</s>
        frequentRenterPoints += rental.getFrequentRenterPoints()

        // Show figures for this rental
        result += "\t" + rental.movie.title + "\t" +
            String(format: "%.1f", <strong>rental.getCharge()</strong>) + "\n"
        totalAmount += <strong>rental.getCharge()</strong>
    }

    // Add footer lines
    result += "Amount owed is \(String(format: "%.1f", totalAmount))\n"
    result += "You earned " + String(frequentRenterPoints) +
        " frequent renter points"

    return result
}</code></pre><p>That was simple, but we didn&#8217;t get any new words. Next, we remove the <strong>totalAmount </strong>variable<strong>. </strong></p><pre><code>class Customer...
    func statement() -&gt; String {
        <s>var totalAmount: Double = 0</s>
        var frequentRenterPoints = 0
        var result = "Rental Record for \(name)\n"

        for rental in rentals {
            frequentRenterPoints += rental.getFrequentRenterPoints()

            // Show figures for this rental
            result += "\t" + rental.movie.title + "\t" +
                String(format: "%.1f", rental.getCharge()) + "\n"
            <s>totalAmount += rental.getCharge()</s>
        }

        // Add footer lines
        result += "Amount owed is " +
            String(format: "%.1f", <strong>getTotalCharge()</strong>) + "\n"
        result += "You earned " + String(frequentRenterPoints) +
            " frequent renter points"

        return result
    }
    
    private func <strong>getTotalCharge()</strong> -&gt; Double {
        rentals.reduce(0) { $0 + $1.getCharge() }
    }</code></pre><p>We got one new word - <strong>getTotalCharge</strong>! The <strong>getTotalCharge() </strong>method uses closure-based <strong>reduce()</strong> in Swift and using shorthand argument names <strong>($0, $1). </strong>This was 7 lines of code in Java using a for-loop, which is now a one liner. </p><p>Now we do the same for <strong>frequentRenterPoints. </strong></p><pre><code>class Customer...
    func statement() -&gt; String {
        <s>var frequentRenterPoints = 0</s>
        var result = "Rental Record for \(name)\n"

        for rental in rentals {
            <s>frequentRenterPoints += rental.getFrequentRenterPoints()</s>
            // Show figures for this rental
            result += "\t" + rental.movie.title + "\t" +
                String(format: "%.1f", rental.getCharge()) + "\n"
        }

        // Add footer lines
        result += "Amount owed is " +
            String(format: "%.1f", getTotalCharge()) + "\n"
        result += "You earned " +
            String(<strong>getTotalFrequentRenterPoints()</strong>) +
            " frequent renter points"

        return result
    }

    private func getTotalCharge() -&gt; Double {
        rentals.reduce(0) { $0 + $1.getCharge() }
    }
    
    private func <strong>getTotalFrequentRenterPoints()</strong> -&gt; Int {
        rentals.reduce(0) { $0 + $1.getFrequentRenterPoints() }
    }</code></pre><h2>Step 6: Extension Methods</h2><p>We have two new words - <strong>getTotalCharge</strong> and <strong>getTotalFrequentRenterPoints</strong>. We again ask the question <em>which object should these words belong to?</em> These methods operator on a list of <strong>Rental</strong> objects. So we can make it an <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/extensions">extension method</a> on Rental list, and move these to the Rental file. </p><pre><code>class Customer...
    func statement() -&gt; String {
        var result = "Rental Record for \(name)\n"

        for rental in rentals {
            // Show figures for this rental
            result += "\t" + rental.movie.title + "\t" +
                String(format: "%.1f", rental.getCharge()) + "\n"
        }

        // Add footer lines
        result += "Amount owed is " +
            String(format: "%.1f", <strong>rentals.getTotalCharge()</strong>) + "\n"
        result += "You earned " +
            String(<strong>rentals.getTotalFrequentRenterPoints()</strong>) +
            " frequent renter points"

        return result
    }

File Rental...
extension Sequence where Element == Rental {
    func <strong>getTotalCharge()</strong> -&gt; Double {
        reduce(0) { $0 + $1.getCharge() }
    }

    func <strong>getTotalFrequentRenterPoints()</strong> -&gt; Int {
        reduce(0) { $0 + $1.getFrequentRenterPoints() }
    }
}</code></pre><p>I love <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/extensions">Swift&#8217;s extension methods</a>. These methods are available to any other part of the code that needs them. That helps a lot in coming up with cleaner code for the class. </p><p>For now we are done with <strong>Customer</strong> class and the <strong>statement</strong> method. The statement method is looking much better than its original state. Now it only calculates the <strong>result</strong> and leaves the rest of the calculations of totalCharge and totalFrequentRenterPoints to others. This follows the powerful design principle known as <strong>&#8216;Tell, Don&#8217;t Ask&#8221;</strong>. </p><blockquote><p><em>Tell, Don't Ask</em> principle says that instead of <em>asking</em> an object for its data and then making decisions based on that data, you should <em>tell</em> the object what to do directly. This encourages thinking in terms of <em>actions</em> and <em>responsibilities</em> rather than data and state, leading to better encapsulation and maintainable code.</p></blockquote><h2>Step 7: Move Method</h2><p>Lets move our attention to the <strong>Renter</strong> class, and its two new methods <strong>getCharge</strong> and <strong>getFrequentRenterPoints</strong>. <em>Are these methods in the right place?</em> </p><p>The way to find out where a particular method should live, we should look at what data does it operator on. These methods use two pieces of data - the <strong>daysRented </strong>and movie type. One belongs to <strong>Rental</strong> and other to the <strong>Movie</strong> structs. Its 50/50. So where should these methods live? </p><p>We choose <strong>Movie</strong>. Why? The book explains it brilliantly. </p><p>It&#8217;s about &#8220;minimizing change&#8221;. Think about which of these two data - <strong>daysRental</strong> or <strong>movie</strong> <strong>type</strong> - is more likely to change, that will lead to lot of other code changing? It will be the movie type. When we add new movie types, the <strong>switch </strong>and the <strong>if </strong>statements will change. If these methods live in <strong>Rental</strong>, then adding a new movie type will lead to two class changing - <strong>Movie</strong> and <strong>Rental</strong>. But if these methods live in <strong>Movie, </strong>then only one class will need to change, the <strong>Movie </strong>itself. Nobody else will need to know. Better encapsulation leads to another design principle called the <strong>&#8220;Open-Closed Principle&#8221;</strong>. </p><blockquote><p>According to <em>open-closed principle, </em>the code should be open to extension (adding new movie types) but closed for modification (a big ripple effect across all the classes). </p></blockquote><p>Lets move <strong>getCharge </strong>and <strong>getFrequentRenterPoints </strong>methods from <strong>Rental </strong>struct to <strong>Movie </strong>struct.</p><pre><code>struct Rental...
    func getCharge() -&gt; Double {
        return <strong>movie.getCharge(for: daysRented)</strong>
    }
    
    func getFrequentRenterPoints() -&gt; Int {
        return <strong>movie.getFrequentRenterPoints(for: daysRented)</strong>
    }

struct Movie...
    func <strong>getCharge</strong>(for daysRented: Int) -&gt; Double {
        var result: Double = 0
        switch priceCode {
        case Movie.REGULAR:
            result += 2
            if daysRented &gt; 2 {
                result += Double(daysRented - 2) * 1.5
            }
        case Movie.NEW_RELEASE:
            result += Double(daysRented) * 3
        case Movie.CHILDRENS:
            result += 1.5
            if daysRented &gt; 3 {
                result += Double(daysRented - 3) * 1.5
            }
        default:
            break
        }
        return result
    }
    
    func <strong>getFrequentRenterPoints</strong>(for daysRented: Int) -&gt; Int {
        if priceCode == Movie.NEW_RELEASE &amp;&amp; daysRented &gt; 1 {
            return 2
        }
        return 1
    }</code></pre><p>This is the brilliant insight right here! This is the <em>inflection point</em> from where the remainder of the refactoring will happen. This is where we start reaping the benefits of our new vocabulary that will lead us to a better polymorphic solution.  </p><h2>Step 8: Inheritance, Composition or Enums?</h2><p>We are going to move our attention to the <strong>Movie</strong> struct. Its got three types, and based on what type of the movie is, we calculate the charge and frequent renter points. </p><pre><code>struct Movie {
    <strong>static let REGULAR = 0
    static let NEW_RELEASE = 1
    static let CHILDRENS = 2</strong>

    let title: String
    <strong>let priceCode: Int</strong>

    func getCharge(for daysRented: Int) -&gt; Double {
        var result: Double = 0
        <strong>switch priceCode {</strong>
        case Movie.REGULAR:
            result += 2
            if daysRented &gt; 2 {
                result += Double(daysRented - 2) * 1.5
            }
        case Movie.NEW_RELEASE:
            result += Double(daysRented) * 3
        case Movie.CHILDRENS:
            result += 1.5
            if daysRented &gt; 3 {
                result += Double(daysRented - 3) * 1.5
            }
        default:
            break
        }
        return result
    }
    
    func getFrequentRenterPoints(for daysRented: Int) -&gt; Int {
        <strong>if priceCode == Movie.NEW_RELEASE</strong> &amp;&amp; daysRented &gt; 1 {
            return 2
        }
        return 1
    }
}</code></pre><p>There are 3 options to move forward. First, we can use <em>inheritance</em>, and create sub classes for Movie. But notice that <strong>switch</strong> statement and the <strong>if</strong> statement is operating on the <strong>priceCode</strong>. <em>These are not movie types but priceCode types!</em> </p><p>Next option is we can use <em>composition</em>, and create an interface or abstract class <strong>Price</strong>, which will have the 3 sub-type implementations - <strong>RegularPrice</strong>, <strong>NewReleasePrice</strong> and <strong>ChildrenPrice</strong>. The Movie struct will have reference to the Price type, which it can <em>polymorphically</em> use to get charge and frequent renter points. </p><p>The book uses this option 2. But I am doing to defer slightly from the book. We have a third option. Instead of making <strong>Price</strong> an abstract class with various types being subclasses, I am going to make it an <em>Enum</em>. This is more idiomatic way of doing Swift. <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/enumerations">Swift Enums</a> are too powerful, and in almost all cases, removes the need to create interfaces or abstract classes. </p><pre><code><strong>enum</strong> PriceCode {
    case childrens, regular, newRelease
}</code></pre><p>Now we can move <strong>getCharge()</strong> and <strong>getFrequentRenterPoints()</strong> to <strong>PriceCode</strong>. </p><pre><code>struct Movie {
<s>    static let REGULAR = 0
    static let NEW_RELEASE = 1
    static let CHILDRENS = 2</s>

    let title: String
    let priceCode: <strong>PriceCode</strong>

    func getCharge(for daysRented: Int) -&gt; Double {
        return <strong>priceCode.getCharge</strong>(for: daysRented)
    }
    
    func getFrequentRenterPoints(for daysRented: Int) -&gt; Int {
        return <strong>priceCode.getFrequentRenterPoints</strong>(for: daysRented)
    }
}

enum Price...
    func getCharge(for daysRented: Int) -&gt; Double {
        switch <strong>self</strong> {
        case <strong>.regular</strong>:
            var charge = 2.0
            if daysRented &gt; 2 {
                charge += Double(daysRented - 2) * 1.5
            }
            return charge

        case <strong>.newRelease</strong>:
            return Double(daysRented) * 3

        case <strong>.childrens</strong>:
            var charge = 1.5
            if daysRented &gt; 3 {
                charge += Double(daysRented - 3) * 1.5
            }
            return charge
        }
    }
    
    func getFrequentRenterPoints(for daysRented: Int) -&gt; Int {
        switch <strong>self</strong> {
        case <strong>.newRelease</strong>: return daysRented &gt; 1 ? 2 : 1
        default: return 1
        }
    }</code></pre><p>In Java example, they had it as classes, so the static movie types were needed. But in Swift, we can just use the enums directly. There is no difference. </p><h2>Enums over Polymorphism</h2><p>We could have done a polymorphic approach in Swift using <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/protocols">Protocols</a>. </p><pre><code>protocol Price {
    func getCharge(for daysRented: Int) -&gt; Double
    func getFrequentRenterPoints(for daysRented: Int) -&gt; Int
}</code></pre><p>Then had 3 structs adopt this protocol. </p><pre><code>struct RegularPrice: Price { ... } 
struct NewReleasePrice: Price { ... }
struct ChildrensPrice: Price { ... }</code></pre><p>Movie will have reference to Price protocol. </p><pre><code>struct Movie...
    let priceCode: <strong>any</strong> <strong>Price</strong>
}</code></pre><p>Here the priceCode is of <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/opaquetypes/">box type</a> Price, which allows the polymorphic behavior. Setting aside the performance cost of box types due to dynamic dispatch, I don&#8217;t like the proliferation of these small small structs every time we add a new type of price code. Enums allows keeping all logic in one place in a <strong>switch</strong> statement. Yes, the switch statement will grow as we add new price types, but they will stay in one place in one file. Enums also have different <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/enumerations#Associated-Values">associative values</a> for its case values. That is like different subclasses with different constructor fields. </p><p>Therefore, I generally prefer enums over polymorphism. </p><h2>Step 9: PriceCode on Movie or Rental? </h2><p>The example in the book end with step 8 above. But I want go on and do a couple more things. </p><p>Should Movie have a price code or Rental? I think Rental should have the price code. A movie&#8217;s release date or genre can influence its price <em>at time of its rental</em>. Few months after its release, a NEW_RELEASE price code will turn into REGULAR price code. But the Movie object shouldn&#8217;t change. Furthermore, there is a big hint in the code - for Rental to get a charge or frequent renter points, it has to make two hops, through <strong>Movie</strong> and <strong>PriceCode</strong>. But <strong>Movie</strong> has no use of price, except to quickly go and delegate to <strong>PriceCode</strong>. It doesn&#8217;t even pass any of its own data to <strong>PriceCode</strong>, like <strong>Rental</strong> passes <strong>daysRented</strong>. </p><p>So lets move <strong>priceCode</strong> to <strong>Rental</strong>. </p><pre><code>struct Rental {
    var movie: Movie
    <strong>var priceCode: PriceCode</strong>
    var daysRented: Int
    
    func getCharge() -&gt; Double {
        return <strong>priceCode</strong>.getCharge(for: daysRented)
    }
    
    func getFrequentRenterPoints() -&gt; Int {
        return <strong>priceCode</strong>.getFrequentRenterPoints(for: daysRented)
    }
}</code></pre><p>Now PriceCode can be created at the time of Rental, without changing Movie. </p><pre><code>// In 2010
var rental = Rental(movie: inception, priceCode: <strong>Price.newRelease</strong>)

// In 2025
var rental = Rental(movie: inception, priceCode: <strong>Price.regular</strong>)</code></pre><p><strong>Movie</strong> just remains with a <strong>title</strong>. More needless code is deleted. </p><pre><code>struct Movie {
    let title: String
<s>    let priceCode: PriceCode</s>
<s>
    func getCharge(for daysRented: Int) -&gt; Double {
        return priceCode.getCharge(for: daysRented)
    }
    
    func getFrequentRenterPoints(for daysRented: Int) -&gt; Int {
        return priceCode.getFrequentRenterPoints(for: daysRented)
    }</s>
}</code></pre><p>We could also delete the whole <strong>Movie</strong> struct and move the <strong>title</strong> to <strong>Rental</strong>. However, I think we should leave it. Later, if needed, we can add <strong>genre</strong> and <strong>releaseDate</strong> to <strong>Movie</strong> struct, which will help <strong>Rental</strong> to assign a price code.</p><pre><code>struct Movie {
    let title: String
    let genre: String
    let releaseDate: Date
}</code></pre><h2>Step 10: Naming</h2><p>This is the final step. We are going to rename a few methods. It is so important to name things correctly. </p><blockquote><p>Methods should communicate both <strong>what</strong> it&#8217;s doing and <strong>how</strong> it should be interpreted by the caller. </p></blockquote><p>We have two methods <strong>getCharge </strong>and <strong>getFrequentRenterPoints</strong> that I am going to rename. </p><p>On PriceCode, the results of these methods involves computation based on input or internal state. The name should communicate <strong>cost</strong> or <strong>intentionality</strong> (e.g., not just fetching a stored value). We want to signal to caller: <em>&#8220;this isn&#8217;t a stored property, it&#8217;s logic.&#8221;</em> Therefore, I think a more appropriate names are <strong>calculateCharge()</strong> and <strong>calculateFrequentRenterPoints()</strong>.  </p><pre><code>enum Price {
    case childrens, regular, newRelease
    
    func <strong>calculateCharge</strong>(for daysRented: Int) -&gt; Double {
        <em>...calculations...</em>
    }
    
    func <strong>calculateFrequentRenterPoints</strong>(for daysRented: Int) -&gt; Int {
        <em>...calculations...</em>
    }
}</code></pre><p>However, on Rental, these methods are very simple. When it comes to <strong>query methods</strong> (methods that retrieve information and don&#8217;t cause side effects), the <a href="https://www.swift.org/documentation/api-design-guidelines/">Swift API Design Guidelines</a> is to <em>avoid</em> using<strong> </strong>&#8220;get&#8221;<strong> </strong>as a prefix.</p><blockquote><p><strong>&#8220;Omit needless words.&#8221; </strong>Methods and properties should read as <strong>grammatical English phrases</strong>. Avoid <strong>get</strong>, <strong>is</strong>, <strong>do,</strong> <strong>compute</strong>, etc., unless they&#8217;re necessary for clarity or disambiguation.</p></blockquote><p>So we can name these methods simply as <strong>charge()</strong> and <strong>frequentRenterPoints()</strong>. Further, for simple side-effect-free queries, Swift encourages to use <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/properties#Computed-Properties">Computed Properties</a>. Lets do this for <strong>getTotalCharge()</strong> and <strong>getTotalFrequentRenterPoints()</strong> extension methods as well. </p><pre><code>struct Rental...
    <strong>var</strong> <strong>charge</strong>: Double {
        return priceCode.<strong>calculateCharge</strong>(for: daysRented)
    }
    
    <strong>var</strong> <strong>frequentRenterPoints</strong>: Int {
        return priceCode.<strong>calculateFrequentRenterPoints</strong>(for: daysRented)
    }


extension Sequence where Element == Rental {
    <strong>var</strong> <strong>totalCharge</strong>: Double {
        reduce(0) { $0 + $1.<strong>charge</strong> }
    }
    
    <strong>var</strong> <strong>totalFrequentRenterPoints</strong>: Int {
        reduce(0) { $0 + $1.<strong>frequentRenterPoints</strong> }
    }
}</code></pre><p>And the <strong>statement() </strong>method becomes even cleaner. </p><pre><code>class Customer...
    func statement() -&gt; String {
        var result = "Rental Record for \(name)\n"

        for rental in rentals {
            result += "\t" + rental.movie.title + "\t" +
                String(format: "%.1f", <strong>rental.charge</strong>) + "\n"
        }

        // Add footer lines
        result += "Amount owed is " +
            String(format: "%.1f", <strong>rentals.totalCharge</strong>) + "\n"
        result += "You earned " +
            String(<strong>rentals.totalFrequentRenterPoints</strong>) +
            " frequent renter points"

        return result
    }</code></pre><p>Thats it! We are done. </p><h2>Conclusion</h2><p>Lets summarize the insights we gained from this exercise. </p><p>When we first write our software, these new &#8220;vocabulary&#8221; words do not exist. In our example, in the beginning this software&#8217;s purpose was to print out a customer&#8217;s rental statement with charges based on &#8220;days rented&#8221;. Life was simple. Over time, new features are added, like in this case we must have added new movie types (&#8220;new releases&#8221; and &#8220;children&#8221;) and frequent renter points. But we kept shoving them into the <em>statement</em> method. So the vocabulary of this program remained stagnant. With refractoring, we discovered new words - charges and frequentRenterPoints. Those led to the creation of a new enum PriceCode. This  significantly improved the design of our software. Now, if we add a new price code, it would just need modifying one Enum. In this simple example its hard to see the cost savings, but imagine a code base with thousands of line of code. </p><p>We also looked at few design principles - Tell, Don&#8217;t Ask, Open-Closed principle, Enums over Polymorphism, and Naming guidelines. </p><p>Lastly, I hope I was able to illustrate some of the lovely features of the Swift programming language - Structs, Enums, Argument labels, Extension Methods, Computed Properties, and <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/stringsandcharacters#String-Interpolation">String Interpolation</a>. </p><p>Thanks for reading! </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ODjR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb52fc9af-79f0-4d52-b568-edcf30b7bb2c_1080x793.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ODjR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb52fc9af-79f0-4d52-b568-edcf30b7bb2c_1080x793.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ODjR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb52fc9af-79f0-4d52-b568-edcf30b7bb2c_1080x793.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ODjR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb52fc9af-79f0-4d52-b568-edcf30b7bb2c_1080x793.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ODjR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb52fc9af-79f0-4d52-b568-edcf30b7bb2c_1080x793.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ODjR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb52fc9af-79f0-4d52-b568-edcf30b7bb2c_1080x793.jpeg" width="1080" height="793" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b52fc9af-79f0-4d52-b568-edcf30b7bb2c_1080x793.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:793,&quot;width&quot;:1080,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:235590,&quot;alt&quot;:&quot;grayscale photo of books on shelves&quot;,&quot;title&quot;:&quot;grayscale photo of books on shelves&quot;,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="grayscale photo of books on shelves" title="grayscale photo of books on shelves" srcset="https://substackcdn.com/image/fetch/$s_!ODjR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb52fc9af-79f0-4d52-b568-edcf30b7bb2c_1080x793.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ODjR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb52fc9af-79f0-4d52-b568-edcf30b7bb2c_1080x793.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ODjR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb52fc9af-79f0-4d52-b568-edcf30b7bb2c_1080x793.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ODjR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb52fc9af-79f0-4d52-b568-edcf30b7bb2c_1080x793.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Varargs in Rust]]></title><description><![CDATA[How to create variable number of parameters of one type in a function in Rust.]]></description><link>https://www.codingpapa.net/p/varargs-in-rust</link><guid isPermaLink="false">https://www.codingpapa.net/p/varargs-in-rust</guid><dc:creator><![CDATA[Rohit]]></dc:creator><pubDate>Mon, 23 Jun 2025 02:47:09 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!FTIe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa489a513-9b7b-486a-893f-60e4982709ae_1024x608.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FTIe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa489a513-9b7b-486a-893f-60e4982709ae_1024x608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FTIe!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa489a513-9b7b-486a-893f-60e4982709ae_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!FTIe!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa489a513-9b7b-486a-893f-60e4982709ae_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!FTIe!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa489a513-9b7b-486a-893f-60e4982709ae_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!FTIe!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa489a513-9b7b-486a-893f-60e4982709ae_1024x608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FTIe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa489a513-9b7b-486a-893f-60e4982709ae_1024x608.png" width="1024" height="608" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a489a513-9b7b-486a-893f-60e4982709ae_1024x608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:608,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FTIe!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa489a513-9b7b-486a-893f-60e4982709ae_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!FTIe!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa489a513-9b7b-486a-893f-60e4982709ae_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!FTIe!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa489a513-9b7b-486a-893f-60e4982709ae_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!FTIe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa489a513-9b7b-486a-893f-60e4982709ae_1024x608.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Introduction</h2><p><em>Varargs</em>&nbsp;were introduced in&nbsp;<em>Java 5</em>&nbsp;and provide a short-hand for methods that support an arbitrary number of parameters of one type. This is signified by three dots (<code>...</code>).</p><pre><code>public boolean match(<strong>TokenType... types</strong>) {
    for (TokenType type : types) {
      if (check(type)) {
        return true;
      }
    }
    return false;  
}</code></pre><p>And are called as a comma separated list. </p><pre><code>match(PLUS, MINUS)</code></pre><p>Rust doesn't have a direct equivalent to Java's <code>...</code> (varargs) syntax. But there are 4 ways we can achieve the same result. </p><h2>1. Vectors (Don't use)</h2><p>We can use vectors to pass the list of arguments.  </p><pre><code>fn match_token(<strong>types: Vec&lt;TokenType&gt;</strong>) -&gt; bool {
    for &amp;token_type in types {
        if check(token_type) {
            return true;
        }
    }
    false
}`</code></pre><p>And then call it like -</p><pre><code>match_token(<strong>vec!</strong>[PLUS, MINUS])</code></pre><h2>2. Slices (Best)</h2><p>We can use slices (<strong>&amp;[T]</strong>) to pass an arbitrary number of arguments. </p><pre><code>fn match_token(<strong>types: &amp;[TokenType]</strong>) -&gt; bool {
    for &amp;token_type in types {
        if check(token_type) {
            return true;
        }
    }
    false
}</code></pre><p>Usage is - </p><pre><code>match_token(<strong>&amp;</strong>[PLUS, MINUS])</code></pre><p>Using <strong>&amp;[T]</strong> is better than using <strong>Vec</strong><em> in most cases</em>.</p><ul><li><p><strong>Avoids heap allocation</strong>: <strong>vec![&#8230;]</strong> creates a new vector on the heap every time you call the function. Whereas, <strong>&amp;[T] </strong>is a borrowed reference to a static array &#8212; no allocation involved.</p></li><li><p><strong>Better performance</strong>: <strong>&amp;[T]</strong> just points to existing data, no copying or memory allocation. <strong>Vec!</strong> has to allocate, construct, and then drop the vector.</p></li><li><p><strong>More idiomatic for fixed/short lists</strong>: We're not modifying the list, just reading it &#8212; so a reference is semantically correct.</p></li></ul><h2>3. Macros (Less common)</h2><p>Macros can give Java-style variadic syntax, but are usually overkill unless you need extreme flexibility.</p><pre><code><strong>macro_rules!</strong> match_token {
    (expr, $( $token_type:expr ),+ ) =&gt; {{
        let mut matched = false;
        $(
            if check($token_type) {
                matched = true;
                break;
            }
        )+
        matched
    }};
}</code></pre><p>Usage is - </p><pre><code><strong>match_token!</strong>(PLUS, MINUS) </code></pre><p>Macros are powerful, but they come with tradeoffs like harder debugging and less type inference. Use <strong>macros</strong> if you want concise call sites or compile-time efficiency. Prefer <strong>slices (&amp;[T])</strong> if you want more readable, testable, and debuggable code.</p><h2>4. Const Generics (Cleanest!)</h2><p>This approach is very clean and performant but only works with <em>fixed-length arrays</em> - i.e. size known at compile time. This is fine if the list is hardcoded at the call sites.</p><pre><code>pub fn match_token<strong>&lt;const N: usize&gt;(types: [TokenType; N])</strong> -&gt; bool {
    for token_type in types {
        if check(token_type) {
            return true;
        }
    }
    false
}</code></pre><p>Here <strong>&lt;const N: usize&gt;</strong> lets Rust know the size of the array at compile time, and <strong>[TokenType; N]</strong> is the fixed-size array. The usage is - </p><pre><code>match_token([PLUS, MINUS])  </code></pre><p>I think this is the cleanest approach! We do <em>not</em> need to take a reference (<strong>&amp;[TokenType]</strong>) &#8212; it's owned, but with zero allocation, and inline. This avoids runtime heap allocations and allows full compile-time optimization.</p><h2>Conclusion</h2><p>Use <strong>slices</strong> when the number of arguments is not known at compile time, and use <strong>const generics</strong> when the size of the array is known at compile time. </p>]]></content:encoded></item><item><title><![CDATA[Copy in Rust]]></title><description><![CDATA[How to use Copy to avoid borrow, lifetime annotation or smart pointers.]]></description><link>https://www.codingpapa.net/p/copy-in-rust</link><guid isPermaLink="false">https://www.codingpapa.net/p/copy-in-rust</guid><dc:creator><![CDATA[Rohit]]></dc:creator><pubDate>Sun, 22 Jun 2025 18:27:20 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!cDza!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F685619c2-cd8a-4e32-8510-87300dc3e1f0_1024x608.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cDza!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F685619c2-cd8a-4e32-8510-87300dc3e1f0_1024x608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cDza!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F685619c2-cd8a-4e32-8510-87300dc3e1f0_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!cDza!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F685619c2-cd8a-4e32-8510-87300dc3e1f0_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!cDza!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F685619c2-cd8a-4e32-8510-87300dc3e1f0_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!cDza!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F685619c2-cd8a-4e32-8510-87300dc3e1f0_1024x608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cDza!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F685619c2-cd8a-4e32-8510-87300dc3e1f0_1024x608.png" width="1024" height="608" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/685619c2-cd8a-4e32-8510-87300dc3e1f0_1024x608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:608,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cDza!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F685619c2-cd8a-4e32-8510-87300dc3e1f0_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!cDza!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F685619c2-cd8a-4e32-8510-87300dc3e1f0_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!cDza!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F685619c2-cd8a-4e32-8510-87300dc3e1f0_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!cDza!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F685619c2-cd8a-4e32-8510-87300dc3e1f0_1024x608.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In Rust, some simple types are &#8220;implicitly copyable&#8221; and when you assign them or pass them as arguments, the receiver will get a copy, leaving the original value in place. <em>Copy</em> types are like &#8220;value&#8221; types in Java or JS language. Therefore <em>Copy</em> can be used to avoid borrow, lifetime annotation or smart pointer.</p><h2>Native types implement Copy</h2><pre><code><em><strong>// u8 implements Copy</strong></em>
let x: u8 = 123;
let y = x;  <em><strong>// copy happen implicitly</strong></em>
println!("x={}, y={}", x, y);  <em><strong>// x can still be used</strong></em>

<em><strong>// Vec&lt;u8&gt; implements Clone, but not Copy</strong></em>
let v: Vec&lt;u8&gt; = vec![1, 2, 3];
let w = v; <em><strong>// This would *move* the value, rendering v unusable.</strong></em></code></pre><p><em>Copy</em> simply tells the compiler that this previous copy is still valid and can be reused. The compiler understands that it doesn't need to consider <em>move</em>.  <em>Reassignments</em> or <em>passing-by-values</em> leave behind a bitwise copy of the object at its previous position. Values are safely duplicated via&nbsp;<strong>memcpy</strong>. This implies the value is somehow primitive or cheap to copy. It is guaranteed to have zero overhead. </p><h2>Reassignment</h2><pre><code>#[derive(Debug, Clone, <strong>Copy</strong>)]
pub struct PointCloneAndCopy {
    pub x: f64,
}

#[derive(Debug, Clone)]
pub struct PointCloneOnly {
    pub x: f64,
}

fn test_copy_and_clone() {
    let p1 = PointCloneAndCopy { x: 0. };
    let p2 = p1; <em><strong>// Copied automatically</strong></em>
    println!("{:?} {:?}", p1, p2);
}

fn test_clone_only() {
    let p1 = PointCloneOnly { x: 0. };
    let p2 = p1; <em><strong>// This is a move instead</strong></em>
    println!("{:?} {:?}", p1, p2); <em><strong>// ERROR!</strong></em>
}</code></pre><p>Every <strong>Copy</strong> type is also required to be <strong>Clone</strong>. <strong>Clone</strong> is a supertrait of <strong>Copy</strong>, so everything which is <strong>Copy</strong> must also implement <strong>Clone</strong>. If a type is <strong>Copy</strong> then its <strong>Clone</strong> implementation only needs to return <strong>*self.</strong></p><h2>Passing-by-value</h2><p>Consider this enum <strong>TokenType</strong> which doesn&#8217;t implement <strong>Copy</strong>. When we pass it as an argument to a method, we do it as <em>borrow</em> using &amp;. </p><pre><code><em><strong>// No Copy</strong></em>
#[derive(Clone, Debug)]
enum TokenType {
    Plus,
    Minus,
    // ...
}

fn check(&amp;self, token_type: &amp;TokenType) -&gt; bool {
    // ...
}

<em><strong>// This is *borrow* i.e. pass-by-reference</strong></em>
self.check(<strong>&amp;</strong>TokenType.Plus)</code></pre><p>I was bothered by the added <strong>&amp;</strong> everywhere. I understand that the borrow is <em>idiomatic </em>in Rust, but here it feels a bit verbose, especially for enum comparisons where we're not mutating or consuming the value &#8212; just checking it. So I made <strong>TokenType</strong> implement <strong>Copy. </strong></p><pre><code>#[derive(<strong>Copy</strong>, Clone, Debug)]
enum TokenType {
    Plus,
    Minus,
    // ...
}

<em><strong>// Now its clean pass-by-value</strong></em>
self.check(TokenType.PLUS)</code></pre><h2>Conclusion</h2><p><strong>Copy</strong>&nbsp;is meant to be implemented for "cheap" types, such as&nbsp;<strong>u8</strong>&nbsp;or simple Enums, as in the example above. If you write a quite heavyweight type, for which you think a move is more efficient than a copy, make it&nbsp;<em>not</em>&nbsp;implement&nbsp;<strong>Copy</strong>. Note that in the u8 case, we cannot possibly be more efficient with a move, since under the hood it would probably at least entail a pointer copy - which is already as expensive as a u8 copy, so why bother.</p>]]></content:encoded></item><item><title><![CDATA[Books read in 2025]]></title><description><![CDATA[A list of books read in 2025]]></description><link>https://www.codingpapa.net/p/books-read-in-2025</link><guid isPermaLink="false">https://www.codingpapa.net/p/books-read-in-2025</guid><dc:creator><![CDATA[Rohit]]></dc:creator><pubDate>Sun, 22 Jun 2025 04:11:06 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!YeTo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74798076-2f4d-4841-8e50-197e37460273_1832x1252.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Non Fiction</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YeTo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74798076-2f4d-4841-8e50-197e37460273_1832x1252.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YeTo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74798076-2f4d-4841-8e50-197e37460273_1832x1252.png 424w, https://substackcdn.com/image/fetch/$s_!YeTo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74798076-2f4d-4841-8e50-197e37460273_1832x1252.png 848w, https://substackcdn.com/image/fetch/$s_!YeTo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74798076-2f4d-4841-8e50-197e37460273_1832x1252.png 1272w, https://substackcdn.com/image/fetch/$s_!YeTo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74798076-2f4d-4841-8e50-197e37460273_1832x1252.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YeTo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74798076-2f4d-4841-8e50-197e37460273_1832x1252.png" width="1456" height="995" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/74798076-2f4d-4841-8e50-197e37460273_1832x1252.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:995,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1930704,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/166500360?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74798076-2f4d-4841-8e50-197e37460273_1832x1252.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!YeTo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74798076-2f4d-4841-8e50-197e37460273_1832x1252.png 424w, https://substackcdn.com/image/fetch/$s_!YeTo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74798076-2f4d-4841-8e50-197e37460273_1832x1252.png 848w, https://substackcdn.com/image/fetch/$s_!YeTo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74798076-2f4d-4841-8e50-197e37460273_1832x1252.png 1272w, https://substackcdn.com/image/fetch/$s_!YeTo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74798076-2f4d-4841-8e50-197e37460273_1832x1252.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Fiction</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!T58U!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdf776e6-ba35-46c0-8f32-d5ad560b5f3d_1840x1652.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!T58U!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdf776e6-ba35-46c0-8f32-d5ad560b5f3d_1840x1652.png 424w, https://substackcdn.com/image/fetch/$s_!T58U!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdf776e6-ba35-46c0-8f32-d5ad560b5f3d_1840x1652.png 848w, https://substackcdn.com/image/fetch/$s_!T58U!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdf776e6-ba35-46c0-8f32-d5ad560b5f3d_1840x1652.png 1272w, https://substackcdn.com/image/fetch/$s_!T58U!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdf776e6-ba35-46c0-8f32-d5ad560b5f3d_1840x1652.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!T58U!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdf776e6-ba35-46c0-8f32-d5ad560b5f3d_1840x1652.png" width="1456" height="1307" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bdf776e6-ba35-46c0-8f32-d5ad560b5f3d_1840x1652.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1307,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3768076,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codingpapa.net/i/166500360?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdf776e6-ba35-46c0-8f32-d5ad560b5f3d_1840x1652.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!T58U!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdf776e6-ba35-46c0-8f32-d5ad560b5f3d_1840x1652.png 424w, https://substackcdn.com/image/fetch/$s_!T58U!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdf776e6-ba35-46c0-8f32-d5ad560b5f3d_1840x1652.png 848w, https://substackcdn.com/image/fetch/$s_!T58U!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdf776e6-ba35-46c0-8f32-d5ad560b5f3d_1840x1652.png 1272w, https://substackcdn.com/image/fetch/$s_!T58U!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdf776e6-ba35-46c0-8f32-d5ad560b5f3d_1840x1652.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p>]]></content:encoded></item><item><title><![CDATA[Solving Interview Coding Problems]]></title><description><![CDATA[Lets examine how a simple step by step approach could lead to solving a challenging coding problem in an interview.]]></description><link>https://www.codingpapa.net/p/coding-problem-1</link><guid isPermaLink="false">https://www.codingpapa.net/p/coding-problem-1</guid><dc:creator><![CDATA[Rohit]]></dc:creator><pubDate>Sat, 18 Jun 2022 15:26:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7LAF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda98827-ecfe-4976-bd3f-4f1311d0472e_1024x608.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7LAF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda98827-ecfe-4976-bd3f-4f1311d0472e_1024x608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7LAF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda98827-ecfe-4976-bd3f-4f1311d0472e_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!7LAF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda98827-ecfe-4976-bd3f-4f1311d0472e_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!7LAF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda98827-ecfe-4976-bd3f-4f1311d0472e_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!7LAF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda98827-ecfe-4976-bd3f-4f1311d0472e_1024x608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7LAF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda98827-ecfe-4976-bd3f-4f1311d0472e_1024x608.png" width="1024" height="608" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/eda98827-ecfe-4976-bd3f-4f1311d0472e_1024x608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:608,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7LAF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda98827-ecfe-4976-bd3f-4f1311d0472e_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!7LAF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda98827-ecfe-4976-bd3f-4f1311d0472e_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!7LAF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda98827-ecfe-4976-bd3f-4f1311d0472e_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!7LAF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda98827-ecfe-4976-bd3f-4f1311d0472e_1024x608.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4>The Question</h4><p>Imagine we got the following coding question in an interview. </p><blockquote><p><em>There exists a staircase with N steps, and you can climb up either 1 or 2 steps at a time. Given N, write a function that returns the number of unique ways you can climb the staircase.</em> </p></blockquote><h4>Step 1: Think of the underlying structure of the problem</h4><p>The underlying structure of this problem can be thought of as a tree. Every step of the staircase is the node of the tree. And from every step, we can go either 1 step or 2 steps. Thinking of the problem as a tree, leads us to a solution idea using depth-first-search (DFS). </p><h4>Step 2: Implement simple DFS using recursion </h4><p>The number of ways we can climb to a step n is the sum of number of ways we can climb to (n-1) step and number ways we can climb to (n-2) step. We can use this to create the recursive method. </p><pre><code>int countWays(int n) {
  return <strong>countWays(n-1) + countWays(n-2);</strong>
}</code></pre><h4>Step 3: Implement Recursion Base Case</h4><p>Now we just need to think of the base case to stop the recursion. Say n = 2. The number of ways to get to step 2 are 2 (1, 1 and 2). Using the equation above, this becomes: </p><p>CountWays(1) + CountWays(0) = CountWays(0) + CountWays(-1) + CountWays(0)</p><p>This mean whenever we have n=0, we return 1 count, and whenever we have n=-1, we return 0. </p><pre><code>int countWays(int n) {
<strong>  if (n&lt;0) {
    return 0; 
  } else if (n == 0) {
    return 1;
  }</strong>

  return countWays(n-1) + countWays(n-2);
}</code></pre><h4>Step 4: Think of Runtime and Optimize</h4><p>The runtime is exponential, <strong>O(2^N)</strong>, since each call branches to 2 more calls. We can fix this with memoization. </p><pre><code><code>int countWays(int n) {
  if (n&lt;0) {
    return 0; 
  } else if (n == 0) {
    return 1;
  } 

  </code><strong>// memoization</strong><code>
</code><strong>  if (cache.containsKey(n)){
    return cache.get(n);
  }</strong><code>

  int ways = countWays(n-1) + countWays(n-2);

</code><strong>  cache.put(n, ways);</strong><code>
  return ways;
} </code></code></pre><h4>Step 5: Think of edge cases</h4><p><strong>Integer</strong> will overflow soon. Using a <strong>Long</strong> or <strong>BigInteger</strong> will help. </p><pre><code><strong>long</strong><code> countWays(int n) {
  if (n&lt;0) {
    return 0; 
  } else if (n == 0) {
    return 1;
  } 

  // memoization
  if (cache.containsKey(n)){
    return cache.get(n);
  }

  </code><strong>long</strong><code> ways = countWays(n-1) + countWays(n-2);

  cache.put(n, ways);
  return ways;
}</code></code></pre><h4>Enhancing the Question</h4><p>We knew this was going to happen. The interviewer was going to extend the problem to make it more challenging. </p><blockquote><p><em>What if, instead of being able to climb 1 or 2 steps at a time, you could climb any number from a set of positive integers X? For example, if X = {1, 3, 5}, you could climb 1, 3, or 5 steps at a time.</em></p></blockquote><h4>Step 6: Again think of the underlying problem</h4><p>This becomes a backtracking problem. We <em>try all steps</em> from the given set, until we reach the end (n=0). </p><pre><code><code>long countWays(int n, </code><strong>Set&lt;int&gt; x</strong><code>) {
  if (n&lt;0) {
    return 0; 
  } else if (n == 0) {
    return 1;
  } 

  if (cache.containsKey(n)){
    return cache.get(n);
  }

</code><strong>  // backtracking
  long ways = 0; 
  for (int st in x) {
    ways += countWays(n - st);
  }</strong><code>

  cache.put(n, ways);
  return ways;
} </code></code></pre><h4>Conclusion</h4><p>Every (good) interview question has some underlying structure. These structures are handful in number. We don&#8217;t need to solve every leetcode problem to ace the interview. Just remember these handful of structures. We examined a few in this post - Trees, DFS, Recursion, Memoization, and Backtracking. </p>]]></content:encoded></item><item><title><![CDATA[Welcome to Coding Papa]]></title><description><![CDATA[I'm a software engineer based in Seattle, who is found tinkering with code on weekends for fun. This is my corner of the web where I write occasionally.]]></description><link>https://www.codingpapa.net/p/welcome</link><guid isPermaLink="false">https://www.codingpapa.net/p/welcome</guid><dc:creator><![CDATA[Rohit]]></dc:creator><pubDate>Thu, 22 Jul 2021 02:51:54 GMT</pubDate><enclosure url="https://cdn.substack.com/image/fetch/h_600,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F50420b5a-34da-4adc-8753-f02b3c283cd4_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0FY4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F50420b5a-34da-4adc-8753-f02b3c283cd4_512x512.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0FY4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F50420b5a-34da-4adc-8753-f02b3c283cd4_512x512.png 424w, https://substackcdn.com/image/fetch/$s_!0FY4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F50420b5a-34da-4adc-8753-f02b3c283cd4_512x512.png 848w, https://substackcdn.com/image/fetch/$s_!0FY4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F50420b5a-34da-4adc-8753-f02b3c283cd4_512x512.png 1272w, https://substackcdn.com/image/fetch/$s_!0FY4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F50420b5a-34da-4adc-8753-f02b3c283cd4_512x512.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0FY4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F50420b5a-34da-4adc-8753-f02b3c283cd4_512x512.png" width="512" height="512" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/50420b5a-34da-4adc-8753-f02b3c283cd4_512x512.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:512,&quot;width&quot;:512,&quot;resizeWidth&quot;:512,&quot;bytes&quot;:61345,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0FY4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F50420b5a-34da-4adc-8753-f02b3c283cd4_512x512.png 424w, https://substackcdn.com/image/fetch/$s_!0FY4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F50420b5a-34da-4adc-8753-f02b3c283cd4_512x512.png 848w, https://substackcdn.com/image/fetch/$s_!0FY4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F50420b5a-34da-4adc-8753-f02b3c283cd4_512x512.png 1272w, https://substackcdn.com/image/fetch/$s_!0FY4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F50420b5a-34da-4adc-8753-f02b3c283cd4_512x512.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I am a software engineer based in Seattle, WA. This is my corner of the web where I write about my programming experience, reading and software tinkering (see my <a href="https://github.com/rohita">github</a>). Visit the <a href="https://www.codingpapa.net/archive">archives</a> for all past articles. </p><h3>Stay up-to-date</h3><p>If you like what you reading here, consider subscribing to the newsletter. It&#8217;s free and you won&#8217;t have to worry about missing anything. Every new article goes directly to your inbox.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.codingpapa.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.codingpapa.net/subscribe?"><span>Subscribe now</span></a></p><h3>Join the crew</h3><p>Be part of a community of people who share your interests. To find out more about the company that provides the tech for this newsletter, visit <a href="https://www.substack.com/">Substack.com</a>.</p>]]></content:encoded></item><item><title><![CDATA[Optionals in Swift]]></title><description><![CDATA[6 ways to use Optional type in Swift. How many of these methods do you already know? The last one may surprise you!]]></description><link>https://www.codingpapa.net/p/6-ways-to-unwrap-an-optional-in-swift</link><guid isPermaLink="false">https://www.codingpapa.net/p/6-ways-to-unwrap-an-optional-in-swift</guid><dc:creator><![CDATA[Rohit]]></dc:creator><pubDate>Thu, 15 Jul 2021 21:03:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!dsuf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7caa80e7-6ae5-43ba-a929-57dd477c51f6_640x448.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dsuf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7caa80e7-6ae5-43ba-a929-57dd477c51f6_640x448.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dsuf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7caa80e7-6ae5-43ba-a929-57dd477c51f6_640x448.jpeg 424w, https://substackcdn.com/image/fetch/$s_!dsuf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7caa80e7-6ae5-43ba-a929-57dd477c51f6_640x448.jpeg 848w, https://substackcdn.com/image/fetch/$s_!dsuf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7caa80e7-6ae5-43ba-a929-57dd477c51f6_640x448.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!dsuf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7caa80e7-6ae5-43ba-a929-57dd477c51f6_640x448.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dsuf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7caa80e7-6ae5-43ba-a929-57dd477c51f6_640x448.jpeg" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/7caa80e7-6ae5-43ba-a929-57dd477c51f6_640x448.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:36017,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dsuf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7caa80e7-6ae5-43ba-a929-57dd477c51f6_640x448.jpeg 424w, https://substackcdn.com/image/fetch/$s_!dsuf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7caa80e7-6ae5-43ba-a929-57dd477c51f6_640x448.jpeg 848w, https://substackcdn.com/image/fetch/$s_!dsuf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7caa80e7-6ae5-43ba-a929-57dd477c51f6_640x448.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!dsuf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7caa80e7-6ae5-43ba-a929-57dd477c51f6_640x448.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><h2>Introduction</h2><p>Object references in many programming languages can point to the real object or not point to anything (i.e. they are <em>Null</em>). Swift, conversely, does not have null object references. The references must always point to a real object. To support the &#8220;can have absence of a value&#8221; feature, Swift has a different solution - the <strong>Optional</strong> type, which is an enum of two cases.</p><pre><code>enum <strong>Optional</strong>&lt;Wrapped&gt; {
  case <strong>none</strong>
  case <strong>some</strong>(Wrapped)
}</code></pre><p><strong>Optional</strong> either holds&nbsp;<em>no value</em>&nbsp;or&nbsp;<em>some value</em>. The&nbsp;<strong>none</strong>&nbsp;enum case denotes the absence of a value and the&nbsp;<strong>some</strong>&nbsp;enum case denotes presence of value. The value is stored as&nbsp;<strong>Wrapped</strong>, which is the generic <em>placeholder</em> type for the actual user define type of the value. Now anytime we have a need to use null, we can use <strong>Optional</strong>.</p><h2>Creating Optionals</h2><p>Lets use an example from an imaginary cat experiment.</p><pre><code>func openSchrodingersBox() -&gt; <strong>Optional&lt;Cat&gt;</strong> {
  if poisonFlaskShattered {
    return .<strong>none</strong>
  } else {
    return <strong>.some(Cat(name: "Shady"))</strong>
  }
}</code></pre><p>This function can return both a <strong>value</strong> and <strong>none</strong>. Swift gives three helpful syntax simplifiers: (a) the special constant <strong>&#8220;nil&#8221;</strong> having the value <strong>Optional.none</strong>, (b) the question mark (<strong>?</strong>) operator to define the optional type instead of typing the full name <strong>Optional&lt;Cat&gt;, </strong>and (c) no need to specify <strong>.some.</strong></p><pre><code><code>func openSchrodingersBox() -&gt; </code><strong>Cat?</strong><code> {
  if poisonFlaskShattered {
    return </code><strong>nil</strong><code>
  } else {
    return </code><strong>Cat(name: "Shady")</strong><code>
  }
}</code> </code></pre><p>This way all the implementation details of the <strong>Optional</strong> enum is completely hidden from the programmer, and they can just work with <strong>nil</strong> and <strong>?</strong>. </p><h2>Unwrapping Optionals</h2><p><strong>Optional</strong>&nbsp;instances in Swift must be &#8220;unwrapped&#8221; before their values can be used. Unwrapping means extracting out the stored value. There are 6 ways to unwrap optional values. The following use the example function above to get a cat which may or may not be alive. </p><pre><code><code>let maybeAliveCat: </code><strong>Cat?</strong><code> = openSchrodingersBox()</code> </code></pre><h3>1. Optional Binding</h3><p>The first way you can unwrap an optional is use&nbsp;<strong>if-let</strong>&nbsp;to find out whether an optional contains a value, and if so, unwrap that value as a new variable. This is called&nbsp;<em>optional binding</em>.</p><pre><code><strong>if let</strong> <code>aliveCat = maybeAliveCat {
  aliveCat.meow() 
} </code></code></pre><p>In this example the scope of&nbsp;<strong>aliveCat</strong>&nbsp;is only within the body of the <strong>if</strong> statement.</p><h3>2. Guard Statement</h3><p>You can use&nbsp;<strong>guard-let-else</strong>&nbsp;statement to also check if optional contains a value. The <strong>guard</strong> statement has an&nbsp;<strong>else</strong>&nbsp;clause. The code inside the&nbsp;<strong>else</strong>&nbsp;clause is executed if the optional doesn&#8217;t have a value. If the optional has a value, it is available in the lines of code that follow the guard statement.</p><pre><code><strong>guard</strong><code> let aliveCat = maybeAliveCat </code><strong>else</strong><code> {
  return 
} 
aliveCat.meow() </code></code></pre><p>Using&nbsp;guard&nbsp;statement lets you&nbsp;<em>early exit</em>&nbsp;a method if value is not present. It improves the readability of the code compared to doing the same check with an <strong>if-let</strong> statement.</p><h3>3. Nil-Coalescing Operator</h3><p>The third way you can unwrap an optional is using the&nbsp;<em>nil-coalescing operator</em>&nbsp;(<strong>??</strong>). This lets you provide a default value if optional is&nbsp;<strong>nil</strong>.</p><pre><code>let aliveCat = <strong>maybeAliveCat ?? defaultCat</strong>
aliveCat.meow()<code> </code></code></pre><h3>4. Optional Chaining</h3><p>Next, you can also unwrap by placing a question mark (<strong>?</strong>) after the optional. This is called&nbsp;<em>optional chaining</em>.</p><pre><code><strong>maybeAliveCat?.</strong>meow() </code></pre><p>If the optional contains a value, the <strong>meow()</strong> call succeeds; if the optional is&nbsp;nil, the method <strong>meow() </strong>is never executed. Multiple queries can be chained together, and the entire chain fails gracefully if any link in the chain is&nbsp;nil.</p><h3>5. Forced Unwrapping</h3><p>So far we have looked at&nbsp;<em>safe</em>&nbsp;ways to unwrap optionals. These next 2 are unsafe, and should be used when you&#8217;re sure that an optional contains a value. First of these is to&nbsp;<em>force unwrap</em>&nbsp;an optional&#8217;s underlying value by adding an exclamation point (<strong>!</strong>) to the end of the optional&#8217;s name.</p><pre><code><strong>maybeAliveCat!.</strong>meow()</code></pre><p>This is similar to optional chaining using&nbsp;<strong>?</strong>. But the difference is that optional chaining fails gracefully when the optional is&nbsp;<strong>nil</strong>, whereas trying to use<strong>&nbsp;!&nbsp;</strong>to access a nonexistent optional value, triggers a runtime error. Therefore, forced unwrapping is generally not recommended.</p><h3>6. Implicit Unwrapping</h3><p>Finally, sometimes it&#8217;s useful to remove the need to check and unwrap the optional&#8217;s value every time it&#8217;s accessed, because it can be safely assumed to have a value all of the time. These kinds of optionals are declared using exclamation mark instead of a question mark, and are called as&nbsp;<em>implicitly unwrapped optionals</em>.</p><pre><code><strong>let aliveCat: Cat! </strong>= maybeAliveCat
aliveCat.meow() </code></pre><p>This way optionals are unwrapped automatically and can be used like non-optional values, without the need to unwrap them each time they&#8217;re accessed. However, if an implicitly unwrapped optional is&nbsp;nil&nbsp;and you try to access its wrapped value, you&#8217;ll trigger a runtime error.</p><h2>Conclusion</h2><p><a href="https://en.wikipedia.org/wiki/Tony_Hoare">Tony Hoare</a>&nbsp;invented the Null reference in 1965 as part of the ALGOL W language. He later called it as a&nbsp;<a href="https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/">&#8220;billion-dollar mistake&#8221;</a>, saying</p><blockquote><p><em>&#8230;it has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.</em></p></blockquote><p>I cannot say if Swift optionals have saved a billion dollars, but I hope at least this article helped you in understanding how they work. Feel free to contact me if you have any questions or comments.</p>]]></content:encoded></item></channel></rss>