RosettaCodeData/Task/24-game/PureBasic/24-game.basic

161 lines
4.5 KiB
Plaintext

#digitCount = 4
Global Dim digits(#digitCount - 1) ;holds random digits
Procedure showDigits()
Print(#CRLF$ + "These are your four digits: ")
Protected i
For i = 0 To #digitCount - 1
Print(Str(digits(i)))
If i < (#digitCount - 1)
Print(", ")
Else
PrintN("")
EndIf
Next
Print("24 = ")
EndProcedure
Procedure playAgain()
Protected answer.s
Repeat
Print("Play again (y/n)? ")
answer = LCase(Left(Trim(Input()), 1))
Select answer
Case "n"
ProcedureReturn #False
Case "y"
ProcedureReturn #True
Default
PrintN("")
Continue
EndSelect
ForEver
EndProcedure
Procedure allDigitsUsed()
Protected i
For i = 0 To #digitCount - 1
If digits(i) <> 0
ProcedureReturn #False
EndIf
Next
ProcedureReturn #True
EndProcedure
Procedure isValidDigit(d)
For i = 0 To #digitCount - 1
If digits(i) = d
digits(i) = 0
ProcedureReturn #True
EndIf
Next
ProcedureReturn #False
EndProcedure
Procedure doOperation(List op.c(), List operand.f())
Protected x.f, y.f, op.c
op = op(): DeleteElement(op())
If op = '('
ProcedureReturn #False ;end of sub-expression
EndIf
y = operand(): DeleteElement(operand())
x = operand()
Select op
Case '+'
x + y
Case '-'
x - y
Case '*'
x * y
Case '/'
x / y
EndSelect
operand() = x
ProcedureReturn #True ;operation completed
EndProcedure
;returns error if present and the expression results in *result\f
Procedure.s parseExpression(expr.s, *result.Float)
NewList op.c()
NewList operand.f()
expr = ReplaceString(expr, " ", "") ;remove spaces
If Len(expr) = 0: *result\f = 0: ProcedureReturn "": EndIf ;no expression, return zero
Protected *ech.Character = @expr, lastWasDigit, lastWasOper, parenCheck, c.c
While *ech\c
c = *ech\c
Select c
Case '*', '/', '-', '+'
If Not lastWasDigit: ProcedureReturn "Improper syntax, need a digit between operators.": EndIf
If ListSize(op()) And (FindString("*/", Chr(op()), 1) Or (FindString("+-", Chr(op()), 1) And FindString("+-", Chr(c), 1)))
doOperation(op(), operand())
EndIf
AddElement(op()): op() = c
lastWasOper = #True: lastWasDigit = #False
Case '('
If lastWasDigit: ProcedureReturn "Improper syntax, need an operator before left paren.": EndIf
AddElement(op()): op() = c
parenCheck + 1: lastWasOper = #False
Case ')'
parenCheck - 1: If parenCheck < 0: ProcedureReturn "Improper syntax, missing a left paren.": EndIf
If Not lastWasDigit: ProcedureReturn "Improper syntax, missing a digit before right paren.": EndIf
Repeat: Until Not doOperation(op(),operand())
lastWasDigit = #True
Case '1' To '9'
If lastWasDigit: ProcedureReturn "Improper syntax, need an operator between digits.": EndIf
AddElement(operand()): operand() = c - '0'
If Not isValidDigit(operand()): ProcedureReturn "'" + Chr(c) + "' is not a valid digit.": EndIf
lastWasDigit = #True: lastWasOper = #False
Default
ProcedureReturn "'" + Chr(c) + "' is not allowed in the expression."
EndSelect
*ech + SizeOf(Character)
Wend
If parenCheck <> 0 Or lastWasOper: ProcedureReturn "Improper syntax, missing a right paren or digit.": EndIf
Repeat
If Not ListSize(op()): Break: EndIf
Until Not doOperation(op(),operand())
*result\f = operand()
ProcedureReturn "" ;no error
EndProcedure
Define success, failure, result.f, error.s, i
If OpenConsole()
PrintN("The 24 Game" + #CRLF$)
PrintN("Given four digits and using just the +, -, *, and / operators; and the")
PrintN("possible use of brackets, (), enter an expression that equates to 24.")
Repeat
For i = 0 To #digitCount - 1
digits(i) = 1 + Random(8)
Next
showDigits()
error = parseExpression(Input(), @result)
If error = ""
If Not allDigitsUsed()
PrintN( "Wrong! (you didn't use all digits)"): failure + 1
ElseIf result = 24.0
PrintN("Correct!"): success + 1
Else
Print("Wrong! (you got ")
If result <> Int(result)
PrintN(StrF(result, 2) + ")")
Else
PrintN(Str(result) + ")")
EndIf
failure + 1
EndIf
Else
PrintN(error): failure + 1
EndIf
Until Not playAgain()
PrintN("success:" + Str(success) + " failure:" + Str(failure) + " total:" + Str(success + failure))
Print(#CRLF$ + "Press ENTER to exit"): Input()
CloseConsole()
EndIf