September 2017 Update

This commit is contained in:
Ingy döt Net 2017-09-23 10:01:46 +02:00
parent bba7bfd280
commit ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions

View file

@ -0,0 +1,8 @@
tfgame{⎕IO1
d?9
i
u[u{¨(0)}(i'1234567890')i]d[d]:'nope'
~/((~bi'1234567890')/i)'+-×÷()':'nope'
24i:'nope'
'Yeah!'
}

View file

@ -1,150 +0,0 @@
@set @dummy=0 /*
::24.bat
::
::Batch file implemetnation of the 24 Game where a player is given four random
::digits n, where 1 <= n <= 9, and needs to provide a simple arithmetic
::operation that does evaluate to 24.
::
::Please open the Batch File Directly to play...
@echo off
setlocal enabledelayedexpansion
title The 24 Game Batch File
cls
echo.
echo The 24 Game
echo.
echo Given four digits, provide a simple arithmetic expression
echo that evaluates to 24 using +,-,*,/.
echo.
echo Reminders (Please read):
echo.
echo 1. Type 'new' (NO quotes) - Fresh digits
echo 2. Type 'show' (NO quotes) - Show digits
echo 3. Type 'exit' (NO quotes) - Quit game
echo 4. Combining two digits as one number is NOT allowed.
echo 5. Use each digit only ONCE in expressions.
echo 6. Use ONLY the Parentheses as the groupting symbols.
echo 7. Do not make any digit Negative.
echo.
echo Why do someone wants to not follow the reminders? To trick me, right? ;)
echo.
pause
:NEW
set TRY=0
::Get four random digits
set /a "DIGIT_1=%RANDOM%%%9+1"
set /a "DIGIT_2=%RANDOM%%%9+1"
set /a "DIGIT_3=%RANDOM%%%9+1"
set /a "DIGIT_4=%RANDOM%%%9+1"
cls
echo.
echo The 24 Game
echo.
goto SHOW
::Main Program Loop
:MAIN
set /a TRY+=1
set ANSWER=
set "TMP_DIGIT_1=%DIGIT_1%"
set "TMP_DIGIT_2=%DIGIT_2%"
set "TMP_DIGIT_3=%DIGIT_3%"
set "TMP_DIGIT_4=%DIGIT_4%"
::Prompt for an answer
echo.
set /p ANSWER="Try %TRY%: "
::Determine if the player inputs a "good" try (input validation...)
if /i "!ANSWER!"=="NEW" goto NEW
if /i "!ANSWER!"=="SHOW" goto SHOW
if /i "!ANSWER!"=="EXIT" goto ABORT
set ANSWER=!ANSWER: =!
set DIGITS_USED=0&set COUNTER=0
:LOOP
set CURR_DIGIT=!ANSWER:~%COUNTER%,1!
if "!CURR_DIGIT!"=="%TMP_DIGIT_1%" (set "TMP_DIGIT_1=X"&goto NEXTCHARSCAN1)
if "!CURR_DIGIT!"=="%TMP_DIGIT_2%" (set "TMP_DIGIT_2=X"&goto NEXTCHARSCAN1)
if "!CURR_DIGIT!"=="%TMP_DIGIT_3%" (set "TMP_DIGIT_3=X"&goto NEXTCHARSCAN1)
if "!CURR_DIGIT!"=="%TMP_DIGIT_4%" (set "TMP_DIGIT_4=X"&goto NEXTCHARSCAN1)
if "!CURR_DIGIT!"=="" goto ALMOST
if "!CURR_DIGIT!"==")" goto SCANMORE
if "!CURR_DIGIT!"=="(" goto SCANMORE
if "!CURR_DIGIT!"=="+" goto NEXTCHARSCAN2
if "!CURR_DIGIT!"=="-" goto DONTALLOWNEGATIVES
if "!CURR_DIGIT!"=="*" goto NEXTCHARSCAN2
if "!CURR_DIGIT!"=="/" goto NEXTCHARSCAN2
goto ERROR_ICHAR_FOUND
:NEXTCHARSCAN1
set /a NEXT=%COUNTER%+1
set NEXT_CHAR=!ANSWER:~%NEXT%,1!
for /l %%w in (1,1,9) do (
if "!NEXT_CHAR!"=="%%w" goto ERROR_POSITION
)
goto :SCANMORE
:DONTALLOWNEGATIVES
set /a NEXT=%COUNTER%-1
if "%NEXT%"=="-1" goto ERROR_NEGA
set NEXT_CHAR=!ANSWER:~%NEXT%,1!
for /l %%z in (1,1,9) do (
if "!NEXT_CHAR!"=="%%z" goto NEXTCHARSCAN2
)
if "!NEXT_CHAR!"=="(" goto ERROR_NEGA
if "!NEXT_CHAR!"==")" goto NEXTCHARSCAN2
goto ERROR_NEGA
:NEXTCHARSCAN2
set /a NEXT=%COUNTER%+1
set NEXT_CHAR=!ANSWER:~%NEXT%,1!
for %%y in (+,-,/) do (
if "!NEXT_CHAR!"=="%%y" goto ERROR_TRICK
)
:SCANMORE
set /a "COUNTER+=1"&goto LOOP
:ALMOST
if not "%TMP_DIGIT_1%%TMP_DIGIT_2%%TMP_DIGIT_3%%TMP_DIGIT_4%"=="XXXX" goto ERROR_CHARS
::(SIGH) Input passed... Now, calculate and evaluate result
set "RESULT="
for /f "usebackq delims=" %%x in (`cscript //nologo //e:jscript "%~f0" "%ANSWER%" 2^>nul`) do set RESULT=%%x
::Wait... Input is STILL erroneous???
if "%RESULT%"=="" goto ERROR_SYNTAX
::YES!!! Correct Expression???
if "%RESULT%"=="24" goto END
::The Outputs
echo Wrong Answer [%RESULT% is not equal to 24.]&goto MAIN
:ERROR_CHARS
echo Invalid input [Please use all the digits above ONCE.]&goto MAIN
:ERROR_ICHAR_FOUND
echo Invalid input [An invalid character is found... C'mon...]&goto MAIN
:ERROR_SYNTAX
echo Invalid input [Syntax Error... Please answer seriously... I'm begging you...]&goto MAIN
:ERROR_POSITION
echo Invalid input [Sorry, digit concatenation is not allowed.]&goto MAIN
:ERROR_TRICK
echo Invalid input [Are you Playing the Game Seriously?]&goto MAIN
:ERROR_NEGA
echo Invalid input [Do not Make any Digit Negative.]&goto MAIN
:SHOW
echo Given digits: %DIGIT_1% %DIGIT_2% %DIGIT_3% %DIGIT_4%&goto MAIN
:END
echo Correct Input [Congratulations^^!]
echo.
echo Press any char key for a new game, or close this window to exit...
pause>nul
goto NEW
:ABORT
echo.
exit
::*/
WScript.echo(eval(WScript.arguments(0)));

View file

@ -1,96 +1,95 @@
#define system.
#define system'routines.
#define system'collections.
#define system'dynamic.
#define extensions.
import system'routines.
import system'collections.
import system'dynamic.
import extensions.
#class ExpressionTree
class ExpressionTree
{
#field theTree.
object theTree.
#constructor new : aLiteral
constructor new : aLiteral
[
#var aLevel := Integer new:0.
var aLevel := Integer new:0.
aLiteral run &each: ch
aLiteral forEach(:ch)
[
#var node := Dynamic new.
var node := DynamicStruct new.
ch =>
#43 ? [ node set &level:(aLevel + 1) set &operation:%add. ] // +
#45 ? [ node set &level:(aLevel + 1) set &operation:%subtract. ] // -
#42 ? [ node set &level:(aLevel + 2) set &operation:%multiply. ] // *
#47 ? [ node set &level:(aLevel + 2) set &operation:%divide. ] // /
#40 ? [ aLevel += 10. ^ $self. ] // (
#41 ? [ aLevel -= 10. ^ $self. ] // )
$43 [ node set level(aLevel + 1); set operation:%add ]; // +
$45 [ node set level(aLevel + 1); set operation:%subtract ]; // -
$42 [ node set level(aLevel + 2); set operation:%multiply ]; // *
$47 [ node set level(aLevel + 2); set operation:%divide ]; // /
$40 [ aLevel append int:10. ^ $self ]; // (
$41 [ aLevel reduce int:10. ^ $self ]; // )
! [
node set &leaf:(ch literal toReal) set &level:((aLevel + 3)).
node set leaf(ch literal; toReal); set level(aLevel + 3).
].
($nil == theTree)
? [ theTree := node. ]
! [
(theTree level >= node level)
? [
node set &left:theTree set &right:$nil.
if ($nil == theTree)
[ theTree := node ];
[
if (theTree level >= node level)
[
node set left:theTree; set right:$nil.
theTree := node.
theTree := node
];
[
var aTop := theTree.
while (($nil != aTop right)and:$(aTop right; level < node level))
[ aTop := aTop right ].
node set left(aTop right); set right:$nil.
aTop set right:node
]
! [
#var aTop := theTree.
#loop (($nil != aTop right)and:[aTop right level < node level] )
? [ aTop := aTop right. ].
node set &left:(aTop right) set &right:$nil.
aTop set &right:node.
].
].
].
]
]
]
#method eval : aNode
eval : aNode
[
(aNode if &leaf)
? [ ^ aNode leaf. ]
! [
#var aLeft := $self eval:(aNode left).
#var aRight := $self eval:(aNode right).
if (aNode containsProperty:%leaf)
[ ^ aNode leaf ];
[
var aLeft := $self eval:(aNode left).
var aRight := $self eval:(aNode right).
^ aLeft::(aNode operation) eval:aRight.
^ aLeft~(aNode operation) eval:aRight
]
]
#method value
value
<= eval:theTree.
#method readLeaves : aList &at:aNode
readLeaves : aList at:aNode
[
($nil == aNode)
? [ #throw InvalidArgumentException new. ].
if ($nil == aNode)
[ InvalidArgumentException new; raise ].
(aNode if &leaf)
? [ aList += aNode leaf. ]
! [
$self readLeaves:aList &at:(aNode left).
$self readLeaves:aList &at:(aNode right).
if (aNode containsProperty:%leaf)
[ aList append(aNode leaf) ];
[
$self readLeaves:aList at(aNode left).
$self readLeaves:aList at(aNode right).
].
]
#method readLeaves : aList
<= readLeaves:aList &at:theTree.
readLeaves : aList
<= readLeaves:aList at:theTree.
}
#class TwentyFourGame
class TwentyFourGame
{
#field theNumbers.
object theNumbers.
#constructor new
constructor new
[
$self newPuzzle.
]
#method newPuzzle
newPuzzle
[
theNumbers := (
1 + randomGenerator eval:9,
@ -99,75 +98,76 @@
1 + randomGenerator eval:9).
]
#method help
help
[
console
writeLine:"------------------------------- Instructions ------------------------------"
writeLine:"Four digits will be displayed."
writeLine:"Enter an equation using all of those four digits that evaluates to 24"
writeLine:"Only * / + - operators and () are allowed"
writeLine:"Digits can only be used once, but in any order you need."
writeLine:"Digits cannot be combined - i.e.: 12 + 12 when given 1,2,2,1 is not allowed"
writeLine:"Submit a blank line to skip the current puzzle."
writeLine:"Type 'q' to quit"
writeLine
writeLine:"Example: given 2 3 8 2, answer should resemble 8*3-(2-2)"
writeLine:"------------------------------- --------------------------------------------".
printLine:"------------------------------- Instructions ------------------------------";
printLine:"Four digits will be displayed.";
printLine:"Enter an equation using all of those four digits that evaluates to 24";
printLine:"Only * / + - operators and () are allowed";
printLine:"Digits can only be used once, but in any order you need.";
printLine:"Digits cannot be combined - i.e.: 12 + 12 when given 1,2,2,1 is not allowed";
printLine:"Submit a blank line to skip the current puzzle.";
printLine:"Type 'q' to quit";
writeLine;
printLine:"Example: given 2 3 8 2, answer should resemble 8*3-(2-2)";
printLine:"------------------------------- --------------------------------------------".
]
#method prompt
prompt
[
theNumbers run &each: n [ console writeLiteral:n:" ". ].
theNumbers forEach(:n) [ console print(n," ") ].
console write:": ".
console print:": "
]
#method resolve : aLine
resolve : aLine
[
#var exp := ExpressionTree new:aLine.
var exp := ExpressionTree new:aLine.
#var Leaves := ArrayList new.
var Leaves := ArrayList new.
exp readLeaves:Leaves.
(Leaves ascendant equal &indexable:(theNumbers ascendant))
! [ console writeLine:"Invalid input. Enter an equation using all of those four digits. Try again.". ^ $self. ].
ifnot (Leaves ascendant; sequenceEqual(theNumbers ascendant))
[ console printLine:"Invalid input. Enter an equation using all of those four digits. Try again.". ^ $self ].
#var aResult := exp value.
(aResult == 24)
? [
console writeLine:"Good work. ":aLine:"=":aResult.
var aResult := exp value.
if (aResult == 24)
[
console printLine("Good work. ",aLine,"=",aResult).
$self newPuzzle.
]
! [ console writeLine:"Incorrect. ":aLine:"=":aResult. ].
];
[ console printLine("Incorrect. ",aLine,"=",aResult) ]
]
}
#class(extension) gameOp
extension gameOp
{
#method playRound : aLine
playRound : aLine
[
(aLine == "q")
? [ ^ false. ]
! [
(aLine == "")
? [ console writeLine:"Skipping this puzzle". self newPuzzle. ]
! [
self resolve:aLine
| if &Error: e
[
console writeLine:"An error occurred. Check your input and try again.".
].
if (aLine == "q")
[ ^ false ];
[
if (aLine == "")
[ console printLine:"Skipping this puzzle". self newPuzzle. ];
[
try(self resolve:aLine)
{
on(Exception e) [
console writeLine:"An error occurred. Check your input and try again."
]
}
].
^ true.
^ true
].
]
}
#symbol program =
program =
[
#var aGame := TwentyFourGame new help.
var aGame := TwentyFourGame new; help.
#loop (aGame prompt playRound:(console readLine)) ? [].
while (aGame prompt; playRound(console readLine)) [].
].

View file

@ -1,43 +1,53 @@
import Char
import Control.Monad.Error
import Data.List
import IO
import Maybe
import Random
import Data.List (sort)
import Data.Char (isDigit)
import Data.Maybe (fromJust)
import Control.Monad (foldM)
import System.Random (randomRs, getStdGen)
import System.IO (hSetBuffering, stdout, BufferMode(NoBuffering))
main = do
hSetBuffering stdout NoBuffering
mapM_ putStrLn
[ "THE 24 GAME\n"
, "Given four digits in the range 1 to 9"
, "Use the +, -, *, and / operators in reverse polish notation"
, "To show how to make an answer of 24.\n"
]
digits <- liftM (sort . take 4 . randomRs (1,9)) getStdGen :: IO [Int]
putStrLn ("Your digits: " ++ intercalate " " (map show digits))
guessLoop digits
where guessLoop digits =
putStr "Your expression: " >>
liftM (processGuess digits . words) getLine >>=
either (\m -> putStrLn m >> guessLoop digits) putStrLn
hSetBuffering stdout NoBuffering
mapM_
putStrLn
[ "THE 24 GAME\n"
, "Given four digits in the range 1 to 9"
, "Use the +, -, *, and / operators in reverse polish notation"
, "To show how to make an answer of 24.\n"
]
digits <- fmap (sort . take 4 . randomRs (1, 9)) getStdGen :: IO [Int]
putStrLn ("Your digits: " ++ unwords (fmap show digits))
guessLoop digits
where
guessLoop digits =
putStr "Your expression: " >> fmap (processGuess digits . words) getLine >>=
either (\m -> putStrLn m >> guessLoop digits) putStrLn
processGuess _ [] = Right ""
processGuess digits xs | not $ matches = Left "Wrong digits used"
where matches = digits == (sort . map read $ filter (all isDigit) xs)
processGuess _ [] = Right ""
processGuess digits xs
| not matches = Left "Wrong digits used"
where
matches = digits == (sort . fmap read $ filter (all isDigit) xs)
processGuess digits xs = calc xs >>= check
where check 24 = Right "Correct"
check x = Left (show (fromRational (x :: Rational)) ++ " is wrong")
where
check 24 = Right "Correct"
check x = Left (show (fromRational (x :: Rational)) ++ " is wrong")
-- A Reverse Polish Notation calculator with full error handling
calc xs = foldM simplify [] xs >>= \ns -> (case ns of
[n] -> Right n
_ -> Left "Too few operators")
calc xs =
foldM simplify [] xs >>=
\ns ->
(case ns of
[n] -> Right n
_ -> Left "Too few operators")
simplify (a:b:ns) s | isOp s = Right ((fromJust $ lookup s ops) b a : ns)
simplify _ s | isOp s = Left ("Too few values before " ++ s)
simplify ns s | all isDigit s = Right (fromIntegral (read s) : ns)
simplify _ s = Left ("Unrecognized symbol: " ++ s)
simplify (a:b:ns) s
| isOp s = Right ((fromJust $ lookup s ops) b a : ns)
simplify _ s
| isOp s = Left ("Too few values before " ++ s)
simplify ns s
| all isDigit s = Right (fromIntegral (read s) : ns)
simplify _ s = Left ("Unrecognized symbol: " ++ s)
isOp v = elem v $ map fst ops
isOp v = elem v $ fmap fst ops
ops = [("+",(+)), ("-",(-)), ("*",(*)), ("/",(/))]
ops = [("+", (+)), ("-", (-)), ("*", (*)), ("/", (/))]

View file

@ -1,6 +1,6 @@
package game24
import java.util.*
import java.util.Random
import java.util.Scanner
import java.util.Stack
internal object Game24 {
fun run() {
@ -10,9 +10,9 @@ internal object Game24 {
print("> ")
val s = Stack<Float>()
var total: Long = 0
var total = 0L
val cin = Scanner(System.`in`)
for (c in cin.nextLine())
for (c in cin.nextLine()) {
when (c) {
in '0'..'9' -> {
val d = c - '0'
@ -20,9 +20,11 @@ internal object Game24 {
s += d.toFloat()
}
else ->
if ("+/-*".indexOf(c) != -1)
if ("+/-*".indexOf(c) != -1) {
s += c.applyOperator(s.pop(), s.pop())
}
}
}
when {
tally(digits) != total ->
@ -34,7 +36,7 @@ internal object Game24 {
}
}
fun Char.applyOperator(a: Float, b: Float) = when (this) {
private fun Char.applyOperator(a: Float, b: Float) = when (this) {
'+' -> a + b
'-' -> b - a
'*' -> a * b
@ -42,7 +44,7 @@ internal object Game24 {
else -> Float.NaN
}
fun tally(a: List<Int>): Long = a.reduce({ t, i -> t + (1 shl (i * 5)) }).toLong()
private fun tally(a: List<Int>): Long = a.reduce({ t, i -> t + (1 shl (i * 5)) }).toLong()
private val target = 24
}

View file

@ -0,0 +1,33 @@
alias 24 {
dialog -m 24-Game 24-Game
}
dialog 24-Game {
title "24-Game"
size -1 -1 100 70
option dbu
text "", 1, 29 7 42 8
text "Equation", 2, 20 21 21 8
edit "", 3, 45 20 40 10
text "Status", 4, 10 34 80 8, center
button "Calculate", 5, 5 45 40 20
button "New", 6, 57 47 35 15
}
on *:DIALOG:24-Game:init:*: {
did -o 24-Game 1 1 Numbers: $rand(1,9) $rand(1,9) $rand(1,9) $rand(1,9)
}
on *:DIALOG:24-Game:sclick:*: {
if ($did == 5) {
if ($regex($did(3),/^[ (]*\d *[-+*/][ (]*\d[ ()]*[-+*/][ ()]*\d[ )]*[-+*/] *\d[ )]*$/)) && ($sorttok($regsubex($did(3),/[^\d]+/g,$chr(32)),32) == $sorttok($remove($did(1),Numbers:),32)) {
did -o 24-Game 4 1 $iif($calc($did(3)) == 24,Correct,Wrong)
}
else {
did -o 24-Game 4 1 Wrong Numbers or Syntax
}
}
elseif ($did == 6) {
did -o 24-Game 1 1 Numbers: $rand(1,9) $rand(1,9) $rand(1,9) $rand(1,9)
}
}

View file

@ -0,0 +1,80 @@
24Game
k number, operator, bracket
; generate 4 random numbers each between 1 & 9
; duplicates allowed!
s n1=$r(9)+1, n2=$r(9)+1, n3=$r(9)+1, n4=$r(9)+1
; save a copy of them so that we can keep restarting
; if the user gets it wrong
s s1=n1,s2=n2,s3=n3,s4=n4
Question
s (numcount,opcount,lbrackcount,rbrackcount)=0
; restart with the random numbers already found
s n1=s1,n2=s2,n3=s3,n4=s4
w !,"Enter an arithmetic expression that evaluates to 24 using (",
n1," ",n2," ",n3," ",n4,"): "
r !,expr
q:expr=""
; validate numbers and operators
s error=""
f n=1:1:$l(expr) {
s char=$e(expr,n)
if char?1n {
s number($i(numcount))=char
w !
zw char
}
elseif char?1(1"*",1"/",1"+",1"-") {
s operator($i(opcount))=char
}
elseif char?1"(" {
s bracket($i(lbrackcount))=char
}
elseif char?1")" {
s bracket($i(rbrackcount))=char
}
else {
s error="That ain't no character I wanted to see"
q
}
}
if error'="" w error g Question
if numcount'=4 {
w "Does not have 4 numbers, do it again."
g Question
}
s error=""
f n=1:1:4 {
if number(n)=n1 {
s n1="dont use again" continue
}
if number(n)=n2 {
s n2="dont use again" continue
}
if number(n)=n3 {
s n3="dont use again" continue
}
if number(n)=n4 {
s n4="dont use again" continue
}
s error="Numbers entered do not match all of the randomly generated numbers."
q
}
if error'="" {
w error
g Question
}
if opcount'=3 {
w "Does not have 3 operators."
g Question
}
if lbrackcount'=rbrackcount {
w "brackets must be in pairs."
g Question
}
x "s x="_expr
if x'=24 {
w !,"Answer does not = 24"
g Question
}
w x
q

View file

@ -1,8 +1,11 @@
import math, strutils, algorithm, sequtils
from random import randomize, random
from strutils import Whitespace
from algorithm import sort
from sequtils import deduplicate
randomize()
template newSeqWith(len: int, init: expr): expr =
var result {.gensym.} = newSeq[type(init)](len)
template newSeqWith(len: int, init: untyped): untyped =
var result = newSeq[type(init)](len)
for i in 0 .. <len:
result[i] = init
result
@ -14,7 +17,7 @@ var
echo "Make 24 with the digits: ", problem
template op(c): stmt =
template op(c) =
let a = stack.pop
stack.add c(stack.pop, a)

View file

@ -0,0 +1,149 @@
redef class Char
fun is_op: Bool do return "-+/*".has(self)
end
# Get `numbers` and `operands` from string `operation` collect with `gets` in `main` function
# Fill `numbers` and `operands` array with previous extraction
fun exportation(operation: String, numbers: Array[Int], operands: Array[Char]) do
var previous_char: nullable Char = null
var number: nullable Int = null
var negative = false
for i in operation.length.times do
var current_char = operation[i]
var current_int = current_char.to_i
if (previous_char == null or previous_char.is_op) and current_char == '-' then
negative = true
continue
end
if current_char.is_digit then
if number == null then
number = current_int
else
number = number * 10 + current_int
end
end
if negative and (current_char.is_op or i == operation.length - 1) then
number = number - number * 2
negative = false
end
if (current_char.is_op or i == operation.length - 1) and number != null then
numbers.add(number)
number = null
end
if not negative and current_char.is_op then
operands.add(current_char)
end
previous_char = current_char
end
# Update `numbers` and `operands` array in main function with pointer
end
# Create random numbers between 1 to 9
fun random: Array[Int] do
return [for i in 4.times do 1 + 9.rand]
end
# Make mathematical operation with `numbers` and `operands` and add the operation result into `random_numbers`
fun calculation(random_numbers, numbers: Array[Int], operands: Array[Char]) do
var number = 0
var temp_numbers = numbers.clone
while temp_numbers.length > 1 do
var operand = operands.shift
var a = temp_numbers.shift
var b = temp_numbers.shift
if operand == '+' then number = a + b
if operand == '-' then number = a - b
if operand == '*' then number = a * b
if operand == '/' then number = a / b
temp_numbers.unshift(number)
end
if number != 0 then random_numbers.add(number)
end
# Check if used `numbers` exist in the `random_numbers` created
fun numbers_exists(random_numbers, numbers: Array[Int]): Bool do
for number in numbers do
if not random_numbers.count(number) >= numbers.count(number) then return false
end
return true
end
# Remove `numbers` when they are used
fun remove_numbers(random_numbers, numbers: Array[Int]) do
for number in numbers do random_numbers.remove(number)
end
# Check if the mathematical `operation` is valid
fun check(operation: String): Bool do
var previous_char: nullable Char = null
var next_char: nullable Char = null
var next_1_char: nullable Char = null
for i in operation.length.times do
var current_char = operation[i]
if i + 1 < operation.length then
next_char = operation[i + 1]
if i + 2 < operation.length then
next_1_char = operation[i + 2]
else
next_1_char = null
end
else
next_char = null
end
if not current_char.is_op and not current_char.is_digit then return false
if next_char == null and current_char.is_op then return false
if previous_char == null then
if next_char == null or next_1_char == null then return false
if current_char == '-' and not next_char.is_digit then return false
if current_char != '-' and not current_char.is_digit then return false
else
if next_char != null then
if previous_char.is_digit and current_char.is_op and
not (next_char == '-' and next_1_char != null and
next_1_char.is_digit or next_char.is_digit) then
return false
end
end
end
previous_char = current_char
end
return true
end
var random_numbers = new Array[Int]
var operation = ""
random_numbers = random
while not random_numbers.has(24) and random_numbers.length > 1 do
var numbers = new Array[Int]
var operands = new Array[Char]
print "numbers: " + random_numbers.join(", ")
operation = gets
if check(operation) then
exportation(operation, numbers, operands)
if numbers_exists(random_numbers, numbers) then
calculation(random_numbers, numbers, operands)
remove_numbers(random_numbers, numbers)
else
print "NUMBERS ERROR!"
end
else
print "STRING ERROR!"
end
end
if random_numbers.has(24) then print "CONGRATULATIONS" else print "YOU LOSE"

View file

@ -0,0 +1,33 @@
import random, re
chars = ["(",")","/","+","-","*"]
while True:
charsandints, ints = [], []
for x in range(4):
ints.append(str(random.randrange(1,10)))
charsandints = chars + ints
print "Numbers are:", ints
guess = raw_input("Enter your guess:")
if guess.lower() == "q":
break
elif guess.lower() == "|":
pass
else:
flag = True
for a in guess:
if a not in charsandints or guess.count(a) > charsandints.count(a):
flag = False
if re.search("\d\d", guess):
print "You cannot combine digits."
break
if flag:
print "Your result is: ", eval(guess)
if eval(guess) == 24:
print "You won"
break
else:
print "You lost"
break
else:
print "You cannot use anthing other than", charsandints
break
print "Thanks for playing"

View file

@ -1,17 +1,14 @@
/*REXX program supports a human to play the game of 24 (twenty-four) with error checking*/
numeric digits 15 /*allow more leeway when computing #s. */
parse arg yyy /*get the optional arguments from C.L. */
yyy = space(yyy, 0) /*remove extraneous blanks from YYY. */
parse arg yyy; yyy=space(yyy, 0) /*get optional CL args; elide blanks. */
parse var yyy start '-' fin /*get the START and FINish (maybe). */
fin = word(fin start, 1) /*if no FINish specified, use START.*/
ops = '+-*/' ; Lops = length(0ps) /*define the legal arithmetic operators*/
groupSym = '()[]{}' /*legal grouping symbols for this game.*/
indent = left('', 30) /*used to indent display of solutions. */
Lpar = '(' ; Rpar = ')' /*strings to make the output prettier.*/
digs = 123456789 /*numerals (digits) that can be used. */
show = 1 /*flag used show solutions (0 = not). */
do j=1 for Lops; @.j=substr(ops,j,1) /*define a version for fast execution. */
end /*j*/
fin= word(fin start, 1) /*if no FINish specified, use START.*/
ops= '+-*/' ; Lops= length(0ps) /*define the legal arithmetic operators*/
groupSym= '()[]{}' /*legal grouping symbols for this game.*/
pad= left('', 30) /*used to indent display of solutions. */
Lpar= '(' ; Rpar= ')' /*strings to make the output prettier.*/
digs= 123456789 /*numerals (digits) that can be used. */
show= 1 /*flag used show solutions (0 = not). */
do j=1 for Lops; @.j=substr(ops,j,1); end /*for fast execution. */
signal on syntax /*enable program to trap syntax errors.*/
if yyy\=='' then do; sols=solve(start, fin) /*solve from START ───► FINish. */
if sols <0 then exit 13 /*Was there a problem with the input? */
@ -30,11 +27,10 @@ $.=0
do j=1 for Lrrrr; _=substr(rrrr,j,1) /*digit count for each digit in RRRR. */
$._= countDigs(rrrr, _) /*define the count for this digit. */
end /*j*/ /* [↑] counts duplicates twice, no harm*/
__ = copies('', 9) /*used for output highlighting. */
__ = copies('', 9) /*used for output highlighting. */
prompt= 'Using the digits ' rrrr", enter an expression that equals 24 (or QUIT):"
/* [↓] ITERATE needs a variable name.*/
do prompter=0; say; say __ prompt /*display blank line and the prompt (P)*/
do prompter=0 by 0; say; say __ prompt /*display blank line and the prompt (P)*/
pull y; y=space(y, 0) /*get Y from CL, then remove all blanks*/
if abbrev('QUIT', y, 1) then exit 0 /*Does the user want to quit this game?*/
_v=verify(y, digs || ops || groupSym); a=substr(y, max(1,_v), 1)
@ -43,33 +39,29 @@ prompt= 'Using the digits ' rrrr", enter an expression that equals 24 (or
if pos('//', y) then do; call ger "invalid // operator"; iterate; end
Ly=length(y)
if y=='' then do; call validate y; iterate; end
do j=1 for Ly-1; if \datatype(substr(y, j , 1), 'W') then iterate
if \datatype(substr(y, j+1, 1), 'W') then iterate
call ger 'invalid use of "digit abuttal".'
iterate prompter
end /*j*/
yd=countDigs(y, digs) /*count of the digits 1──►9 (123456789)*/
do j=1 for Ly-1; if \datatype(substr(y,j ,1), 'W') then iterate
if \datatype(substr(y,j+1,1), 'W') then iterate
call ger 'invalid use of "digit abuttal".'
iterate prompter
end /*j*/
yd=countDigs(y,digs) /*count of the digits 1──►9 (123456789)*/
if yd<4 then do; call ger 'not enough digits entered.'; iterate /*prompter*/; end
if yd>4 then do; call ger 'too many digits entered.' ; iterate /*prompter*/; end
do j=1 for 9; if $.j==0 then iterate
_d=countDigs(y, j); if $.j==_d then iterate
if _d<$.j then call ger 'not enough' j "digits, must be" $.j
else call ger 'too many' j "digits, must be" $.j
iterate prompter
end /*j*/
do j=1 for 9; if $.j==0 then iterate
_d=countDigs(y, j); if $.j==_d then iterate
if _d<$.j then call ger 'not enough' j "digits, must be" $.j
else call ger 'too many' j "digits, must be" $.j
iterate prompter
end /*j*/
interpret 'ans=' translate(y, '()()', "[]{}"); ans=ans/1
if ans==24 then leave prompter; say 'incorrect, ' y"="ans
end /*prompter*/
say; say center('', 79)
say center(' ', 79)
say center(' congratulations ! ', 79)
say center(' ', 79)
say center('', 79)
say; say center('', 79)
say center(' ', 79)
say center(' congratulations ! ', 79)
say center(' ', 79)
say center('', 79)
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
countDigs: arg ?; return length(?) - length(space(translate(?, , arg(2)), 0))
@ -79,18 +71,12 @@ s: if arg(1)==1 then return ''; return "s" /*a simple plu
syntax: call ger 'illegal syntax in' y; exit
/*──────────────────────────────────────────────────────────────────────────────────────*/
solve: parse arg ssss, ffff /*parse the argument passed to SOLVE. */
if ffff=='' then ffff=ssss /*create a FFFF if necessary. */
if \validate(ssss) then return -1 /*validate the SSSS field. */
if \validate(ffff) then return -1 /* " " FFFF " */
#=0 /*number of found solutions (so far). */
!.=0 /*a method to hold unique expressions. */
/*alternative: indent=copies(' ',30) */
if ffff=='' then ffff=ssss /*create a FFFF if necessary. */
if \validate(ssss) | \validate(ffff) then return -1 /*validate SSSS & FFFF*/
!.=0; #=0 /*holds unique expressions; # solutions*/
do g=ssss to ffff /*process a (possible) range of values.*/
if pos(0, g)\==0 then iterate /*ignore values with zero in them. */
do j=1 for 4; g.j=substr(g, j, 1) /*define a version for fast execution. */
end /*j*/
do j=1 for 4; g.j=substr(g,j,1); end /*for fast execution.*/
do i =1 for Lops /*insert an operator after 1st number. */
do j =1 for Lops /* " " " " 2nd " */
do k =1 for Lops /* " " " " 3rd " */
@ -108,14 +94,13 @@ solve: parse arg ssss, ffff /*parse the argument passed to
interpret 'x=' e /*have REXX do all the heavy lifting */
if x\=24 then iterate /*Is the result incorrect? Try again. */
#=#+1 /*bump number of found solutions. */
if show then say indent 'a solution:' translate(yyyE, '][', ")(")
if show then say pad 'a solution for' g": " translate(yyyE,'][',")(")
end /*n*/ /* [↑] display a (single) solution. */
end /*m*/
end /*k*/
end /*j*/
end /*i*/
end /*g*/
return #
/*──────────────────────────────────────────────────────────────────────────────────────*/
sort: procedure; parse arg #; L=length(#); !.= /*this is a modified bin sort.*/
@ -130,5 +115,4 @@ validate: parse arg y; OK=1; _v=verify(y,digs); DE='digits entered, there must
when pos(0,y)\==0 then call ger "can't use the digit 0 (zero)."
when _v\==0 then call ger "illegal character: " substr(y, _v, 1)
otherwise nop
end /*select*/
return OK
end /*select*/; return OK

View file

@ -1,25 +0,0 @@
changestr: Procedure
/* change needle to newneedle in haystack (as often as specified */
/* or all of them if count is omitted */
Parse Arg needle,haystack,newneedle,count
If count>'' Then Do
If count=0 Then Do
Say 'chstr count must be > 0'
Signal Syntax
End
End
res=""
changes=0
px=1
do Until py=0
py=pos(needle,haystack,px)
if py>0 then Do
res=res||substr(haystack,px,py-px)||newneedle
px=py+length(needle)
changes=changes+1
If count>'' Then
If changes=count Then Leave
End
end
res=res||substr(haystack,px)
Return res

View file

@ -1,34 +1,34 @@
const digits = (1..9 -> pick(4));
const grammar = Regex.new(
const digits = (1..9 -> pick(4))
const grammar = Regex(
'^ (?&exp) \z
(?(DEFINE)
(?<exp> ( (?&term) (?&op) (?&term) )+ )
(?<term> \( (?&exp) \) | [' + digits.join + '])
(?<op> [-+*/] )
(?<op> [\-+*/] )
)', 'x'
);
 
say "Here are your digits: #{digits.join(' ')}";
 
)
say "Here are your digits: #{digits.join(' ')}"
loop {
var input = Sys.scanln("Expression: ");
 
var expr = input;
expr -= /\s+/g; # remove all whitespace
 
input == 'q' && (
say "Goodbye. Sorry you couldn't win.";
break;
);
 
var given_digits = digits.map{.to_s}.sort.join;
var entry_digits = input.scan(/\d/).sort.join;
 
if ((given_digits != entry_digits) || (expr !~ grammar)) {
say "That's not valid";
next;
var input = read("Expression: ", String)
var expr = input
expr -= /\s+/g # remove all whitespace
if (input == 'q') {
say "Goodbye. Sorry you couldn't win."
break
}
 
var given_digits = digits.map{.to_s}.sort.join
var entry_digits = input.scan(/\d/).sort.join
if ((given_digits != entry_digits) || (expr !~ grammar)) {
say "That's not valid"
next
}
given(var n = eval(input)) {
when (24) { say "You win!"; break }
default { say "Sorry, your expression is #{n}, not 24" }

View file

@ -0,0 +1,296 @@
BEGIN
CLASS EXPR;
BEGIN
REAL PROCEDURE POP;
BEGIN
IF STACKPOS > 0 THEN
BEGIN STACKPOS := STACKPOS - 1; POP := STACK(STACKPOS); END;
END POP;
PROCEDURE PUSH(NEWTOP); REAL NEWTOP;
BEGIN
STACK(STACKPOS) := NEWTOP;
STACKPOS := STACKPOS + 1;
END PUSH;
REAL PROCEDURE CALC(OPERATOR, ERR); CHARACTER OPERATOR; LABEL ERR;
BEGIN
REAL X, Y; X := POP; Y := POP;
IF OPERATOR = '+' THEN PUSH(Y + X)
ELSE IF OPERATOR = '-' THEN PUSH(Y - X)
ELSE IF OPERATOR = '*' THEN PUSH(Y * X)
ELSE IF OPERATOR = '/' THEN BEGIN
IF X = 0 THEN
BEGIN
EVALUATEDERR :- "DIV BY ZERO";
GOTO ERR;
END;
PUSH(Y / X);
END
ELSE
BEGIN
EVALUATEDERR :- "UNKNOWN OPERATOR";
GOTO ERR;
END
END CALC;
PROCEDURE READCHAR(CH); NAME CH; CHARACTER CH;
BEGIN
IF T.MORE THEN CH := T.GETCHAR ELSE CH := EOT;
END READCHAR;
PROCEDURE SKIPWHITESPACE(CH); NAME CH; CHARACTER CH;
BEGIN
WHILE (CH = SPACE) OR (CH = TAB) OR (CH = CR) OR (CH = LF) DO
READCHAR(CH);
END SKIPWHITESPACE;
PROCEDURE BUSYBOX(OP, ERR); INTEGER OP; LABEL ERR;
BEGIN
CHARACTER OPERATOR;
REAL NUMBR;
BOOLEAN NEGATIVE;
SKIPWHITESPACE(CH);
IF OP = EXPRESSION THEN
BEGIN
NEGATIVE := FALSE;
WHILE (CH = '+') OR (CH = '-') DO
BEGIN
IF CH = '-' THEN NEGATIVE := NOT NEGATIVE;
READCHAR(CH);
END;
BUSYBOX(TERM, ERR);
IF NEGATIVE THEN
BEGIN
NUMBR := POP; PUSH(0 - NUMBR);
END;
WHILE (CH = '+') OR (CH = '-') DO
BEGIN
OPERATOR := CH; READCHAR(CH);
BUSYBOX(TERM, ERR); CALC(OPERATOR, ERR);
END;
END
ELSE IF OP = TERM THEN
BEGIN
BUSYBOX(FACTOR, ERR);
WHILE (CH = '*') OR (CH = '/') DO
BEGIN
OPERATOR := CH; READCHAR(CH);
BUSYBOX(FACTOR, ERR); CALC(OPERATOR, ERR)
END
END
ELSE IF OP = FACTOR THEN
BEGIN
IF (CH = '+') OR (CH = '-') THEN
BUSYBOX(EXPRESSION, ERR)
ELSE IF (CH >= '0') AND (CH <= '9') THEN
BUSYBOX(NUMBER, ERR)
ELSE IF CH = '(' THEN
BEGIN
READCHAR(CH);
BUSYBOX(EXPRESSION, ERR);
IF CH = ')' THEN READCHAR(CH) ELSE GOTO ERR;
END
ELSE GOTO ERR;
END
ELSE IF OP = NUMBER THEN
BEGIN
NUMBR := 0;
WHILE (CH >= '0') AND (CH <= '9') DO
BEGIN
NUMBR := 10 * NUMBR + RANK(CH) - RANK('0'); READCHAR(CH);
END;
IF CH = '.' THEN
BEGIN
REAL FAKTOR;
READCHAR(CH);
FAKTOR := 10;
WHILE (CH >= '0') AND (CH <= '9') DO
BEGIN
NUMBR := NUMBR + (RANK(CH) - RANK('0')) / FAKTOR;
FAKTOR := 10 * FAKTOR;
READCHAR(CH);
END;
END;
PUSH(NUMBR);
END;
SKIPWHITESPACE(CH);
END BUSYBOX;
BOOLEAN PROCEDURE EVAL(INP); TEXT INP;
BEGIN
EVALUATEDERR :- NOTEXT;
STACKPOS := 0;
T :- COPY(INP.STRIP);
READCHAR(CH);
BUSYBOX(EXPRESSION, ERRORLABEL);
! OUTTEXT("T = '");
! OUTTEXT(T);
! OUTTEXT("'");
! OUTTEXT(", T.POS = ");
! OUTINT(T.POS, 0);
! OUTTEXT(", STACKPOS = ");
! OUTINT(STACKPOS, 0);
! OUTTEXT(", T.MORE = ");
! OUTCHAR(IF T.MORE THEN 'T' ELSE 'F');
! OUTTEXT(", CH = ");
! OUTCHAR(CH);
! OUTIMAGE;
IF NOT T.MORE AND STACKPOS = 1 AND CH = EOT THEN
BEGIN
EVALUATED := POP;
EVAL := TRUE;
GOTO NOERRORLABEL;
END;
ERRORLABEL:
EVAL := FALSE;
IF EVALUATEDERR = NOTEXT THEN
EVALUATEDERR :- "INVALID EXPRESSION: " & INP;
NOERRORLABEL:
END EVAL;
REAL PROCEDURE RESULT;
RESULT := EVALUATED;
TEXT PROCEDURE ERR;
ERR :- EVALUATEDERR;
TEXT T;
INTEGER EXPRESSION;
INTEGER TERM;
INTEGER FACTOR;
INTEGER NUMBER;
CHARACTER TAB;
CHARACTER LF;
CHARACTER CR;
CHARACTER SPACE;
CHARACTER EOT;
CHARACTER CH;
REAL ARRAY STACK(0:31);
INTEGER STACKPOS;
REAL EVALUATED;
TEXT EVALUATEDERR;
EXPRESSION := 1;
TERM := 2;
FACTOR := 3;
NUMBER := 4;
TAB := CHAR(9);
LF := CHAR(10);
CR := CHAR(13);
SPACE := CHAR(32);
EOT := CHAR(0);
END EXPR;
INTEGER ARRAY DIGITS(1:4);
INTEGER SEED, I;
REF(EXPR) E;
E :- NEW EXPR;
OUTTEXT("ENTER RANDOM SEED: ");
OUTIMAGE;
SEED := ININT;
FOR I := 1 STEP 1 UNTIL 4 DO DIGITS(I) := RANDINT(0, 9, SEED);
L: BEGIN
INTEGER ARRAY DIGITSUSED(0:9);
INTEGER ARRAY DIGITSTAKEN(0:9);
CHARACTER C, LASTC;
TEXT INP;
LASTC := CHAR(0);
OUTTEXT("MAKE 24 USING THESE DIGITS: ");
FOR I := 1 STEP 1 UNTIL 4 DO
BEGIN
OUTINT(DIGITS(I), 2);
DIGITSUSED( DIGITS(I) ) := DIGITSUSED( DIGITS(I) ) + 1;
END;
OUTIMAGE;
INIMAGE;
INP :- COPY(SYSIN.IMAGE.STRIP);
OUTIMAGE;
WHILE INP.MORE DO
BEGIN
C := INP.GETCHAR;
IF (C >= '0') AND (C <= '9') THEN
BEGIN
INTEGER D;
IF (LASTC >= '0') AND (LASTC <= '9') THEN
BEGIN
OUTTEXT("NUMBER HAS TOO MANY DIGITS: ");
OUTCHAR(LASTC);
OUTCHAR(C);
OUTIMAGE;
GOTO L;
END;
D := RANK(C) - RANK('0');
DIGITSTAKEN(D) := DIGITSTAKEN(D) + 1;
END
ELSE IF NOT ((C = '+') OR (C = '-') OR (C = '/') OR (C = '*') OR
(C = ' ') OR (C = '(') OR (C = ')')) THEN
BEGIN
OUTTEXT("ILLEGAL INPUT CHARACTER: ");
OUTCHAR(C);
OUTIMAGE;
GOTO L;
END;
LASTC := C;
END;
FOR I := 0 STEP 1 UNTIL 9 DO
BEGIN
IF DIGITSUSED(I) <> DIGITSTAKEN(I) THEN
BEGIN
OUTTEXT("NOT THE SAME DIGITS.");
OUTIMAGE;
GOTO L;
END;
END;
IF E.EVAL(INP) THEN
BEGIN
OUTTEXT("RESULT IS ");
OUTFIX(E.RESULT, 4, 10);
OUTIMAGE;
OUTTEXT(IF ABS(E.RESULT - 24) < 0.001
THEN "YOU WIN"
ELSE "YOU LOOSE");
OUTIMAGE;
END
ELSE
BEGIN
OUTTEXT(E.ERR);
OUTIMAGE;
END;
END;
END.

View file

@ -0,0 +1,19 @@
while(1){
digits := [1..4].pump(String,(0).random.fpM("11-",1,9));
exp := ask("Enter an expression using the digits ",digits,
" that evals to 24: ") - " \n";
expf:=exp.apply(fcn(c){if ("1"<=c<="9") "(%s).toFloat()".fmt(c) else c});
reg r;
try { Compiler.Compiler.compileText(expf).__constructor(); r=vm.regX }
catch { println("bad expression"); continue; }
else{
extra := (exp - "+-/*()" - digits);
if (extra) { println("Extra goodies in expression: ",extra); continue; }
(digits.split("").sort() != (exp - "+-/*()").split("").sort()) :
if(_) { println("You can only use the digits ",digits," once each"); continue; };
if (exp.matches("*[1-9][1-9]*"))
{ println("no repeated digits"); continue; }
if (r.closeTo(24,0.001)) "nice!".println();
else println("That evaled to ",r,", not 24");
}
}