mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-05 20:40:25 -08:00
Added MiniScript implementation of 71_Poker.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
print ""*30 + "POETRY"
|
||||
print ""*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"
|
||||
print " "*30 + "POETRY"
|
||||
print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"
|
||||
print; print; print
|
||||
|
||||
I = 0; J = 0; K = 0; U = 0
|
||||
|
||||
18
00_Alternate_Languages/71_Poker/MiniScript/README.md
Normal file
18
00_Alternate_Languages/71_Poker/MiniScript/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).
|
||||
|
||||
Conversion to [MiniScript](https://miniscript.org).
|
||||
|
||||
Ways to play:
|
||||
|
||||
1. Command-Line MiniScript:
|
||||
Download for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:
|
||||
```
|
||||
miniscript poker.ms
|
||||
```
|
||||
|
||||
2. Mini Micro:
|
||||
Download Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose "Mount Folder..." Select the folder containing the MiniScript program and this README file. Then, at the Mini Micro command prompt, enter:
|
||||
```
|
||||
load "poker"
|
||||
run
|
||||
```
|
||||
557
00_Alternate_Languages/71_Poker/MiniScript/poker.ms
Normal file
557
00_Alternate_Languages/71_Poker/MiniScript/poker.ms
Normal file
@@ -0,0 +1,557 @@
|
||||
print " "*33 + "POKER"
|
||||
print " "*15 + "Creative Computing Morristown, New Jersey"
|
||||
print; print; print
|
||||
|
||||
print "Welcome to the casino. We each have $200."
|
||||
print "I will open the betting before the draw; you open after."
|
||||
print "To fold bet 0; to check bet .5."
|
||||
print "Enough talk -- let's get down to business."
|
||||
print
|
||||
|
||||
askYesNo = function(prompt)
|
||||
while true
|
||||
yn = input(prompt + "? ").lower + " "
|
||||
if yn[0] == "y" then return "yes"
|
||||
if yn[0] == "n" then return "no"
|
||||
print "Answer yes or no, please."
|
||||
end while
|
||||
end function
|
||||
askNumber = function(prompt, maxQty=3, minQty=1, maxErr=null, minErr=null)
|
||||
while true
|
||||
value = input(prompt + "? ").val
|
||||
if minQty <= value <= maxQty then return value
|
||||
if value < minQty and minErr != null then
|
||||
print minErr
|
||||
else if maxErr != null then
|
||||
print maxErr
|
||||
else
|
||||
print "Enter a value between " + minQty + " and " + maxQty + ", please."
|
||||
end if
|
||||
end while
|
||||
end function
|
||||
random = function(n)
|
||||
return floor(n * rnd)
|
||||
end function
|
||||
rand10 = function
|
||||
return floor(10 * rnd)
|
||||
end function
|
||||
pad = function(s, width)
|
||||
return s + " " * (width - s.len)
|
||||
end function
|
||||
|
||||
// Bonus little feature when running in Mini Micro: display a header bar
|
||||
// always at the top of the screen, showing current balances. Does nothing
|
||||
// on other platforms.
|
||||
drawHeaders = function
|
||||
if version.hostName != "Mini Micro" then return
|
||||
display(2).mode = displayMode.text; td = display(2)
|
||||
td.color = color.black; td.backColor = text.color
|
||||
td.row = 25; td.column = 0
|
||||
td.print pad("Computer: $" + computer.balance, 25) +
|
||||
pad("Table: $" + Table.pot, 25) +
|
||||
pad("Player: $" + human.balance, 18)
|
||||
end function
|
||||
|
||||
|
||||
// Card class: represents a single playing card
|
||||
Card = {}
|
||||
Card.rank = 0 // from 2 to 14 (Ace)
|
||||
Card.suit = "Clubs"
|
||||
Card.keep = false // temp flag, used to note which cards to keep vs. discard
|
||||
Card.make = function(rank, suit)
|
||||
result = new Card
|
||||
result.rank = rank
|
||||
result.suit = suit
|
||||
return result
|
||||
end function
|
||||
Card.rankStr = function(plural=false)
|
||||
if self.rank > 10 then
|
||||
return ["Jack", "Queen", "King", "Ace"][self.rank-11] + "s"*plural
|
||||
else
|
||||
return str(self.rank) + "'s" * plural
|
||||
end if
|
||||
end function
|
||||
Card.str = function
|
||||
return self.rankStr + " of " + self.suit
|
||||
end function
|
||||
|
||||
// Prepare a standard deck of 52 cards, and functions to draw and discard
|
||||
deck = []
|
||||
for suit in ["Clubs", "Diamonds", "Hearts", "Spades"]
|
||||
for rank in range(2, 14)
|
||||
deck.push Card.make(rank, suit)
|
||||
end for
|
||||
end for
|
||||
deck.shuffle
|
||||
discardPile = []
|
||||
drawCard = function
|
||||
if not deck then
|
||||
globals.deck = discardPile
|
||||
deck.shuffle
|
||||
globals.discardPile = []
|
||||
end if
|
||||
return deck.pop
|
||||
end function
|
||||
discard = function(cardOrCards)
|
||||
if cardOrCards isa Hand then
|
||||
globals.discardPile += cardOrCards.cards
|
||||
else if cardOrCards isa list then
|
||||
globals.discardPile += cardOrCards
|
||||
else
|
||||
discardPile.push cardOrCards
|
||||
end if
|
||||
end function
|
||||
|
||||
// Hand ranks: how we compare Poker hands
|
||||
HandRank = {}
|
||||
HandRank.value = 0
|
||||
HandRank.str = function(highCard); return ""; end function
|
||||
HandRank.make = function(value)
|
||||
result = new HandRank
|
||||
result.value = value
|
||||
return result
|
||||
end function
|
||||
|
||||
HandRank.None = new HandRank
|
||||
HandRank.Schmaltz = HandRank.make(1)
|
||||
HandRank.Schmaltz.str = function(c); return "schmaltz, " + c.rankStr + " high"; end function
|
||||
HandRank.PartialStraight = HandRank.make(2)
|
||||
HandRank.PartialStraight.str = function(c); return ""; end function // (no display string; this is used only internally)
|
||||
HandRank.Pair = HandRank.make(3)
|
||||
HandRank.Pair.str = function(c); return "a pair of " + c.rankStr(true); end function
|
||||
HandRank.TwoPair = HandRank.make(4)
|
||||
HandRank.TwoPair.str = function(c); return "two pair, " + c.rankStr(true); end function
|
||||
HandRank.Three = HandRank.make(5)
|
||||
HandRank.Three.str = function(c); return "three " + c.rankStr(true); end function
|
||||
HandRank.Straight = HandRank.make(6)
|
||||
HandRank.Straight.str = function(c); return "straight, " + c.rankStr + " high"; end function
|
||||
HandRank.Flush = HandRank.make(7)
|
||||
HandRank.Flush.str = function(c); return "a flush in " + c.suit; end function
|
||||
HandRank.FullHouse = HandRank.make(8)
|
||||
HandRank.FullHouse.str = function(c); return "full house, " + c.rankStr(true); end function
|
||||
HandRank.Four = HandRank.make(9)
|
||||
HandRank.Four.str = function(c); return "four " + c.rankStr(true); end function
|
||||
// Note: original code does not detect a straight flush or royal flush.
|
||||
|
||||
// Hand: represents a set of cards in the hand of one player.
|
||||
Hand = {}
|
||||
Hand.cards = null // list of Card
|
||||
Hand.rank = null // HandRank instance
|
||||
Hand.highCard = null // reference to which (of self.cards) determines relative value
|
||||
Hand.afterDraw = false // true if we've already had a chance to draw cards
|
||||
Hand.make = function(cards)
|
||||
result = new Hand
|
||||
result.cards = cards
|
||||
result.analyze
|
||||
return result
|
||||
end function
|
||||
Hand.deal = function
|
||||
return Hand.make([drawCard, drawCard, drawCard, drawCard, drawCard])
|
||||
end function
|
||||
Hand.replaceCard = function(index)
|
||||
discard self.cards[index]
|
||||
self.cards[index] = drawCard
|
||||
end function
|
||||
Hand.rankStr = function
|
||||
return self.rank.str(self.highCard)
|
||||
end function
|
||||
Hand.isWeak = function
|
||||
return self.rank.value < HandRank.PartialStraight.value or
|
||||
(self.rank.value == HandRank.PartialStraight.value and self.afterDraw) or
|
||||
(self.rank <= HandRank.TwoPair.value and self.highCard.rank <= 6)
|
||||
end function
|
||||
Hand.beats = function(other)
|
||||
if self.rank.value > other.rank.value then return true
|
||||
if self.rank.value < other.rank.value then return false
|
||||
return self.highCard.rank > other.highCard.rank
|
||||
end function
|
||||
Hand.print = function(startingNumber=1)
|
||||
num = startingNumber
|
||||
for c in self.cards
|
||||
s = " " * (num < 10) + num + " -- " + c.str
|
||||
print " " + s, ""
|
||||
if num % 2 == 0 then
|
||||
print
|
||||
else
|
||||
print " " * (28-s.len), ""
|
||||
end if
|
||||
num += 1
|
||||
end for
|
||||
if num % 2 == 0 then print
|
||||
end function
|
||||
Hand.analyze = function
|
||||
allSameSuit = true
|
||||
for i in range(1, self.cards.len-1)
|
||||
if self.cards[i].suit != self.cards[0].suit then allSameSuit = false
|
||||
end for
|
||||
if allSameSuit then
|
||||
self.rank = HandRank.Flush
|
||||
self.highCard = self.cards[0]
|
||||
return
|
||||
end if
|
||||
|
||||
sortedCards = self.cards[:]
|
||||
sortedCards.sort "rank"
|
||||
self.rank = HandRank.Schmaltz
|
||||
for c in sortedCards; c.keep = false; end for
|
||||
keepAny = false
|
||||
|
||||
for i in range(0, sortedCards.len-2)
|
||||
matchesNextCard = (sortedCards[i].rank == sortedCards[i+1].rank)
|
||||
if matchesNextCard then
|
||||
self.highCard = sortedCards[i]
|
||||
matchesPrevCard = (i > 0 and sortedCards[i].rank == sortedCards[i-1].rank)
|
||||
sortedCards[i].keep = true
|
||||
sortedCards[i+1].keep = true
|
||||
keepAny = true
|
||||
if self.rank.value < HandRank.Pair.value then
|
||||
self.rank = HandRank.Pair
|
||||
else if matchesPrevCard and self.rank == HandRank.Pair then
|
||||
self.rank = HandRank.Three
|
||||
else if self.rank == HandRank.Pair then
|
||||
self.rank = HandRank.TwoPair
|
||||
else if self.rank == HandRank.TwoPair then
|
||||
self.rank = HandRank.FullHouse
|
||||
else if matchesPrevCard then
|
||||
self.rank = HandRank.Four
|
||||
else
|
||||
self.rank = HandRank.FullHouse
|
||||
end if
|
||||
end if
|
||||
end for
|
||||
if not keepAny then
|
||||
if sortedCards[3].rank - sortedCards[0].rank == 3 then
|
||||
for i in range(0,3); sortedCards[i].keep = true; end for
|
||||
self.rank = HandRank.PartialStraight
|
||||
end if
|
||||
if sortedCards[4].rank - sortedCards[1].rank == 3 then
|
||||
if self.rank == HandRank.PartialStraight then
|
||||
self.rank = HandRank.Straight
|
||||
sortedCards[4].keep = true
|
||||
self.highCard = sortedCards[4]
|
||||
else
|
||||
self.rank = HandRank.PartialStraight
|
||||
for i in range(1,4); sortedCards[i].keep = true; end for
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
if self.rank == HandRank.Schmaltz then
|
||||
self.highCard = sortedCards[4]
|
||||
sortedCards[4].keep = true
|
||||
sortedCards[3].keep = true
|
||||
end if
|
||||
|
||||
end function
|
||||
|
||||
// Some global constants, just to make the code more understandable
|
||||
Ante = 5
|
||||
|
||||
// Player -- base class for computer and human
|
||||
Player = {}
|
||||
Player.balance = 200
|
||||
Player.hand = null
|
||||
Player.totalBet = 0
|
||||
Player.anteUp = function
|
||||
self.balance -= Ante
|
||||
return Ante
|
||||
end function
|
||||
Player.newHand = function
|
||||
if self.hand then discard self.hand
|
||||
self.hand = Hand.deal
|
||||
self.totalBet = 0
|
||||
end function
|
||||
Player.addToPot = function(amount)
|
||||
self.balance -= amount
|
||||
Table.pot += amount
|
||||
drawHeaders
|
||||
end function
|
||||
Player.win = function
|
||||
self.balance += Table.pot
|
||||
Table.pot = 0
|
||||
drawHeaders
|
||||
end function
|
||||
|
||||
// strategies the computer player might employ
|
||||
Strategy = {}
|
||||
Strategy.make = function(name, value=2, drawCount=null)
|
||||
result = new Strategy
|
||||
result.name = name
|
||||
result.value = value
|
||||
result.drawCount = drawCount
|
||||
return result
|
||||
end function
|
||||
Strategy.fold = Strategy.make("FOLD")
|
||||
Strategy.check = Strategy.make("CHECK")
|
||||
Strategy.raise = Strategy.make("RAISE", 2)
|
||||
Strategy.bluff = function(value, drawCount); return Strategy.make("BLUFF", value, drawCount); end function
|
||||
Strategy.bet = function(value); return Strategy.make("BET", value); end function
|
||||
|
||||
// computer player
|
||||
computer = new Player
|
||||
computer.strategy = null
|
||||
computer.newHand = function
|
||||
super.newHand
|
||||
if self.hand.isWeak then
|
||||
if rand10 < 2 then
|
||||
self.strategy = Strategy.bluff(23, 2)
|
||||
else if rand10 < 2 then
|
||||
self.strategy = Strategy.bluff(23, 1)
|
||||
else if rand10 < 1 then
|
||||
self.strategy = Strategy.bluff(23, 0)
|
||||
else
|
||||
self.strategy = Strategy.fold
|
||||
end if
|
||||
else if self.hand.rank.value < HandRank.Three.value then
|
||||
if rand10 < 2 then self.strategy = Strategy.bluff(23, null) else self.strategy = Strategy.check
|
||||
else if self.hand.rank.value < HandRank.FullHouse.value then
|
||||
self.strategy = Strategy.bet(35)
|
||||
else
|
||||
if rand10 < 1 then self.strategy = Strategy.bet(35) else self.strategy = Strategy.raise
|
||||
end if
|
||||
end function
|
||||
computer.bet = function(minBet=1, openingBet=false)
|
||||
//print "My hand: "; self.hand.print; print "Strategy: " + self.strategy
|
||||
if self.balance < minBet then
|
||||
print "I fold."
|
||||
return 0
|
||||
end if
|
||||
if openingBet and (self.strategy == Strategy.check or self.strategy == Strategy.fold) then
|
||||
print "I check."
|
||||
return 0.5
|
||||
else if self.strategy == Strategy.fold and human.totalBet > 5 then
|
||||
print "I fold."
|
||||
return 0
|
||||
else if self.strategy == Strategy.check then
|
||||
print "I'll see you."
|
||||
return minBet
|
||||
else if openingBet then
|
||||
result = self.strategy.value + rand10
|
||||
if result > self.balance then result = self.balance
|
||||
if result == 0 then
|
||||
print "I check."
|
||||
return 0.5
|
||||
end if
|
||||
print "I'll open with $" + result
|
||||
return result
|
||||
else
|
||||
bet = self.strategy.value + rand10
|
||||
if self.strategy == Strategy.raise then bet += minBet
|
||||
if bet > self.balance then bet = self.balance
|
||||
raise = bet - minBet
|
||||
if raise <= 0 then
|
||||
print "I'll see you."
|
||||
return minBet
|
||||
else
|
||||
print "I'll see you, and raise you " + raise
|
||||
return bet
|
||||
end if
|
||||
end if
|
||||
end function
|
||||
computer.drawCards = function
|
||||
//print "My hand:"; self.hand.print
|
||||
drawCount = 0
|
||||
for c in self.hand.cards; if not c.keep then drawCount += 1; end for
|
||||
print "I am taking " + drawCount + " card" + "s" * (drawCount != 1)
|
||||
for i in self.hand.cards.indexes
|
||||
if not self.hand.cards[i].keep then self.hand.replaceCard i
|
||||
end for
|
||||
self.hand.analyze
|
||||
//print "My new hand: "; self.hand.print
|
||||
if self.strategy.name == "BLUFF" then
|
||||
self.strategy = Strategy.bluff(28)
|
||||
else if self.hand.isWeak then
|
||||
self.strategy = Strategy.fold
|
||||
else if self.hand.rank.value < HandRank.Three.value then
|
||||
if rand10 == 0 then self.strategy = Strategy.bet(19) else self.strategy = Strategy.raise
|
||||
else if self.hand.rank.value < HandRank.FullHouse.value then
|
||||
if rand10 == 0 then self.strategy = Strategy.bet(11) else self.strategy = Strategy.bet(19)
|
||||
else
|
||||
self.strategy = Strategy.raise
|
||||
end if
|
||||
end function
|
||||
computer.win = function
|
||||
print; print "I win."
|
||||
super.win
|
||||
end function
|
||||
computer.checkFunds = function
|
||||
if self.balance >= Ante then return
|
||||
if human.balance < 50 then return // BUGFIX
|
||||
if human.hasWatch or askYesNo("Would you like to buy back your watch for $50") == "no" then
|
||||
print "I'm busted. Conglatulations!"
|
||||
exit
|
||||
end if
|
||||
self.balance += 50
|
||||
// Note: original BASIC code does not take money from the player, but let's fix that:
|
||||
human.balance -= 50 // BUGFIX
|
||||
human.hasWatch = true
|
||||
drawHeaders
|
||||
end function
|
||||
|
||||
|
||||
human = new Player
|
||||
human.hasWatch = true
|
||||
human.bet = function(minBet=1, openingBet=false)
|
||||
while true
|
||||
betStr = input("What is your bet? ")
|
||||
bet = betStr.val
|
||||
if bet == 0 and betStr != "0" then
|
||||
print "Enter 0 to fold, 0.5 to check, or a value of 1 or more to bet."
|
||||
continue
|
||||
else if bet == 0.5 and openingBet then
|
||||
return bet // (check)
|
||||
else if 0 < bet < 1 then
|
||||
print "No small change, please."
|
||||
continue
|
||||
else if bet < minBet then
|
||||
print "If you can't see my bet, then fold."
|
||||
continue
|
||||
else if bet > self.balance then
|
||||
print "You can't bet with what you haven't got."
|
||||
self.trySellWatch
|
||||
continue
|
||||
end if
|
||||
return bet
|
||||
end while
|
||||
end function
|
||||
human.drawCards = function
|
||||
qty = askNumber("How many cards do you want", 3, 0, "You can't draw more than three cards.")
|
||||
if qty == 0 then return
|
||||
print "What are their numbers: "
|
||||
for i in range(1, qty)
|
||||
num = askNumber("", 5, 1)
|
||||
self.hand.replaceCard num - 1
|
||||
end for
|
||||
print "Your new hand:"
|
||||
self.hand.print
|
||||
self.hand.analyze
|
||||
end function
|
||||
human.win = function
|
||||
print; print "You win."
|
||||
super.win
|
||||
end function
|
||||
human.checkFunds = function
|
||||
if self.balance < Ante then self.trySellWatch
|
||||
if self.balance < Ante then
|
||||
print "Your wad is shot. So long, sucker!"
|
||||
exit
|
||||
end if
|
||||
end function
|
||||
human.trySellWatch = function
|
||||
if not self.hasWatch then return
|
||||
if rand10 < 7 then
|
||||
value = 75
|
||||
msg = "I'll give you $" + value + " for it."
|
||||
else
|
||||
value = 25
|
||||
msg = "That's a pretty crummy watch - I'll give you $" + value + "."
|
||||
end if
|
||||
if computer.balance < value then return // BUGFIX
|
||||
if askYesNo("Would you like to sell your watch") == "no" then return
|
||||
print msg
|
||||
self.balance += value
|
||||
self.hasWatch = false
|
||||
// Note: the original BASIC program does not actually take any money from the computer.
|
||||
// But let's do it right here:
|
||||
computer.balance -= value // BUGFIX
|
||||
drawHeaders
|
||||
end function
|
||||
|
||||
Table = {}
|
||||
Table.pot = 0
|
||||
|
||||
|
||||
deal = function
|
||||
Table.pot += computer.anteUp + human.anteUp
|
||||
drawHeaders
|
||||
computer.newHand
|
||||
human.newHand
|
||||
end function
|
||||
|
||||
// Do a round of betting. Return true to continue, or false
|
||||
// if either player folds (ending the hand).
|
||||
takeBets = function(computerFirst)
|
||||
if computerFirst then
|
||||
bet = computer.bet(1, true)
|
||||
if bet == 0 then
|
||||
human.win
|
||||
return false
|
||||
end if
|
||||
if bet == 0.5 then bet = 0 // "check" (no bet, but stay in the hand)
|
||||
computer.addToPot bet
|
||||
else
|
||||
bet = 0
|
||||
end if
|
||||
raise = bet
|
||||
canCheck = (bet == 0)
|
||||
while true
|
||||
bet = human.bet(raise, canCheck)
|
||||
if bet == 0 then
|
||||
computer.win
|
||||
return false
|
||||
end if
|
||||
if bet == 0.5 then // (checked)
|
||||
if computerFirst then return true
|
||||
bet = 0
|
||||
else
|
||||
human.addToPot bet
|
||||
raise = bet - raise
|
||||
if raise == 0 then return true
|
||||
end if
|
||||
if computerFirst or bet > 0 then canCheck = false
|
||||
|
||||
bet = computer.bet(raise, canCheck)
|
||||
if bet == 0 then
|
||||
human.win
|
||||
return false
|
||||
end if
|
||||
if bet == 0.5 then return true // (checked)
|
||||
canCheck = false
|
||||
computer.addToPot bet
|
||||
raise = bet - raise
|
||||
if raise == 0 then return true
|
||||
end while
|
||||
end function
|
||||
|
||||
playHand = function
|
||||
print
|
||||
computer.checkFunds
|
||||
human.checkFunds
|
||||
print "The ante is " + Ante + ". I will deal:"
|
||||
print
|
||||
|
||||
deal
|
||||
|
||||
print "Your hand:"
|
||||
human.hand.print
|
||||
|
||||
print
|
||||
if not takeBets(true) then return
|
||||
|
||||
print; print "Now we draw -- ", ""
|
||||
human.drawCards
|
||||
computer.drawCards
|
||||
|
||||
if not takeBets(false) then return
|
||||
|
||||
print; print "Now we compare hands:"
|
||||
print "My hand:"
|
||||
computer.hand.print 6
|
||||
print
|
||||
print "You have " + human.hand.rankStr
|
||||
print "I have " + computer.hand.rankStr
|
||||
if computer.hand.beats(human.hand) then
|
||||
computer.win
|
||||
else if human.hand.beats(computer.hand) then
|
||||
human.win
|
||||
else
|
||||
print "The hand is drawn."
|
||||
print "All $" + Table.pot + " remains in the pot."
|
||||
end if
|
||||
end function
|
||||
|
||||
drawHeaders
|
||||
while true
|
||||
playHand
|
||||
print "Now I have $" + computer.balance + " and you have $" + human.balance
|
||||
if askYesNo("Do you wish to continue") == "no" then break
|
||||
end while
|
||||
@@ -15,6 +15,17 @@ As published in Basic Computer Games (1978):
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
#### Known Bugs
|
||||
|
||||
- If you bet more than the computer has, it will still see you, resulting in a negative balance. (To handle this properly, the computer would need to go "all in" and reduce your bet to an amount it can match; or else lose the game, which is what happens to the human player in the same situation.)
|
||||
|
||||
- If you are low on cash and sell your watch, then make a bet much smaller than the amount you just gained from the watch, it sometimes nonetheless tells you you "blew your wad" and ends the game.
|
||||
|
||||
- When the watch is sold (in either direction), the buyer does not actually lose any money.
|
||||
|
||||
- The code in the program about selling your tie tack is unreachable due to a logic bug.
|
||||
|
||||
|
||||
#### Porting Notes
|
||||
|
||||
(please note any difficulties or challenges in porting here)
|
||||
|
||||
Reference in New Issue
Block a user