2016 Update

This commit is contained in:
Tina Müller 2016-12-05 22:15:40 +01:00
parent 948b86eafa
commit dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions

View file

@ -1,18 +1,28 @@
The [[wp:24 Game|24 Game]] tests one's mental arithmetic.
Write a program that [[task feature::Rosetta Code:randomness|randomly]] chooses and [[task feature::Rosetta Code:user output|displays]] four digits, each from one to nine, with repetitions allowed. The program should prompt for the player to enter an arithmetic expression using ''just'' those, and ''all'' of those four digits, used exactly ''once'' each. The program should ''check'' then [[task feature::Rosetta Code:parsing|evaluate the expression]].
The goal is for the player to [[task feature::Rosetta Code:user input|enter]] an expression that evaluates to '''24'''.
* Only multiplication, division, addition, and subtraction operators/functions are allowed.
* Division should use floating point or rational arithmetic, etc, to preserve remainders.
* Brackets are allowed, if using an infix expression evaluator.
* Forming multiple digit numbers from the supplied digits is ''disallowed''. (So an answer of 12+12 when given 1, 2, 2, and 1 is wrong).
* The order of the digits when given does not have to be preserved.
Note:
;Task
Write a program that [[task feature::Rosetta Code:randomness|randomly]] chooses and [[task feature::Rosetta Code:user output|displays]] four digits, each from 1 ──► 9 (inclusive) with repetitions allowed.
The program should prompt for the player to enter an arithmetic expression using ''just'' those, and ''all'' of those four digits, used exactly ''once'' each. The program should ''check'' then [[task feature::Rosetta Code:parsing|evaluate the expression]].
The goal is for the player to [[task feature::Rosetta Code:user input|enter]] an expression that (numerically) evaluates to '''24'''.
* Only the following operators/functions are allowed: multiplication, division, addition, subtraction
* Division should use floating point or rational arithmetic, etc, to preserve remainders.
* Brackets are allowed, if using an infix expression evaluator.
* Forming multiple digit numbers from the supplied digits is ''disallowed''. (So an answer of 12+12 when given 1, 2, 2, and 1 is wrong).
* The order of the digits when given does not have to be preserved.
<br>
;Notes
* The type of expression evaluator used is not mandated. An [[wp:Reverse Polish notation|RPN]] evaluator is equally acceptable for example.
* The task is not for the program to generate the expression, or test whether an expression is even possible.
C.f: [[24 game Player]]
'''Reference'''
# [http://www.bbc.co.uk/dna/h2g2/A933121 The 24 Game] on h2g2.
;Related tasks
* [[24 game/Solve]]
;Reference
* [http://www.bbc.co.uk/dna/h2g2/A933121 The 24 Game] on h2g2.
<br><br>

View file

@ -0,0 +1,843 @@
>>SOURCE FORMAT FREE
*> This code is dedicated to the public domain
*> This is GNUCobol 2.0
identification division.
program-id. twentyfour.
environment division.
configuration section.
repository. function all intrinsic.
data division.
working-storage section.
01 p pic 999.
01 p1 pic 999.
01 p-max pic 999 value 38.
01 program-syntax pic x(494) value
*>statement = expression;
'001 001 000 n'
& '002 000 004 ='
& '003 005 000 n'
& '004 000 002 ;'
*>expression = term, {('+'|'-') term,};
& '005 005 000 n'
& '006 000 016 ='
& '007 017 000 n'
& '008 000 015 {'
& '009 011 013 ('
& '010 001 000 t'
& '011 013 000 |'
& '012 002 000 t'
& '013 000 009 )'
& '014 017 000 n'
& '015 000 008 }'
& '016 000 006 ;'
*>term = factor, {('*'|'/') factor,};
& '017 017 000 n'
& '018 000 028 ='
& '019 029 000 n'
& '020 000 027 {'
& '021 023 025 ('
& '022 003 000 t'
& '023 025 000 |'
& '024 004 000 t'
& '025 000 021 )'
& '026 029 000 n'
& '027 000 020 }'
& '028 000 018 ;'
*>factor = ('(' expression, ')' | digit,);
& '029 029 000 n'
& '030 000 038 ='
& '031 035 037 ('
& '032 005 000 t'
& '033 005 000 n'
& '034 006 000 t'
& '035 037 000 |'
& '036 000 000 n'
& '037 000 031 )'
& '038 000 030 ;'.
01 filler redefines program-syntax.
03 p-entry occurs 038.
05 p-address pic 999.
05 filler pic x.
05 p-definition pic 999.
05 p-alternate redefines p-definition pic 999.
05 filler pic x.
05 p-matching pic 999.
05 filler pic x.
05 p-symbol pic x.
01 t pic 999.
01 t-len pic 99 value 6.
01 terminal-symbols
pic x(210) value
'01 + '
& '01 - '
& '01 * '
& '01 / '
& '01 ( '
& '01 ) '.
01 filler redefines terminal-symbols.
03 terminal-symbol-entry occurs 6.
05 terminal-symbol-len pic 99.
05 filler pic x.
05 terminal-symbol pic x(32).
01 nt pic 999.
01 nt-lim pic 99 value 5.
01 nonterminal-statements pic x(294) value
"000 ....,....,....,....,....,....,....,....,....,"
& "001 statement = expression; "
& "005 expression = term, {('+'|'-') term,}; "
& "017 term = factor, {('*'|'/') factor,}; "
& "029 factor = ('(' expression, ')' | digit,); "
& "036 digit; ".
01 filler redefines nonterminal-statements.
03 nonterminal-statement-entry occurs 5.
05 nonterminal-statement-number pic 999.
05 filler pic x.
05 nonterminal-statement pic x(45).
01 indent pic x(64) value all '| '.
01 interpreter-stack.
03 r pic 99. *> previous top of stack
03 s pic 99. *> current top of stack
03 s-max pic 99 value 32.
03 s-entry occurs 32.
05 filler pic x(2) value 'p='.
05 s-p pic 999. *> callers return address
05 filler pic x(4) value ' sc='.
05 s-start-control pic 999. *> sequence start address
05 filler pic x(4) value ' ec='.
05 s-end-control pic 999. *> sequence end address
05 filler pic x(4) value ' al='.
05 s-alternate pic 999. *> the next alternate
05 filler pic x(3) value ' r='.
05 s-result pic x. *> S success, F failure, N no result
05 filler pic x(3) value ' c='.
05 s-count pic 99. *> successes in a sequence
05 filler pic x(3) value ' x='.
05 s-repeat pic 99. *> repeats in a {} sequence
05 filler pic x(4) value ' nt='.
05 s-nt pic 99. *> current nonterminal
01 language-area.
03 l pic 99.
03 l-lim pic 99.
03 l-len pic 99 value 1.
03 nd pic 9.
03 number-definitions.
05 n occurs 4 pic 9.
03 nu pic 9.
03 number-use.
05 u occurs 4 pic x.
03 statement.
05 c occurs 32.
07 c9 pic 9.
01 number-validation.
03 p4 pic 99.
03 p4-lim pic 99 value 24.
03 permutations-4 pic x(96) value
'1234'
& '1243'
& '1324'
& '1342'
& '1423'
& '1432'
& '2134'
& '2143'
& '2314'
& '2341'
& '2413'
& '2431'
& '3124'
& '3142'
& '3214'
& '3241'
& '3423'
& '3432'
& '4123'
& '4132'
& '4213'
& '4231'
& '4312'
& '4321'.
03 filler redefines permutations-4.
05 permutation-4 occurs 24 pic x(4).
03 current-permutation-4 pic x(4).
03 cpx pic 9.
03 od1 pic 9.
03 od2 pic 9.
03 odx pic 9.
03 od-lim pic 9 value 4.
03 operator-definitions pic x(4) value '+-*/'.
03 current-operators pic x(3).
03 co3 pic 9.
03 rpx pic 9.
03 rpx-lim pic 9 value 4.
03 valid-rpn-forms pic x(28) value
'nnonono'
& 'nnnonoo'
& 'nnnoono'
& 'nnnnooo'.
03 filler redefines valid-rpn-forms.
05 rpn-form occurs 4 pic x(7).
03 current-rpn-form pic x(7).
01 calculation-area.
03 osx pic 99.
03 operator-stack pic x(32).
03 oqx pic 99.
03 oqx1 pic 99.
03 output-queue pic x(32).
03 work-number pic s9999.
03 top-numerator pic s9999 sign leading separate.
03 top-denominator pic s9999 sign leading separate.
03 rsx pic 9.
03 result-stack occurs 8.
05 numerator pic s9999.
05 denominator pic s9999.
01 error-found pic x.
01 divide-by-zero-error pic x.
*> diagnostics
01 NL pic x value x'0A'.
01 NL-flag pic x value space.
01 display-level pic x value '0'.
01 loop-lim pic 9999 value 1500.
01 loop-count pic 9999 value 0.
01 message-area value spaces.
03 message-level pic x.
03 message-value pic x(128).
*> input and examples
01 instruction pic x(32) value spaces.
01 tsx pic 99.
01 tsx-lim pic 99 value 14.
01 test-statements.
03 filler pic x(32) value '1234;1 + 2 + 3 + 4'.
03 filler pic x(32) value '1234;1 * 2 * 3 * 4'.
03 filler pic x(32) value '1234;((1)) * (((2 * 3))) * 4'.
03 filler pic x(32) value '1234;((1)) * ((2 * 3))) * 4'.
03 filler pic x(32) value '1234;(1 + 2 + 3 + 4'.
03 filler pic x(32) value '1234;)1 + 2 + 3 + 4'.
03 filler pic x(32) value '1234;1 * * 2 * 3 * 4'.
03 filler pic x(32) value '5679;6 - (5 - 7) * 9'.
03 filler pic x(32) value '1268;((1 * (8 * 6) / 2))'.
03 filler pic x(32) value '4583;-5-3+(8*4)'.
03 filler pic x(32) value '4583;8 * 4 - 5 - 3'.
03 filler pic x(32) value '4583;8 * 4 - (5 + 3)'.
03 filler pic x(32) value '1223;1 * 3 / (2 - 2)'.
03 filler pic x(32) value '2468;(6 * 8) / 4 / 2'.
01 filler redefines test-statements.
03 filler occurs 14.
05 test-numbers pic x(4).
05 filler pic x.
05 test-statement pic x(27).
procedure division.
start-twentyfour.
display 'start twentyfour'
perform generate-numbers
display 'type h <enter> to see instructions'
accept instruction
perform until instruction = spaces or 'q'
evaluate true
when instruction = 'h'
perform display-instructions
when instruction = 'n'
perform generate-numbers
when instruction(1:1) = 'm'
move instruction(2:4) to number-definitions
perform validate-number
if divide-by-zero-error = space
and 24 * top-denominator = top-numerator
display number-definitions ' is solved by ' output-queue(1:oqx)
else
display number-definitions ' is not solvable'
end-if
when instruction = 'd0' or 'd1' or 'd2' or 'd3'
move instruction(2:1) to display-level
when instruction = 'e'
display 'examples:'
perform varying tsx from 1 by 1
until tsx > tsx-lim
move spaces to statement
move test-numbers(tsx) to number-definitions
move test-statement(tsx) to statement
perform evaluate-statement
perform show-result
end-perform
when other
move instruction to statement
perform evaluate-statement
perform show-result
end-evaluate
move spaces to instruction
display 'instruction? ' with no advancing
accept instruction
end-perform
display 'exit twentyfour'
stop run
.
generate-numbers.
perform with test after until divide-by-zero-error = space
and 24 * top-denominator = top-numerator
compute n(1) = random(seconds-past-midnight) * 10 *> seed
perform varying nd from 1 by 1 until nd > 4
compute n(nd) = random() * 10
perform until n(nd) <> 0
compute n(nd) = random() * 10
end-perform
end-perform
perform validate-number
end-perform
display NL 'numbers:' with no advancing
perform varying nd from 1 by 1 until nd > 4
display space n(nd) with no advancing
end-perform
display space
.
validate-number.
perform varying p4 from 1 by 1 until p4 > p4-lim
move permutation-4(p4) to current-permutation-4
perform varying od1 from 1 by 1 until od1 > od-lim
move operator-definitions(od1:1) to current-operators(1:1)
perform varying od2 from 1 by 1 until od2 > od-lim
move operator-definitions(od2:1) to current-operators(2:1)
perform varying odx from 1 by 1 until odx > od-lim
move operator-definitions(odx:1) to current-operators(3:1)
perform varying rpx from 1 by 1 until rpx > rpx-lim
move rpn-form(rpx) to current-rpn-form
move 0 to cpx co3
move spaces to output-queue
move 7 to oqx
perform varying oqx1 from 1 by 1 until oqx1 > oqx
if current-rpn-form(oqx1:1) = 'n'
add 1 to cpx
move current-permutation-4(cpx:1) to nd
move n(nd) to output-queue(oqx1:1)
else
add 1 to co3
move current-operators(co3:1) to output-queue(oqx1:1)
end-if
end-perform
end-perform
perform evaluate-rpn
if divide-by-zero-error = space
and 24 * top-denominator = top-numerator
exit paragraph
end-if
end-perform
end-perform
end-perform
end-perform
.
display-instructions.
display '1) Type h <enter> to repeat these instructions.'
display '2) The program will display four randomly-generated'
display ' single-digit numbers and will then prompt you to enter'
display ' an arithmetic expression followed by <enter> to sum'
display ' the given numbers to 24.'
display ' The four numbers may contain duplicates and the entered'
display ' expression must reference all the generated numbers and duplicates.'
display ' Warning: the program converts the entered infix expression'
display ' to a reverse polish notation (rpn) expression'
display ' which is then interpreted from RIGHT to LEFT.'
display ' So, for instance, 8*4 - 5 - 3 will not sum to 24.'
display '3) Type n <enter> to generate a new set of four numbers.'
display ' The program will ensure the generated numbers are solvable.'
display '4) Type m#### <enter> (e.g. m1234) to create a fixed set of numbers'
display ' for testing purposes.'
display ' The program will test the solvability of the entered numbers.'
display ' For example, m1234 is solvable and m9999 is not solvable.'
display '5) Type d0, d1, d2 or d3 followed by <enter> to display none or'
display ' increasingly detailed diagnostic information as the program evaluates'
display ' the entered expression.'
display '6) Type e <enter> to see a list of example expressions and results'
display '7) Type <enter> or q <enter> to exit the program'
.
show-result.
if error-found = 'y'
or divide-by-zero-error = 'y'
exit paragraph
end-if
display 'statement in RPN is' space output-queue
evaluate true
when top-numerator = 0
when top-denominator = 0
when 24 * top-denominator <> top-numerator
display 'result (' top-numerator '/' top-denominator ') is not 24'
when other
display 'result is 24'
end-evaluate
.
evaluate-statement.
compute l-lim = length(trim(statement))
display NL 'numbers:' space n(1) space n(2) space n(3) space n(4)
move number-definitions to number-use
display 'statement is' space statement
move 1 to l
move 0 to loop-count
move space to error-found
move 0 to osx oqx
move spaces to output-queue
move 1 to p
move 1 to nt
move 0 to s
perform increment-s
perform display-start-nonterminal
perform increment-p
*>===================================
*> interpret ebnf
*>===================================
perform until s = 0
or error-found = 'y'
evaluate true
when p-symbol(p) = 'n'
and p-definition(p) = 000 *> a variable
perform test-variable
if s-result(s) = 'S'
perform increment-l
end-if
perform increment-p
when p-symbol(p) = 'n'
and p-address(p) <> p-definition(p) *> nonterminal reference
move p to s-p(s)
move p-definition(p) to p
when p-symbol(p) = 'n'
and p-address(p) = p-definition(p) *> nonterminal definition
perform increment-s
perform display-start-nonterminal
perform increment-p
when p-symbol(p) = '=' *> nonterminal control
move p to s-start-control(s)
move p-matching(p) to s-end-control(s)
perform increment-p
when p-symbol(p) = ';' *> end nonterminal
perform display-end-control
perform display-end-nonterminal
perform decrement-s
if s > 0
evaluate true
when s-result(r) = 'S'
perform set-success
when s-result(r) = 'F'
perform set-failure
end-evaluate
move s-p(s) to p
perform increment-p
perform display-continue-nonterminal
end-if
when p-symbol(p) = '{' *> start repeat sequence
perform increment-s
perform display-start-control
move p to s-start-control(s)
move p-alternate(p) to s-alternate(s)
move p-matching(p) to s-end-control(s)
move 0 to s-count(s)
perform increment-p
when p-symbol(p) = '}' *> end repeat sequence
perform display-end-control
evaluate true
when s-result(s) = 'S' *> repeat the sequence
perform display-repeat-control
perform set-nothing
add 1 to s-repeat(s)
move s-start-control(s) to p
perform increment-p
when other
perform decrement-s
evaluate true
when s-result(r) = 'N'
and s-repeat(r) = 0 *> no result
perform increment-p
when s-result(r) = 'N'
and s-repeat(r) > 0 *> no result after success
perform set-success
perform increment-p
when other *> fail the sequence
perform increment-p
end-evaluate
end-evaluate
when p-symbol(p) = '(' *> start sequence
perform increment-s
perform display-start-control
move p to s-start-control(s)
move p-alternate(p) to s-alternate(s)
move p-matching(p) to s-end-control(s)
move 0 to s-count(s)
perform increment-p
when p-symbol(p) = ')' *> end sequence
perform display-end-control
perform decrement-s
evaluate true
when s-result(r) = 'S' *> success
perform set-success
perform increment-p
when s-result(r) = 'N' *> no result
perform set-failure
perform increment-p
when other *> fail the sequence
perform set-failure
perform increment-p
end-evaluate
when p-symbol(p) = '|' *> alternate
evaluate true
when s-result(s) = 'S' *> exit the sequence
perform display-skip-alternate
move s-end-control(s) to p
when other
perform display-take-alternate
move p-alternate(p) to s-alternate(s) *> the next alternate
perform increment-p
perform set-nothing
end-evaluate
when p-symbol(p) = 't' *> terminal
move p-definition(p) to t
move terminal-symbol-len(t) to t-len
perform display-terminal
evaluate true
when statement(l:t-len) = terminal-symbol(t)(1:t-len) *> successful match
perform set-success
perform display-recognize-terminal
perform process-token
move t-len to l-len
perform increment-l
perform increment-p
when s-alternate(s) <> 000 *> we are in an alternate sequence
move s-alternate(s) to p
when other *> fail the sequence
perform set-failure
move s-end-control(s) to p
end-evaluate
when other *> end control
perform display-control-failure *> shouldnt happen
end-evaluate
end-perform
evaluate true *> at end of evaluation
when error-found = 'y'
continue
when l <= l-lim *> not all tokens parsed
display 'error: invalid statement'
perform statement-error
when number-use <> spaces
display 'error: not all numbers were used: ' number-use
move 'y' to error-found
end-evaluate
.
increment-l.
evaluate true
when l > l-lim *> end of statement
continue
when other
add l-len to l
perform varying l from l by 1
until c(l) <> space
or l > l-lim
continue
end-perform
move 1 to l-len
if l > l-lim
perform end-tokens
end-if
end-evaluate
.
increment-p.
evaluate true
when p >= p-max
display 'at' space p ' parse overflow'
space 's=<' s space s-entry(s) '>'
move 'y' to error-found
when other
add 1 to p
perform display-statement
end-evaluate
.
increment-s.
evaluate true
when s >= s-max
display 'at' space p ' stack overflow '
space 's=<' s space s-entry(s) '>'
move 'y' to error-found
when other
move s to r
add 1 to s
initialize s-entry(s)
move 'N' to s-result(s)
move p to s-p(s)
move nt to s-nt(s)
end-evaluate
.
decrement-s.
if s > 0
move s to r
subtract 1 from s
if s > 0
move s-nt(s) to nt
end-if
end-if
.
set-failure.
move 'F' to s-result(s)
if s-count(s) > 0
display 'sequential parse failure'
perform statement-error
end-if
.
set-success.
move 'S' to s-result(s)
add 1 to s-count(s)
.
set-nothing.
move 'N' to s-result(s)
move 0 to s-count(s)
.
statement-error.
display statement
move spaces to statement
move '^ syntax error' to statement(l:)
display statement
move 'y' to error-found
.
*>=====================
*> twentyfour semantics
*>=====================
test-variable.
*> check validity
perform varying nd from 1 by 1 until nd > 4
or c(l) = n(nd)
continue
end-perform
*> check usage
perform varying nu from 1 by 1 until nu > 4
or c(l) = u(nu)
continue
end-perform
evaluate true
when l > l-lim
perform set-failure
when c9(l) not numeric
perform set-failure
when nd > 4
display 'invalid number'
perform statement-error
when nu > 4
display 'number already used'
perform statement-error
when other
move space to u(nu)
perform set-success
add 1 to oqx
move c(l) to output-queue(oqx:1)
end-evaluate
.
*> ==================================
*> Dijkstra Shunting-Yard Algorithm
*> to convert infix to rpn
*> ==================================
process-token.
evaluate true
when c(l) = '('
add 1 to osx
move c(l) to operator-stack(osx:1)
when c(l) = ')'
perform varying osx from osx by -1 until osx < 1
or operator-stack(osx:1) = '('
add 1 to oqx
move operator-stack(osx:1) to output-queue(oqx:1)
end-perform
if osx < 1
display 'parenthesis error'
perform statement-error
exit paragraph
end-if
subtract 1 from osx
when (c(l) = '+' or '-') and (operator-stack(osx:1) = '*' or '/')
*> lesser operator precedence
add 1 to oqx
move operator-stack(osx:1) to output-queue(oqx:1)
move c(l) to operator-stack(osx:1)
when other
*> greater operator precedence
add 1 to osx
move c(l) to operator-stack(osx:1)
end-evaluate
.
end-tokens.
*> 1) copy stacked operators to the output-queue
perform varying osx from osx by -1 until osx < 1
or operator-stack(osx:1) = '('
add 1 to oqx
move operator-stack(osx:1) to output-queue(oqx:1)
end-perform
if osx > 0
display 'parenthesis error'
perform statement-error
exit paragraph
end-if
*> 2) evaluate the rpn statement
perform evaluate-rpn
if divide-by-zero-error = 'y'
display 'divide by zero error'
end-if
.
evaluate-rpn.
move space to divide-by-zero-error
move 0 to rsx *> stack depth
perform varying oqx1 from 1 by 1 until oqx1 > oqx
if output-queue(oqx1:1) >= '1' and <= '9'
*> push current data onto the stack
add 1 to rsx
move top-numerator to numerator(rsx)
move top-denominator to denominator(rsx)
move output-queue(oqx1:1) to top-numerator
move 1 to top-denominator
else
*> apply the operation
evaluate true
when output-queue(oqx1:1) = '+'
compute top-numerator = top-numerator * denominator(rsx)
+ top-denominator * numerator(rsx)
compute top-denominator = top-denominator * denominator(rsx)
when output-queue(oqx1:1) = '-'
compute top-numerator = top-denominator * numerator(rsx)
- top-numerator * denominator(rsx)
compute top-denominator = top-denominator * denominator(rsx)
when output-queue(oqx1:1) = '*'
compute top-numerator = top-numerator * numerator(rsx)
compute top-denominator = top-denominator * denominator(rsx)
when output-queue(oqx1:1) = '/'
compute work-number = numerator(rsx) * top-denominator
compute top-denominator = denominator(rsx) * top-numerator
if top-denominator = 0
move 'y' to divide-by-zero-error
exit paragraph
end-if
move work-number to top-numerator
end-evaluate
*> pop the stack
subtract 1 from rsx
end-if
end-perform
.
*>====================
*> diagnostic displays
*>====================
display-start-nonterminal.
perform varying nt from nt-lim by -1 until nt < 1
or p-definition(p) = nonterminal-statement-number(nt)
continue
end-perform
if nt > 0
move '1' to NL-flag
string '1' indent(1:s + s) 'at ' s space p ' start ' trim(nonterminal-statement(nt))
into message-area perform display-message
move nt to s-nt(s)
end-if
.
display-continue-nonterminal.
move s-nt(s) to nt
string '1' indent(1:s + s) 'at ' s space p space p-symbol(p) ' continue ' trim(nonterminal-statement(nt)) ' with result ' s-result(s)
into message-area perform display-message
.
display-end-nonterminal.
move s-nt(s) to nt
move '2' to NL-flag
string '1' indent(1:s + s) 'at ' s space p ' end ' trim(nonterminal-statement(nt)) ' with result ' s-result(s)
into message-area perform display-message
.
display-start-control.
string '2' indent(1:s + s) 'at ' s space p ' start ' p-symbol(p) ' in ' trim(nonterminal-statement(nt))
into message-area perform display-message
.
display-repeat-control.
string '2' indent(1:s + s) 'at ' s space p ' repeat ' p-symbol(p) ' in ' trim(nonterminal-statement(nt)) ' with result ' s-result(s)
into message-area perform display-message
.
display-end-control.
string '2' indent(1:s + s) 'at ' s space p ' end ' p-symbol(p) ' in ' trim(nonterminal-statement(nt)) ' with result ' s-result(s)
into message-area perform display-message
.
display-take-alternate.
string '2' indent(1:s + s) 'at ' s space p ' take alternate' ' in ' trim(nonterminal-statement(nt))
into message-area perform display-message
.
display-skip-alternate.
string '2' indent(1:s + s) 'at ' s space p ' skip alternate' ' in ' trim(nonterminal-statement(nt))
into message-area perform display-message
.
display-terminal.
string '1' indent(1:s + s) 'at ' s space p
' compare ' statement(l:t-len) ' to ' terminal-symbol(t)(1:t-len)
' in ' trim(nonterminal-statement(nt))
into message-area perform display-message
.
display-recognize-terminal.
string '1' indent(1:s + s) 'at ' s space p ' recognize terminal: ' c(l) ' in ' trim(nonterminal-statement(nt))
into message-area perform display-message
.
display-recognize-variable.
string '1' indent(1:s + s) 'at ' s space p ' recognize digit: ' c(l) ' in ' trim(nonterminal-statement(nt))
into message-area perform display-message
.
display-statement.
compute p1 = p - s-start-control(s)
string '3' indent(1:s + s) 'at ' s space p
' statement: ' s-start-control(s) '/' p1
space p-symbol(p) space s-result(s)
' in ' trim(nonterminal-statement(nt))
into message-area perform display-message
.
display-control-failure.
display loop-count space indent(1:s + s) 'at' space p ' control failure' ' in ' trim(nonterminal-statement(nt))
display loop-count space indent(1:s + s) ' ' 'p=<' p p-entry(p) '>'
display loop-count space indent(1:s + s) ' ' 's=<' s space s-entry(s) '>'
display loop-count space indent(1:s + s) ' ' 'l=<' l space c(l)'>'
perform statement-error
.
display-message.
if display-level = 1
move space to NL-flag
end-if
evaluate true
when loop-count > loop-lim *> loop control
display 'display count exceeds ' loop-lim
stop run
when message-level <= display-level
evaluate true
when NL-flag = '1'
display NL loop-count space trim(message-value)
when NL-flag = '2'
display loop-count space trim(message-value) NL
when other
display loop-count space trim(message-value)
end-evaluate
end-evaluate
add 1 to loop-count
move spaces to message-area
move space to NL-flag
.
end program twentyfour.

View file

@ -0,0 +1,39 @@
defmodule Game24 do
def main do
IO.puts "24 Game"
play
end
defp play do
IO.puts "Generating 4 digits..."
digts = for _ <- 1..4, do: Enum.random(1..9)
IO.puts "Your digits\t#{inspect digts, char_lists: :as_lists}"
read_eval(digts)
play
end
defp read_eval(digits) do
exp = IO.gets("Your expression: ") |> String.strip
if exp in ["","q"], do: exit(:normal) # give up
case {correct_nums(exp, digits), eval(exp)} do
{:ok, x} when x==24 -> IO.puts "You Win!"
{:ok, x} -> IO.puts "You Lose with #{inspect x}!"
{err, _} -> IO.puts "The following numbers are wrong: #{inspect err, char_lists: :as_lists}"
end
end
defp correct_nums(exp, digits) do
nums = String.replace(exp, ~r/\D/, " ") |> String.split |> Enum.map(&String.to_integer &1)
if length(nums)==4 and (nums--digits)==[], do: :ok, else: nums
end
defp eval(exp) do
try do
Code.eval_string(exp) |> elem(0)
rescue
e -> Exception.message(e)
end
end
end
Game24.main

View file

@ -29,10 +29,9 @@ processGuess digits xs = calc xs >>= check
check x = Left (show (fromRational (x :: Rational)) ++ " is wrong")
-- A Reverse Polish Notation calculator with full error handling
calc = result []
where result [n] [] = Right n
result _ [] = Left "Too few operators"
result ns (x:xs) = simplify ns x >>= flip result xs
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)

View file

@ -0,0 +1,84 @@
play24 := module()
export ModuleApply;
local cheating;
cheating := proc(input, digits)
local i, j, stringDigits;
use StringTools in
stringDigits := Implode([seq(convert(i, string), i in digits)]);
for i in digits do
for j in digits do
if Search(cat(convert(i, string), j), input) > 0 then
return true, ": Please don't combine digits to form another number."
end if;
end do;
end do;
for i in digits do
if CountCharacterOccurrences(input, convert(i, string)) < CountCharacterOccurrences(stringDigits, convert(i, string)) then
return true, ": Please use all digits.";
end if;
end do;
for i in digits do
if CountCharacterOccurrences(input, convert(i, string)) > CountCharacterOccurrences(stringDigits, convert(i, string)) then
return true, ": Please only use a digit once.";
end if;
end do;
for i in input do
try
if type(parse(i), numeric) and not member(parse(i), digits) then
return true, ": Please only use the digits you were given.";
end if;
catch:
end try;
end do;
return false, "";
end use;
end proc:
ModuleApply := proc()
local replay, digits, err, message, answer;
randomize():
replay := "":
while not replay = "END" do
if not replay = "YES" then
digits := [seq(rand(1..9)(), i = 1..4)]:
end if;
err := true:
while err do
message := "";
printf("Please make 24 from the digits: %a. Press enter for a new set of numbers or type END to quit\n", digits);
answer := StringTools[UpperCase](readline());
if not answer = "" and not answer = "END" then
try
if not type(parse(answer), numeric) then
error;
elif cheating(answer, digits)[1] then
message := cheating(answer, digits)[2];
error;
end if;
err := false;
catch:
printf("Invalid Input%s\n\n", message);
end try;
else
err := false;
end if;
end do:
if not answer = "" and not answer = "END" then
if parse(answer) = 24 then
printf("You win! Do you wish to play another game? (Press enter for a new set of numbers or END to quit.)\n");
replay := StringTools[UpperCase](readline());
else
printf("Your expression evaluated to %a. Try again!\n", parse(answer));
replay := "YES";
end if;
else
replay := answer;
end if;
printf("\n");
end do:
printf("GAME OVER\n");
end proc:
end module:
play24();

View file

@ -1,3 +1,5 @@
use MONKEY-SEE-NO-EVAL;
say "Here are your digits: ",
constant @digits = (1..9).roll(4)».Str;
@ -9,15 +11,16 @@ grammar Exp24 {
}
while my $exp = prompt "\n24? " {
if Exp24.parse: $exp {
say "You win :)";
last;
if try Exp24.parse: $exp {
say "You win :)";
last;
} else {
say pick 1,
'Sorry. Try again.' xx 20,
'Try harder.' xx 5,
'Nope. Not even close.' xx 2,
'Are you five or something?',
'Come on, you can do better than that.';
say (
'Sorry. Try again.' xx 20,
'Try harder.' xx 5,
'Nope. Not even close.' xx 2,
'Are you five or something?',
'Come on, you can do better than that.'
).flat.pick
}
}

View file

@ -64,4 +64,5 @@ def main():
if ans == 24:
print ("Thats right!")
print ("Thank you and goodbye")
main()
if __name__ == '__main__': main()

View file

@ -1,73 +1,68 @@
/*REXX program which allows a user to play the game of 24 (twenty-four). */
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 var yyy start '-' fin /*get the START and FINish (maybe). */
fin = word(fin start,1) /*if no FINish specified, use START.*/
opers = '+-*/' /*define the legal arithmetic operators*/
ops = length(opers) /* ··· and the count of them (length). */
groupSymbols = '()[]{}' /*legal grouping symbols for this game.*/
indent = left('',30) /*used to indent display of solutions. */
Lpar = '(' /*a string to make the output prettier.*/
Rpar = ')' /*Ditto. [You can say that again.] */
digs = 123456789 /*numerals (digits) that can be used. */
show = 1 /*flag used show solutions (0 = not). */
do j=1 for ops /*define a version for fast execution. */
@.j=substr(opers,j,1) /*assign each operation to an array. */
end /*j*/
signal on syntax /*enable program to trap syntax errors.*/
if yyy\=='' then do /*if START (or FINish), then solve 'em.*/
sols=solve(start,fin) /*solve START ───► FINish. */
if sols <0 then exit 13 /*Was there a problem with input? */
if sols==0 then sols='No' /*Englishize the SOLS variable.*/
say; say sols 'unique solution's(sols) "found for" yyy
exit /*S [↑] does pluralizations. */
end
show=0 /*stop SOLVE from blabbing solutions.*/
/*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 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*/
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? */
if sols==0 then sols='No' /*Englishize the SOLS variable value*/
say; say sols 'unique solution's(sols) "found for" yyy
exit /*S [↑] does pluralizations. */
end
show=0 /*stop SOLVE from blabbing solutions.*/
do forever; rrrr=random(1111, 9999)
if pos(0, rrrr)\==0 then iterate /*if contains a zero, ignore it*/
if solve(rrrr)\==0 then leave /*if solved, then stop looking.*/
if pos(0, rrrr)\==0 then iterate /*if it contains a zero, then ignore it*/
if solve(rrrr) \==0 then leave /*if solved, then we can stop looking. */
end /*forever*/
show=1 /*enable SOLVE to display solutions. */
rrrr=sort(rrrr) /*sort four digits (for consistency). */
show=1 /*enable SOLVE to display solutions. */
rrrr=sort(rrrr); Lrrrr=length(rrrr) /*sort four digits (for consistency). */
$.=0
do j=1 for length(rrrr) /*digit count for each digit in RRRR. */
_=substr(rrrr, j, 1) /*pick off one of the digits in RRRR. */
$._=countDigs(rrrr, _) /*define the count for this digit. */
end /*j*/ /* [↑] counts duplicates twice, no harm*/
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*/
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)*/
pull y; y=space(y,0) /*get Y from CL, then remove all blanks*/
if abbrev('QUIT',y,1) then exit /*Does the user want to quit this game?*/
_v=verify(y, digs || opers || groupSymbols); a=substr(y, max(1,_v), 1)
if _v\==0 then do; call ger 'invalid character:' a; iterate; end
if pos('**',y) then do; call ger 'invalid ** operator'; iterate; end
if pos('//',y) then do; call ger 'invalid // operator'; iterate; end
yL=length(y)
if y=='' then do; call validate y; iterate; end
__ = 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)*/
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)
if _v\==0 then do; call ger "invalid character:" a; iterate; end
if pos('**', y) then do; call ger "invalid ** operator"; iterate; end
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 yL-1; if \datatype(substr(y, j ,1), 'W') then iterate
if \datatype(substr(y, j+1,1), 'W') then iterate
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
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
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*/
y=translate(y, '()()', "[]{}")
interpret 'ans=' y; ans=ans/1; if ans==24 then leave prompter
say 'incorrect, ' y'='ans
interpret 'ans=' translate(y, '()()', "[]{}"); ans=ans/1
if ans==24 then leave prompter; say 'incorrect, ' y"="ans
end /*prompter*/
say; say center('', 79)
@ -75,84 +70,65 @@ say; say center('┌────────────────
say center(' congratulations ! ', 79)
say center(' ', 79)
say center('', 79)
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────one─liner subroutines─────────────────────*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
countDigs: arg ?; return length(?) - length(space(translate(?, , arg(2)), 0))
div: if arg(1)=0 then return 7e9; return arg(1) /*if ÷ by 0, fudge result*/
ger: say; say '***error!*** for argument:' y; say arg(1); say;errCode=1;return 0
s: if arg(1)==1 then return ''; return 's' /*simple pluralizer.*/
syntax: call ger 'illegal syntax in' y; exit
/*──────────────────────────────────SOLVE subroutine──────────────────────────*/
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) */
div: if arg(1)=0 then return 7e9; return arg(1) /*÷ by 0? Fudge result*/
ger: say; say __ '***error*** for expression:' y; say __ arg(1); say; OK=0; return 0
s: if arg(1)==1 then return ''; return "s" /*a simple pluralizer.*/
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) */
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 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 /*define a version for fast execution. */
g.j=substr(g, j, 1) /*extract each digit of G into array.*/
end /*j*/
do i =1 for Lops /*insert an operator after 1st number. */
do j =1 for Lops /* " " " " 2nd " */
do k =1 for Lops /* " " " " 3rd " */
do m=0 to 3; L.= /*assume no left parenthesis (so far).*/
do n=m+1 to 4; L.m=Lpar; R.= /*match left paren with a right paren. */
if m==1 & n==2 then L.= /*special case of : (n) + ··· */
else if m\==0 then R.n=Rpar /*no (, no )*/
e= L.1 g.1 @.i L.2 g.2 @.j L.3 g.3 R.3 @.k g.4 R.4
e=space(e, 0) /*remove all blanks from the expression*/
yyyE=e /*keep old the version for the display.*/
/* [↓] change /(yyy) ═══► /div(yyy) */
if pos('/(', e)\==0 then e=changestr( "/(", e, '/div(' )
if !.e then iterate /*was this expression already used? */
!.e=1 /*mark this expression as being used. */
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, '][', ")(")
end /*n*/ /* [↑] display a (single) solution. */
end /*m*/
end /*k*/
end /*j*/
end /*i*/
end /*g*/
do i =1 for ops /*insert an operator after 1st number. */
do j =1 for ops /*insert an operator after 2nd number. */
do k =1 for ops /*insert an operator after 2nd number. */
do m=0 to 3; L.= /*assume no left parenthesis so far. */
do n=m+1 to 4 /*match left paren with a right paren. */
L.m=Lpar /*define a left paren, m=0 means ignore*/
R.= /*un-define all right parenthesis. */
if m==1 & n==2 then L.= /*special case of : (n) + ··· */
else if m\==0 then R.n=Rpar /*no (, no )*/
e = L.1 g.1 @.i L.2 g.2 @.j L.3 g.3 R.3 @.k g.4 R.4
e=space(e, 0) /*remove all blanks from the expression*/
/* [↓] change expression: */
/* /(yyy) ═══► /div(yyy) */
/*Enables to check for division by zero*/
yyyE=e /*keep old the version for the display.*/
if pos('/(', e)\==0 then e=changestr( '/(', e, "/div(" )
/* [↓] INTERPRET stresses REXX's groin,*/
/* so try to avoid repeated lifting.*/
if !.e then iterate /*was this expression already used? */
!.e=1 /*mark this expression as being used. */
interpret 'x=' e /*have REXX do all the heavy lifting */
x=x/1 /*remove any trailing decimal point. */
if x\==24 then iterate /*Is the result incorrect? Try again. */
#=#+1 /*bump number of found solutions. */
_=translate(yyyE, '][', ")(") /*display [], not (). */
if show then say indent 'a solution:' _
end /*n*/ /* [↑] show a solution.*/
end /*m*/
end /*k*/
end /*j*/
end /*i*/
end /*g*/
return #
/*──────────────────────────────────SORT subroutine───────────────────────────*/
sort: procedure; arg nnnn; L=length(nnnn)
do i=1 for L /*build an array of digits from NNNN. */
s.i=substr(nnnn, i, 1) /*this enables SORT to sort an array. */
end /*i*/
do j=1 for L; _=s.j
do k=j+1 to L
if s.k<_ then parse value s.j s.k with s.k s.j
end /*k*/
end /*j*/
return s.1 || s.2 || s.3 || s.4
/*──────────────────────────────────VALIDATE subroutine───────────────────────*/
validate: parse arg y; errCode=0; _v=verify(y,digs)
select
when y=='' then call ger 'no digits entered.'
when length(y)<4 then call ger 'not enough digits entered, must be four.'
when length(y)>4 then call ger 'too many digits entered, must be four.'
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 \errCode
return #
/*──────────────────────────────────────────────────────────────────────────────────────*/
sort: procedure; parse arg #; L=length(#); !.= /*this is a modified bin sort.*/
do d=1 for L; _=substr(#, d, 1); !.d=!.d || _; end /*d*/
return space(!.0 !.1 !.2 !.3 !.4 !.5 !.6 !.7 !.8 !.9, 0) /*reconstitute the #.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
validate: parse arg y; OK=1; _v=verify(y,digs); DE='digits entered, there must be four.'
select
when y=='' then call ger "no" DE
when length(y)<4 then call ger "not enough" DE
when length(y)>4 then call ger "too many" DE
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

View file

@ -1,16 +1,14 @@
def validate(guess, nums)
name, error =
{
invalid_character: ->(str){ !str.scan(%r{[^\d\s()+*/-]}).empty? },
wrong_number: ->(str){ str.scan(/\d/).map(&:to_i).sort != nums.sort },
multi_digit_number: ->(str){ str.match(/\d\d/) }
}
.find {|name, validator| validator[guess] }
error ? puts("Invalid input of a(n) #{name.to_s.tr('_',' ')}!") : true
end
class Guess < String
def self.play
nums = Array.new(4){rand(1..9)}
loop do
result = get(nums).evaluate!
break if result == 24.0
puts "Try again! That gives #{result}!"
end
puts "You win!"
end
def self.get(nums)
loop do
print "\nEnter a guess using #{nums}: "
@ -19,24 +17,24 @@ class Guess < String
end
end
def self.validate(guess, nums)
name, error =
{
invalid_character: ->(str){ !str.scan(%r{[^\d\s()+*/-]}).empty? },
wrong_number: ->(str){ str.scan(/\d/).map(&:to_i).sort != nums.sort },
multi_digit_number: ->(str){ str.match(/\d\d/) }
}
.find {|name, validator| validator[guess] }
error ? puts("Invalid input of a(n) #{name.to_s.tr('_',' ')}!") : true
end
def evaluate!
as_rat = gsub(/(\d)/, 'Rational(\1,1)')
begin
eval "(#{as_rat}).to_f"
rescue SyntaxError
"[syntax error]"
end
as_rat = gsub(/(\d)/, '\1r') # r : Rational suffix
eval "(#{as_rat}).to_f"
rescue SyntaxError
"[syntax error]"
end
end
def play
nums = Array.new(4){rand(1..9)}
loop do
result = Guess.get(nums).evaluate!
break if result == 24.0
puts "Try again! That gives #{result}!"
end
puts "You win!"
end
play
Guess.play

View file

@ -0,0 +1,102 @@
use std::io::{self,BufRead};
extern crate rand;
use rand::Rng;
fn op_type(x: char) -> i32{
match x {
'-' | '+' => return 1,
'/' | '*' => return 2,
'(' | ')' => return -1,
_ => return 0,
}
}
fn to_rpn(input: &mut String){
let mut rpn_string : String = String::new();
let mut rpn_stack : String = String::new();
let mut last_token = '#';
for token in input.chars(){
if token.is_digit(10) {
rpn_string.push(token);
}
else if op_type(token) == 0 {
continue;
}
else if op_type(token) > op_type(last_token) || token == '(' {
rpn_stack.push(token);
last_token=token;
}
else {
while let Some(top) = rpn_stack.pop() {
if top=='(' {
break;
}
rpn_string.push(top);
}
if token != ')'{
rpn_stack.push(token);
}
}
}
while let Some(top) = rpn_stack.pop() {
rpn_string.push(top);
}
println!("you formula results in {}", rpn_string);
*input=rpn_string;
}
fn calculate(input: &String, list : &mut [u32;4]) -> f32{
let mut stack : Vec<f32> = Vec::new();
let mut accumulator : f32 = 0.0;
for token in input.chars(){
if token.is_digit(10) {
let test = token.to_digit(10).unwrap() as u32;
match list.iter().position(|&x| x == test){
Some(idx) => list[idx]=10 ,
_ => println!(" invalid digit: {} ",test),
}
stack.push(accumulator);
accumulator = test as f32;
}else{
let a = stack.pop().unwrap();
accumulator = match token {
'-' => a-accumulator,
'+' => a+accumulator,
'/' => a/accumulator,
'*' => a*accumulator,
_ => {accumulator},//NOP
};
}
}
println!("you formula results in {}",accumulator);
accumulator
}
fn main() {
let mut rng = rand::thread_rng();
let mut list :[u32;4]=[rng.gen::<u32>()%10,rng.gen::<u32>()%10,rng.gen::<u32>()%10,rng.gen::<u32>()%10];
println!("form 24 with using + - / * {:?}",list);
//get user input
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
//convert to rpn
to_rpn(&mut input);
let result = calculate(&input, &mut list);
if list.iter().any(|&list| list !=10){
println!("and you used all numbers");
match result {
24.0 => println!("you won"),
_ => println!("but your formulla doesn't result in 24"),
}
}else{
println!("you didn't use all the numbers");
}
}

View file

@ -0,0 +1,52 @@
10 LET n$=""
20 RANDOMIZE
30 FOR i=1 TO 4
40 LET n$=n$+STR$ (INT (RND*9)+1)
50 NEXT i
60 LET i$="": LET f$="": LET p$=""
70 CLS
80 PRINT "24 game"
90 PRINT "Allowed characters:"
100 LET i$=n$+"+-*/()"
110 PRINT AT 4,0;
120 FOR i=1 TO 10
130 PRINT i$(i);" ";
140 NEXT i
150 PRINT "(0 to end)"
160 INPUT "Enter the formula";f$
170 IF f$="0" THEN STOP
180 PRINT AT 6,0;f$;" = ";
190 FOR i=1 TO LEN f$
200 LET c$=f$(i)
210 IF c$=" " THEN LET f$(i)="": GO TO 250
220 IF c$="+" OR c$="-" OR c$="*" OR c$="/" THEN LET p$=p$+"o": GO TO 250
230 IF c$="(" OR c$=")" THEN LET p$=p$+c$: GO TO 250
240 LET p$=p$+"n"
250 NEXT i
260 RESTORE
270 FOR i=1 TO 11
280 READ t$
290 IF t$=p$ THEN LET i=11
300 NEXT i
310 IF t$<>p$ THEN PRINT INVERSE 1;"Bad construction!": BEEP 1,.1: PAUSE 0: GO TO 60
320 FOR i=1 TO LEN f$
330 FOR j=1 TO 10
340 IF (f$(i)=i$(j)) AND f$(i)>"0" AND f$(i)<="9" THEN LET i$(j)=" "
350 NEXT j
360 NEXT i
370 IF i$( TO 4)<>" " THEN PRINT FLASH 1;"Invalid arguments!": BEEP 1,.01: PAUSE 0: GO TO 60
380 LET r=VAL f$
390 PRINT r;" ";
400 IF r<>24 THEN PRINT FLASH 1;"Wrong!": BEEP 1,1: PAUSE 0: GO TO 60
410 PRINT FLASH 1;"Correct!": PAUSE 0: GO TO 10
420 DATA "nononon"
430 DATA "(non)onon"
440 DATA "nono(non)"
450 DATA "no(no(non))"
460 DATA "((non)on)on"
470 DATA "no(non)on"
480 DATA "(non)o(non)"
485 DATA "no((non)on)"
490 DATA "(nonon)on"
495 DATA "(no(non))on"
500 DATA "no(nonon)"