24 game/Solve: Difference between revisions

m
m (Phrasing)
m (→‎{{header|Wren}}: Minor tidy)
 
(125 intermediate revisions by 46 users not shown)
Line 1:
{{task}}
 
;task:
Write a program that takes four digits, either from user input or by random generation, and computes arithmetic expressions following the rules of the [[24 game]].
 
Show examples of solutions generated by the functionprogram.
 
 
C.F: [[Arithmetic Evaluator]]
;Related task:
*   [[Arithmetic Evaluator]]
<br><br>
=={{header|11l}}==
{{trans|Nim}}
 
<syntaxhighlight lang="11l">[Char = ((Float, Float) -> Float)] op
op[Char(‘+’)] = (x, y) -> x + y
op[Char(‘-’)] = (x, y) -> x - y
op[Char(‘*’)] = (x, y) -> x * y
op[Char(‘/’)] = (x, y) -> I y != 0 {x / y} E 9999999
 
F almost_equal(a, b)
R abs(a - b) <= 1e-5
 
F solve(nums)
V syms = ‘+-*/’
V sorted_nums = sorted(nums).map(Float)
L(x, y, z) cart_product(syms, syms, syms)
V n = copy(sorted_nums)
L
V (a, b, c, d) = (n[0], n[1], n[2], n[3])
I almost_equal(:op[x](:op[y](a, b), :op[z](c, d)), 24.0)
R ‘(’a‘ ’y‘ ’b‘) ’x‘ (’c‘ ’z‘ ’d‘)’
I almost_equal(:op[x](a, :op[y](b, :op[z](c, d))), 24.0)
R a‘ ’x‘ (’b‘ ’y‘ (’c‘ ’z‘ ’d‘))’
I almost_equal(:op[x](:op[y](:op[z](c, d), b), a), 24.0)
R ‘((’c‘ ’z‘ ’d‘) ’y‘ ’b‘) ’x‘ ’a
I almost_equal(:op[x](:op[y](b, :op[z](c, d)), a), 24.0)
R ‘(’b‘ ’y‘ (’c‘ ’z‘ ’d‘)) ’x‘’a
I !n.next_permutation()
L.break
R ‘not found’
 
L(nums) [[9, 4, 4, 5],
[1, 7, 2, 7],
[5, 7, 5, 4],
[1, 4, 6, 6],
[2, 3, 7, 3],
[8, 7, 9, 7],
[1, 6, 2, 6],
[7, 9, 4, 1],
[6, 4, 2, 2],
[5, 7, 9, 7],
[3, 3, 8, 8]]
print(‘solve(’nums‘) -> ’solve(nums))</syntaxhighlight>
 
{{out}}
<pre>
solve([9, 4, 4, 5]) -> not found
solve([1, 7, 2, 7]) -> ((7 * 7) - 1) / 2
solve([5, 7, 5, 4]) -> 4 * (7 - (5 / 5))
solve([1, 4, 6, 6]) -> 6 + (6 * (4 - 1))
solve([2, 3, 7, 3]) -> ((2 + 7) * 3) - 3
solve([8, 7, 9, 7]) -> not found
solve([1, 6, 2, 6]) -> 6 + (6 * (1 + 2))
solve([7, 9, 4, 1]) -> (1 - 9) * (4 - 7)
solve([6, 4, 2, 2]) -> (2 - 2) + (4 * 6)
solve([5, 7, 9, 7]) -> (5 + 7) * (9 - 7)
solve([3, 3, 8, 8]) -> 8 / (3 - (8 / 3))
</pre>
 
=={{header|AArch64 Assembly}}==
{{works with|as|Raspberry Pi 3B version Buster 64 bits}}
<syntaxhighlight lang="aarch64 assembly">
/* ARM assembly AARCH64 Raspberry PI 3B */
/* program game24Solvex64.s */
 
/*******************************************/
/* Constantes file */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"
 
.equ NBDIGITS, 4 // digits number
.equ TOTAL, 24
.equ BUFFERSIZE, 80
 
/*********************************/
/* Initialized data */
/*********************************/
.data
szMessRules: .ascii "24 Game\n"
.ascii "The program will display four randomly-generated \n"
.asciz "single-digit numbers and search a solution for a total to 24\n\n"
 
szMessDigits: .asciz "The four digits are @ @ @ @ and the score is 24. \n"
szMessOK: .asciz "Solution : \n"
szMessNotOK: .asciz "No solution for this problem !! \n"
szMessNewGame: .asciz "New game (y/n) ? \n"
szMessErrOper: .asciz "Error opérator in display result !!!"
szCarriageReturn: .asciz "\n"
.align 4
qGraine: .quad 123456
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
.align 4
sZoneConv: .skip 24
sBuffer: .skip BUFFERSIZE
qTabDigit: .skip 8 * NBDIGITS // digits table
qTabOperand1: .skip 8 * NBDIGITS // operand 1 table
qTabOperand2: .skip 8 * NBDIGITS // operand 2 table
qTabOperation: .skip 8 * NBDIGITS // operator table
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: // entry of program
ldr x0,qAdrszMessRules // display rules
bl affichageMess
1:
mov x3,#0
ldr x12,qAdrqTabDigit
ldr x5,qAdrszMessDigits
2: // loop generate random digits
mov x0,#8
bl genereraleas
add x0,x0,#1
str x0,[x12,x3,lsl 3] // store in table
ldr x1,qAdrsZoneConv
bl conversion10 // call decimal conversion
mov x0,x5
ldr x1,qAdrsZoneConv // insert conversion in message
bl strInsertAtCharInc
mov x5,x0
add x3,x3,#1
cmp x3,#NBDIGITS // end ?
blt 2b // no -> loop
mov x0,x5
bl affichageMess
mov x0,#0 // start leval
mov x1,x12 // address digits table
bl searchSoluce
cmp x0,#-1 // solution ?
bne 3f // no
ldr x0,qAdrszMessOK
bl affichageMess
bl writeSoluce // yes -> write solution in buffer
ldr x0,qAdrsBuffer // and display buffer
bl affichageMess
b 10f
3: // display message no solution
ldr x0,qAdrszMessNotOK
bl affichageMess
 
 
10: // display new game ?
ldr x0,qAdrszCarriageReturn
bl affichageMess
ldr x0,qAdrszMessNewGame
bl affichageMess
bl saisie
cmp x0,#'y'
beq 1b
cmp x0,#'Y'
beq 1b
100: // standard end of the program
mov x0,0 // return code
mov x8,EXIT // request to exit program
svc 0 // perform the system call
qAdrszCarriageReturn: .quad szCarriageReturn
qAdrszMessRules: .quad szMessRules
qAdrszMessDigits: .quad szMessDigits
qAdrszMessNotOK: .quad szMessNotOK
qAdrszMessOK: .quad szMessOK
qAdrszMessNewGame: .quad szMessNewGame
qAdrsZoneConv: .quad sZoneConv
qAdrqTabDigit: .quad qTabDigit
/******************************************************************/
/* recherche solution */
/******************************************************************/
/* x0 level */
/* x1 table value address */
/* x0 return -1 if ok */
searchSoluce:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
stp x6,x7,[sp,-16]! // save registres
stp x8,x9,[sp,-16]! // save registres
stp x10,x11,[sp,-16]! // save registres
stp x12,fp,[sp,-16]! // save registres
sub sp,sp,#8* NBDIGITS // reserve size new digits table
mov fp,sp // frame pointer = address stack
mov x10,x1 // save table
add x9,x0,#1 // new level
mov x13,#NBDIGITS
sub x3,x13,x9 // last element digits table
ldr x4,[x1,x3,lsl 3] // load last element
cmp x4,#TOTAL // equal to total to search ?
bne 0f // no
cmp x9,#NBDIGITS // all digits are used ?
bne 0f // no
mov x0,#-1 // yes -> it is ok -> end
b 100f
0:
mov x5,#0 // indice loop 1
1: // begin loop 1
cmp x5,x3
bge 9f
ldr x4,[x10,x5,lsl 3] // load first operand
ldr x8,qAdrqTabOperand1
str x4,[x8,x9,lsl 3] // and store in operand1 table
add x6,x5,#1 // indice loop 2
2: // begin loop 2
cmp x6,x3
bgt 8f
ldr x12,[x10,x6,lsl 3] // load second operand
ldr x8,qAdrqTabOperand2
str x12,[x8,x9,lsl 3] // and store in operand2 table
mov x7,#0 // k
mov x8,#0 // n
3:
cmp x7,x5
beq 4f
cmp x7,x6
beq 4f
ldr x0,[x10,x7,lsl 3] // copy other digits in new table on stack
str x0,[fp,x8,lsl 3]
add x8,x8,#1
4:
add x7,x7,#1
cmp x7,x3
ble 3b
 
add x7,x4,x12 // addition test
str x7,[fp,x8,lsl 3] // store result of addition
mov x7,#'+'
ldr x0,qAdrqTabOperation
str x7,[x0,x9,lsl 3] // store operator
mov x0,x9 // pass new level
mov x1,fp // pass new table address on stack
bl searchSoluce
cmp x0,#0
blt 100f
// soustraction test
sub x13,x4,x12
sub x14,x12,x4
cmp x4,x12
csel x7,x13,x14,gt
str x7,[fp,x8,lsl 3]
mov x7,#'-'
ldr x0,qAdrqTabOperation
str x7,[x0,x9,lsl 3]
mov x0,x9
mov x1,fp
bl searchSoluce
cmp x0,#0
blt 100f
mul x7,x4,x12 // multiplication test
str x7,[fp,x8,lsl 3]
mov x7,#'*'
ldr x0,qAdrqTabOperation
str x7,[x0,x9,lsl 3]
mov x0,x9
mov x1,fp
bl searchSoluce
cmp x0,#0
blt 100f
5: // division test
udiv x13,x4,x12
msub x14,x13,x12,x4
cmp x14,#0
bne 6f
str x13,[fp,x8,lsl 3]
mov x7,#'/'
ldr x0,qAdrqTabOperation
str x7,[x0,x9,lsl 3]
mov x0,x9
mov x1,fp
bl searchSoluce
b 7f
6:
udiv x13,x12,x4
msub x14,x13,x4,x12
cmp x14,#0
bne 7f
str x13,[fp,x8,lsl 3]
mov x7,#'/'
ldr x0,qAdrqTabOperation
str x7,[x0,x9,lsl 3]
mov x0,x9
mov x1,fp
bl searchSoluce
7:
cmp x0,#0
blt 100f
add x6,x6,#1 // increment indice loop 2
b 2b
 
8:
add x5,x5,#1 // increment indice loop 1
b 1b
9:
100:
add sp,sp,8* NBDIGITS // stack alignement
ldp x12,fp,[sp],16 // restaur des 2 registres
ldp x10,x11,[sp],16 // restaur des 2 registres
ldp x8,x9,[sp],16 // restaur des 2 registres
ldp x6,x7,[sp],16 // restaur des 2 registres
ldp x4,x5,[sp],16 // restaur des 2 registres
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
qAdrqTabOperand1: .quad qTabOperand1
qAdrqTabOperand2: .quad qTabOperand2
qAdrqTabOperation: .quad qTabOperation
/******************************************************************/
/* write solution */
/******************************************************************/
writeSoluce:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
stp x6,x7,[sp,-16]! // save registres
stp x8,x9,[sp,-16]! // save registres
stp x10,x11,[sp,-16]! // save registres
stp x12,fp,[sp,-16]! // save registres
ldr x6,qAdrqTabOperand1
ldr x7,qAdrqTabOperand2
ldr x8,qAdrqTabOperation
ldr x10,qAdrsBuffer
mov x4,#0 // buffer indice
mov x9,#1
1:
ldr x13,[x6,x9,lsl 3] // operand 1
ldr x11,[x7,x9,lsl 3] // operand 2
ldr x12,[x8,x9,lsl 3] // operator
cmp x12,#'-'
beq 2f
cmp x12,#'/'
beq 2f
b 3f
2: // if division or soustraction
cmp x13,x11 // reverse operand if operand 1 is < operand 2
bge 3f
mov x2,x13
mov x13,x11
mov x11,x2
3: // conversion operand 1 = x13
mov x1,#10
udiv x2,x13,x1
msub x3,x1,x2,x13
cmp x2,#0
beq 31f
add x2,x2,#0x30
strb w2,[x10,x4]
add x4,x4,#1
31:
add x3,x3,#0x30
strb w3,[x10,x4]
add x4,x4,#1
ldr x2,[x7,x9,lsl 3]
 
strb w12,[x10,x4] // operator
add x4,x4,#1
mov x1,#10 // conversion operand 2 = x11
udiv x2,x11,x1
msub x3,x2,x1,x11
cmp x2,#0
beq 32f
add x2,x2,#0x30
strb w2,[x10,x4]
add x4,x4,#1
32:
add x3,x3,#0x30
strb w3,[x10,x4]
add x4,x4,#1
mov x0,#'='
strb w0,[x10,x4] // compute sous total
add x4,x4,#1
cmp x12,'+' // addition
bne 33f
add x0,x13,x11
b 37f
33:
cmp x12,'-' // soustraction
bne 34f
sub x0,x13,x11
b 37f
34:
cmp x12,'*' // multiplication
bne 35f
mul x0,x13,x11
b 37f
35:
cmp x12,'/' // division
bne 36f
udiv x0,x13,x11
b 37f
36: // error
ldr x0,qAdrszMessErrOper
bl affichageMess
b 100f
37: // and conversion ascii
mov x1,#10
udiv x2,x0,x1
msub x3,x2,x1,x0
cmp x2,#0
beq 36f
add x2,x2,#0x30
strb w2,[x10,x4]
add x4,x4,#1
36:
add x3,x3,#0x30
strb w3,[x10,x4]
add x4,x4,#1
mov x0,#'\n'
strb w0,[x10,x4]
add x4,x4,#1
add x9,x9,1
cmp x9,#NBDIGITS
blt 1b
mov x1,#0
strb w1,[x10,x4] // store 0 final
100:
ldp x12,fp,[sp],16 // restaur des 2 registres
ldp x10,x11,[sp],16 // restaur des 2 registres
ldp x8,x9,[sp],16 // restaur des 2 registres
ldp x6,x7,[sp],16 // restaur des 2 registres
ldp x4,x5,[sp],16 // restaur des 2 registres
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
qAdrsBuffer: .quad sBuffer
qAdrszMessErrOper: .quad szMessErrOper
/******************************************************************/
/* string entry */
/******************************************************************/
/* x0 return the first character of human entry */
saisie:
stp x1,lr,[sp,-16]! // save registres
stp x2,x8,[sp,-16]! // save registres
mov x0,#STDIN // Linux input console
ldr x1,qAdrsBuffer // buffer address
mov x2,#BUFFERSIZE // buffer size
mov x8,#READ // request to read datas
svc 0 // call system
ldr x1,qAdrsBuffer // buffer address
ldrb w0,[x1] // load first character
100:
ldp x2,x8,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
/***************************************************/
/* Generation random number */
/***************************************************/
/* x0 contains limit */
genereraleas:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
ldr x4,qAdrqGraine
ldr x2,[x4]
ldr x3,qNbDep1
mul x2,x3,x2
ldr x3,qNbDep2
add x2,x2,x3
str x2,[x4] // maj de la graine pour l appel suivant
cmp x0,#0
beq 100f
add x1,x0,#1 // divisor
mov x0,x2 // dividende
udiv x3,x2,x1
msub x0,x3,x1,x0 // résult = remainder
100: // end function
 
ldp x4,x5,[sp],16 // restaur des 2 registres
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
/*****************************************************/
qAdrqGraine: .quad qGraine
qNbDep1: .quad 0x0019660d
qNbDep2: .quad 0x3c6ef35f
/********************************************************/
/* File Include fonctions */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"
</syntaxhighlight>
{{Output}}
<pre>
The four digits are 6 8 3 1 and the score is 24.
Solution :
6*8=48
3-1=2
48/2=24
 
New game (y/n) ?
y
The four digits are 8 6 6 5 and the score is 24.
Solution :
8-5=3
6*3=18
6+18=24
 
New game (y/n) ?
</pre>
 
=={{header|ABAP}}==
Line 10 ⟶ 526:
 
Note: the permute function was locally from [[Permutations#ABAP|here]]
<langsyntaxhighlight ABAPlang="abap">data: lv_flag type c,
lv_number type i,
lt_numbers type table of i.
Line 207 ⟶ 723:
modify iv_set index lv_perm from lv_temp_2.
modify iv_set index lv_len from lv_temp.
endform.</langsyntaxhighlight>
 
Sample Runs:
Line 500 ⟶ 1,016:
=={{header|Argile}}==
{{works with|Argile|1.0.0}}
<langsyntaxhighlight Argilelang="argile">die "Please give 4 digits as argument 1\n" if argc < 2
 
print a function that given four digits argv[1] subject to the rules of \
Line 597 ⟶ 1,113:
(roperators[(rrop[rpn][2])]) (rdigits[3]);
return buffer as text
nil</langsyntaxhighlight>
Examples:
<pre>$ arc 24_game_solve.arg -o 24_game_solve.c
Line 609 ⟶ 1,125:
$ ./24_game_solve 1127
(1+2)*(1+7)</pre>
=={{header|ARM Assembly}}==
{{works with|as|Raspberry Pi}}
<syntaxhighlight lang="arm assembly">
/* ARM assembly Raspberry PI */
/* program game24Solver.s */
 
/* REMARK 1 : this program use routines in a include file
see task Include a file language arm assembly
for the routine affichageMess conversion10
see at end of this program the instruction include */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes */
/************************************/
.include "../constantes.inc"
.equ STDIN, 0 @ Linux input console
.equ READ, 3 @ Linux syscall
.equ NBDIGITS, 4 @ digits number
.equ TOTAL, 24
.equ BUFFERSIZE, 80
 
/*********************************/
/* Initialized data */
/*********************************/
.data
szMessRules: .ascii "24 Game\n"
.ascii "The program will display four randomly-generated \n"
.asciz "single-digit numbers and search a solution for a total to 24\n\n"
 
szMessDigits: .asciz "The four digits are @ @ @ @ and the score is 24. \n"
szMessOK: .asciz "Solution : \n"
szMessNotOK: .asciz "No solution for this problem !! \n"
szMessNewGame: .asciz "New game (y/n) ? \n"
szCarriageReturn: .asciz "\n"
.align 4
iGraine: .int 123456
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
.align 4
sZoneConv: .skip 24
sBuffer: .skip BUFFERSIZE
iTabDigit: .skip 4 * NBDIGITS @ digits table
iTabOperand1: .skip 4 * NBDIGITS @ operand 1 table
iTabOperand2: .skip 4 * NBDIGITS @ operand 2 table
iTabOperation: .skip 4 * NBDIGITS @ operator table
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: @ entry of program
ldr r0,iAdrszMessRules @ display rules
bl affichageMess
1:
mov r3,#0
ldr r12,iAdriTabDigit
ldr r5,iAdrszMessDigits
2: @ loop generate random digits
mov r0,#8
bl genereraleas
add r0,r0,#1
str r0,[r12,r3,lsl #2] @ store in table
ldr r1,iAdrsZoneConv
bl conversion10 @ call decimal conversion
mov r2,#0
strb r2,[r1,r0] @ reduce size display area with zéro final
mov r0,r5
ldr r1,iAdrsZoneConv @ insert conversion in message
bl strInsertAtCharInc
mov r5,r0
add r3,r3,#1
cmp r3,#NBDIGITS @ end ?
blt 2b @ no -> loop
mov r0,r5
bl affichageMess
mov r0,#0 @ start leval
mov r1,r12 @ address digits table
bl searchSoluce
cmp r0,#-1 @ solution ?
bne 3f @ no
ldr r0,iAdrszMessOK
bl affichageMess
bl writeSoluce @ yes -> write solution in buffer
ldr r0,iAdrsBuffer @ and display buffer
bl affichageMess
b 10f
3: @ display message no solution
ldr r0,iAdrszMessNotOK
bl affichageMess
 
 
10: @ display new game ?
ldr r0,iAdrszCarriageReturn
bl affichageMess
ldr r0,iAdrszMessNewGame
bl affichageMess
bl saisie
cmp r0,#'y'
beq 1b
cmp r0,#'Y'
beq 1b
100: @ standard end of the program
mov r0, #0 @ return code
mov r7, #EXIT @ request to exit program
svc #0 @ perform the system call
iAdrszCarriageReturn: .int szCarriageReturn
iAdrszMessRules: .int szMessRules
iAdrszMessDigits: .int szMessDigits
iAdrszMessNotOK: .int szMessNotOK
iAdrszMessOK: .int szMessOK
iAdrszMessNewGame: .int szMessNewGame
iAdrsZoneConv: .int sZoneConv
iAdriTabDigit: .int iTabDigit
/******************************************************************/
/* recherche solution */
/******************************************************************/
/* r0 level */
/* r1 table value address */
/* r0 return -1 if ok */
searchSoluce:
push {r1-r12,lr} @ save registers
sub sp,#4* NBDIGITS @ reserve size new digits table
mov fp,sp @ frame pointer = address stack
mov r10,r1 @ save table
add r9,r0,#1 @ new level
rsb r3,r9,#NBDIGITS @ last element digits table
ldr r4,[r1,r3,lsl #2] @ load last element
cmp r4,#TOTAL @ equal to total to search ?
bne 0f @ no
cmp r9,#NBDIGITS @ all digits are used ?
bne 0f @ no
mov r0,#-1 @ yes -> it is ok -> end
b 100f
0:
mov r5,#0 @ indice loop 1
1: @ begin loop 1
cmp r5,r3
bge 9f
ldr r4,[r10,r5,lsl #2] @ load first operand
ldr r8,iAdriTabOperand1
str r4,[r8,r9,lsl #2] @ and store in operand1 table
add r6,r5,#1 @ indice loop 2
2: @ begin loop 2
cmp r6,r3
bgt 8f
ldr r12,[r10,r6,lsl #2] @ load second operand
ldr r8,iAdriTabOperand2
str r12,[r8,r9,lsl #2] @ and store in operand2 table
mov r7,#0 @ k
mov r8,#0 @ n
3:
cmp r7,r5
beq 4f
cmp r7,r6
beq 4f
ldr r0,[r10,r7,lsl #2] @ copy other digits in new table on stack
str r0,[fp,r8,lsl #2]
add r8,r8,#1
4:
add r7,r7,#1
cmp r7,r3
ble 3b
 
add r7,r4,r12 @ addition test
str r7,[fp,r8,lsl #2] @ store result of addition
mov r7,#'+'
ldr r0,iAdriTabOperation
str r7,[r0,r9,lsl #2] @ store operator
mov r0,r9 @ pass new level
mov r1,fp @ pass new table address on stack
bl searchSoluce
cmp r0,#0
blt 100f
@ soustraction test
cmp r4,r12
subgt r7,r4,r12
suble r7,r12,r4
str r7,[fp,r8,lsl #2]
mov r7,#'-'
ldr r0,iAdriTabOperation
str r7,[r0,r9,lsl #2]
mov r0,r9
mov r1,fp
bl searchSoluce
cmp r0,#0
blt 100f
mul r7,r4,r12 @ multiplication test
str r7,[fp,r8,lsl #2]
mov r7,#'*'
//vidregtit mult
ldr r0,iAdriTabOperation
str r7,[r0,r9,lsl #2]
mov r0,r9
mov r1,fp
bl searchSoluce
cmp r0,#0
blt 100f
5: @ division test
push {r1-r3}
mov r0,r4
mov r1,r12
bl division
// mov r7,r9
cmp r3,#0
bne 6f
str r2,[fp,r8,lsl #2]
mov r7,#'/'
ldr r0,iAdriTabOperation
str r7,[r0,r9,lsl #2]
mov r0,r9
mov r1,fp
bl searchSoluce
b 7f
6:
mov r0,r12
mov r1,r4
bl division
cmp r3,#0
bne 7f
str r2,[fp,r8,lsl #2]
mov r7,#'/'
ldr r0,iAdriTabOperation
str r7,[r0,r9,lsl #2]
mov r0,r9
mov r1,fp
bl searchSoluce
7:
pop {r1-r3}
cmp r0,#0
blt 100f
add r6,r6,#1 @ increment indice loop 2
b 2b
 
8:
add r5,r5,#1 @ increment indice loop 1
b 1b
9:
100:
add sp,#4* NBDIGITS @ stack alignement
pop {r1-r12,lr}
bx lr @ return
iAdriTabOperand1: .int iTabOperand1
iAdriTabOperand2: .int iTabOperand2
iAdriTabOperation: .int iTabOperation
/******************************************************************/
/* write solution */
/******************************************************************/
writeSoluce:
push {r1-r12,lr} @ save registers
ldr r6,iAdriTabOperand1
ldr r7,iAdriTabOperand2
ldr r8,iAdriTabOperation
ldr r10,iAdrsBuffer
mov r4,#0 @ buffer indice
mov r9,#1
1:
ldr r5,[r6,r9,lsl #2] @ operand 1
ldr r11,[r7,r9,lsl #2] @ operand 2
ldr r12,[r8,r9,lsl #2] @ operator
cmp r12,#'-'
beq 2f
cmp r12,#'/'
beq 2f
b 3f
2: @ if division or soustraction
cmp r5,r11 @ reverse operand if operand 1 is < operand 2
movlt r2,r5
movlt r5,r11
movlt r11,r2
3: @ conversion operand 1 = r0
mov r0,r5
mov r1,#10
bl division
cmp r2,#0
addne r2,r2,#0x30
strneb r2,[r10,r4]
addne r4,r4,#1
add r3,r3,#0x30
strb r3,[r10,r4]
add r4,r4,#1
ldr r2,[r7,r9,lsl #2]
 
strb r12,[r10,r4] @ operator
add r4,r4,#1
mov r0,r11 @ conversion operand 2
mov r1,#10
bl division
cmp r2,#0
addne r2,r2,#0x30
strneb r2,[r10,r4]
addne r4,r4,#1
add r3,r3,#0x30
strb r3,[r10,r4]
add r4,r4,#1
mov r0,#'='
str r0,[r10,r4] @ conversion sous total
add r4,r4,#1
cmp r12,#'+'
addeq r0,r5,r11
cmp r12,#'-'
subeq r0,r5,r11
cmp r12,#'*'
muleq r0,r5,r11
cmp r12,#'/'
udiveq r0,r5,r11
 
mov r1,#10
bl division
cmp r2,#0
addne r2,r2,#0x30
strneb r2,[r10,r4]
addne r4,r4,#1
add r3,r3,#0x30
strb r3,[r10,r4]
add r4,r4,#1
mov r0,#'\n'
str r0,[r10,r4]
add r4,r4,#1
add r9,#1
cmp r9,#NBDIGITS
blt 1b
mov r1,#0
strb r1,[r10,r4] @ store 0 final
100:
pop {r1-r12,lr}
bx lr @ return
iAdrsBuffer: .int sBuffer
 
/******************************************************************/
/* string entry */
/******************************************************************/
/* r0 return the first character of human entry */
saisie:
push {r1-r7,lr} @ save registers
mov r0,#STDIN @ Linux input console
ldr r1,iAdrsBuffer @ buffer address
mov r2,#BUFFERSIZE @ buffer size
mov r7,#READ @ request to read datas
svc 0 @ call system
ldr r1,iAdrsBuffer @ buffer address
ldrb r0,[r1] @ load first character
100:
pop {r1-r7,lr}
bx lr @ return
/***************************************************/
/* Generation random number */
/***************************************************/
/* r0 contains limit */
genereraleas:
push {r1-r4,lr} @ save registers
ldr r4,iAdriGraine
ldr r2,[r4]
ldr r3,iNbDep1
mul r2,r3,r2
ldr r3,iNbDep2
add r2,r2,r3
str r2,[r4] @ maj de la graine pour l appel suivant
cmp r0,#0
beq 100f
add r1,r0,#1 @ divisor
mov r0,r2 @ dividende
bl division
mov r0,r3 @ résult = remainder
100: @ end function
pop {r1-r4,lr} @ restaur registers
bx lr @ return
/*****************************************************/
iAdriGraine: .int iGraine
iNbDep1: .int 0x343FD
iNbDep2: .int 0x269EC3
/***************************************************/
/* ROUTINES INCLUDE */
/***************************************************/
.include "../affichage.inc"
 
</syntaxhighlight>
{{output}}
<pre>
New game (y/n) ?
y
The four digits are 8 3 9 1 and the score is 24.
Solution :
8*9=72
3*1=3
72/3=24
 
New game (y/n) ?
y
The four digits are 7 7 9 4 and the score is 24.
No solution for this problem !!
 
New game (y/n) ?
y
The four digits are 3 5 8 9 and the score is 24.
Solution :
3*9=27
8-5=3
27-3=24
 
New game (y/n) ?
</pre>
=={{header|AutoHotkey}}==
{{works with|AutoHotkey_L}}
Output is in RPN.
<langsyntaxhighlight AHKlang="ahk">#NoEnv
InputBox, NNNN ; user input 4 digits
NNNN := RegExReplace(NNNN, "(\d)(?=\d)", "$1,") ; separate with commas for the sort command
Line 720 ⟶ 1,650:
o := A_LoopField o
return o
}</langsyntaxhighlight>
{{out}}for 1127:
<pre>
Line 735 ⟶ 1,665:
 
=={{header|BBC BASIC}}==
<langsyntaxhighlight lang="bbcbasic">
PROCsolve24("1234")
PROCsolve24("6789")
Line 792 ⟶ 1,722:
IF I% > 4 PRINT "No solution found"
ENDPROC
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 802 ⟶ 1,732:
 
=={{header|C}}==
This is a solver that's generic enough to deal with more than 4 numbers,
goals other than 24, or different digit ranges.
It guarantees a solution if there is one.
Its output format is reasonably good looking, though not necessarily optimal.
<lang C>#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
Tested with GCC 10.2.0, but should work with all versions supporting C99.<br>
#define n_cards 4
Provided code prints all solutions or nothing in case no solutions are found.<br>
#define solve_goal 24
It can be modified or extended to work with more than 4 numbers, goals other than 24 and additional operations.<br>
#define max_digit 9
Note: This a brute-force approach with time complexity <em>O(6<sup>n</sup>.n.(2n-3)!!)</em> and recursion depth <em>n</em>.<br>
 
<syntaxhighlight lang="c">#include <stdio.h>
typedef struct { int num, denom; } frac_t, *frac;
typedef enum { C_NUM = 0, C_ADD, C_SUB, C_MUL, C_DIV } op_type;
 
typedef struct expr_t{int *exprval, op, left, right;} Node;
typedef struct expr_t {
op_type op;
expr left, right;
int value;
} expr_t;
 
Node nodes[10000];
void show_expr(expr e, op_type prec, int is_right)
int iNodes;
{
 
const char * op;
int b;
switch(e->op) {
float eval(Node x){
case C_NUM: printf("%d", e->value);
if (x.op != -1){
return;
casefloat C_ADD:l = eval(nodes[x.left]), opr = " + "; breakeval(nodes[x.right]);
case C_SUB: switch(x.op = " - "; break;){
case C_MUL: case 0: op = " x ";return breakl+r;
case C_DIV: case 1: op = " / ";return breakl-r;
case 2: return r-l;
case 3: return l*r;
case 4: return r?l/r:(b=1,0);
case 5: return l?r/l:(b=1,0);
}
}
 
else return x.val*1.;
if ((e->op == prec && is_right) || e->op < prec) printf("(");
show_expr(e->left, e->op, 0);
printf("%s", op);
show_expr(e->right, e->op, 1);
if ((e->op == prec && is_right) || e->op < prec) printf(")");
}
 
void eval_exprshow(exprNode e, frac fx){
if (x.op != -1){
{
frac_t left, rightprintf("(");
if switch(e->x.op == C_NUM) {
case 0: show(nodes[x.left]); printf(" f->num+ ="); e->valueshow(nodes[x.right]); break;
case 1: show(nodes[x.left]); printf(" f->denom ="); 1show(nodes[x.right]); break;
case 2: show(nodes[x.right]); printf(" return- "); show(nodes[x.left]); break;
case 3: show(nodes[x.left]); printf(" * "); show(nodes[x.right]); break;
}
case 4: show(nodes[x.left]); printf(" / "); show(nodes[x.right]); break;
eval_expr(e->left, &left);
eval_expr case 5: show(e->nodes[x.right,]); &rightprintf(" / "); show(nodes[x.left]); break;
switch (e->op) {
case C_ADD:
f->num = left.num * right.denom + left.denom * right.num;
f->denom = left.denom * right.denom;
return;
case C_SUB:
f->num = left.num * right.denom - left.denom * right.num;
f->denom = left.denom * right.denom;
return;
case C_MUL:
f->num = left.num * right.num;
f->denom = left.denom * right.denom;
return;
case C_DIV:
f->num = left.num * right.denom;
f->denom = left.denom * right.num;
return;
default:
fprintf(stderr, "Unknown op: %d\n", e->op);
return;
}
printf(")");
}
else printf("%d", x.val);
}
int solve(expr ex_in[], int len)
{
int i, j;
expr_t node;
expr ex[n_cards];
frac_t final;
 
int float_fix(float x){ return x < 0.00001 && x > -0.00001; }
if (len == 1) {
 
eval_expr(ex_in[0], &final);
void solutions(int a[], int n, float t, int s){
if (final.num == final.denom * solve_goal && final.denom) {
if (s == n){
show_expr(ex_in[0], 0, 0);
b = return 10;
float e = eval(nodes[0]); }
return 0;
if (!b && float_fix(e-t)){
show(nodes[0]);
printf("\n");
}
}
else{
nodes[iNodes++] = (typeof(Node)){a[s],-1,-1,-1};
for (int op = 0; op < 6; op++){
int k = iNodes-1;
for (int i = 0; i < k; i++){
nodes[iNodes++] = nodes[i];
nodes[i] = (typeof(Node)){-1,op,iNodes-1,iNodes-2};
solutions(a, n, t, s+1);
nodes[i] = nodes[--iNodes];
}
}
iNodes--;
}
};
 
int main(){
for (i = 0; i < len - 1; i++) {
// define problem
for (j = i + 1; j < len; j++)
ex[j - 1] = ex_in[j];
ex[i] = &node;
for (j = i + 1; j < len; j++) {
node.left = ex_in[i];
node.right = ex_in[j];
for (node.op = C_ADD; node.op <= C_DIV; node.op++)
if (solve(ex, len - 1))
return 1;
 
int a[4] = {8, 3, 8, 3};
node.left = ex_in[j];
float t = 24;
node.right = ex_in[i];
node.op = C_SUB;
if (solve(ex, len - 1)) return 1;
node.op = C_DIV;
if (solve(ex, len - 1)) return 1;
 
// print all solutions
ex[j] = ex_in[j];
}
ex[i] = ex_in[i];
}
 
nodes[0] = (typeof(Node)){a[0],-1,-1,-1};
return 0;
iNodes = 1;
}
 
solutions(a, sizeof(a)/sizeof(int), t, 1);
int solve24(int n[])
{
int i;
expr_t ex[n_cards];
expr e[n_cards];
for (i = 0; i < n_cards; i++) {
e[i] = ex + i;
ex[i].op = C_NUM;
ex[i].left = ex[i].right = 0;
ex[i].value = n[i];
}
return solve(e, n_cards);
}
 
return 0;
int main()
}</syntaxhighlight>
{
int i, j, n[] = { 3, 3, 8, 8, 9 };
srand(time(0));
 
for (j = 0; j < 10; j++) {
for (i = 0; i < n_cards; i++) {
n[i] = 1 + (double) rand() * max_digit / RAND_MAX;
printf(" %d", n[i]);
}
printf(": ");
printf(solve24(n) ? "\n" : "No solution\n");
}
 
return 0;
}</lang>
{{out}}
<pre> 1 8 2 1: 1 x 8 x (2 + 1)
6 8 2 8: 6 + 8 + 2 + 8
4 2 8 1: (4 - 2 + 1) x 8
3 1 9 9: (9 - 1) / (3 / 9)
5 7 5 1: No solution
5 8 4 1: (5 + 1) x (8 - 4)
8 3 4 9: 8 + 3 + 4 + 9
3 7 4 4: ((3 + 7) - 4) x 4
5 6 4 1: 4 / (1 - 5 / 6)
5 5 9 8: 5 x 5 - 9 + 8</pre>
For the heck of it, using seven numbers ranging from 0 to 99, trying to calculate 1:
<pre> 54 64 44 67 60 54 97: (54 + 64 + 44) / 54 + 60 / (67 - 97)
83 3 52 50 14 48 55: 55 - (((83 + 3 + 52) - 50 + 14) - 48)
70 14 26 6 4 50 19: ((70 + 14 + 26) / 4 - 19) x 6 - 50
75 29 61 95 1 6 73: 6 / (73 - ((75 + 29 + 61) - 95)) - 1
99 65 59 54 29 3 21: 3 - (99 + 65 + 54) / (59 + 29 + 21)
88 57 18 72 60 70 22: (72 - 70) x (60 + 22) - (88 + 57 + 18)
73 18 76 44 32 3 49: 32 / (49 - (44 + 3)) - ((73 + 18) - 76)
36 53 68 12 82 30 8: ((36 + 53 + 68) - 82) / 30 - 12 / 8
83 35 81 82 99 40 36: ((83 + 35) x 81 - 82 x 99) / 40 / 36
29 43 57 18 1 74 89: (1 + 74) / (((29 + 43) - 57) / 18) - 89</pre>
 
=={{header|C++}}==
{{works with|C++11}}
{{works with|GCC|4.8}}
 
This code may be extended to work with more than 4 numbers, goals other than 24, or different digit ranges. Operations have been manually determined for these parameters, with the belief they are complete.
 
<langsyntaxhighlight lang="cpp">
#include <iostream>
#include <ratio>
Line 1,056 ⟶ 1,909:
if(d[0] * d[1] == gameGoal * (d[2] - d[3])) printOperation("( ", " * ", " ) / ( ", " - ", " )");
// Operations with 2 symbols *, one symbol /:
if(d[0] * d[1] * d[2] == gameGoal * d[3]) printOperation("", " * ", " /* ", " / ");
if(d[0] * d[1] == gameGoal * d[2] * d[3]) printOperation("", " * ", " / ( ", " * ", " )");
// Operations with 2 symbols /, one symbol -:
if(d[0] * d[3] == gameGoal * (d[1] * d[3] - d[2])) printOperation("", " / ( ", " - ", " / ", " )");
// Operations with 2 symbols /, one symbol *:
if(d[0] * d[1] == gameGoal * d[2] * d[3]) printOperation("( ", " * ", " / ", " ) / ", "");
} while(std::next_permutation(d.begin(), d.end())); // All operations are repeated for all possible permutations of the numbers.
}
return 0;
}
</syntaxhighlight>
</lang>
 
{{out}}
Line 1,114 ⟶ 1,969:
(( 5 + 3 ) * 3 ) / 1
</pre>
 
=={{header|C sharp|C#}}==
Generate binary trees -> generate permutations -> create expression -> evaluate expression<br/>
This works with other targets and more numbers but it will of course become slower.<br/>
Redundant expressions are filtered out (based on https://www.4nums.com/theory/) but I'm not sure I caught them all.
{{works with|C sharp|8}}
<syntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using static System.Linq.Enumerable;
 
public static class Solve24Game
{
public static void Main2() {
var testCases = new [] {
new [] { 1,1,2,7 },
new [] { 1,2,3,4 },
new [] { 1,2,4,5 },
new [] { 1,2,7,7 },
new [] { 1,4,5,6 },
new [] { 3,3,8,8 },
new [] { 4,4,5,9 },
new [] { 5,5,5,5 },
new [] { 5,6,7,8 },
new [] { 6,6,6,6 },
new [] { 6,7,8,9 },
};
foreach (var t in testCases) Test(24, t);
Test(100, 9,9,9,9,9,9);
 
static void Test(int target, params int[] numbers) {
foreach (var eq in GenerateEquations(target, numbers)) Console.WriteLine(eq);
Console.WriteLine();
}
}
 
static readonly char[] ops = { '*', '/', '+', '-' };
public static IEnumerable<string> GenerateEquations(int target, params int[] numbers) {
var operators = Repeat(ops, numbers.Length - 1).CartesianProduct().Select(e => e.ToArray()).ToList();
return (
from pattern in Patterns(numbers.Length)
let expression = CreateExpression(pattern)
from ops in operators
where expression.WithOperators(ops).HasPreferredTree()
from permutation in Permutations(numbers)
let expr = expression.WithValues(permutation)
where expr.Value == target && expr.HasPreferredValues()
select $"{expr.ToString()} = {target}")
.Distinct()
.DefaultIfEmpty($"Cannot make {target} with {string.Join(", ", numbers)}");
}
 
///<summary>Generates postfix expression trees where 1's represent operators and 0's represent numbers.</summary>
static IEnumerable<int> Patterns(int length) {
if (length == 1) yield return 0; //0
if (length == 2) yield return 1; //001
if (length < 3) yield break;
//Of each tree, the first 2 bits must always be 0 and the last bit must be 1. Generate the bits in between.
length -= 2;
int len = length * 2 + 3;
foreach (int permutation in BinaryPatterns(length, length * 2)) {
(int p, int l) = ((permutation << 1) + 1, len);
if (IsValidPattern(ref p, ref l)) yield return (permutation << 1) + 1;
}
}
 
///<summary>Generates all numbers with the given number of 1's and total length.</summary>
static IEnumerable<int> BinaryPatterns(int ones, int length) {
int initial = (1 << ones) - 1;
int blockMask = (1 << length) - 1;
for (int v = initial; v >= initial; ) {
yield return v;
int w = (v | (v - 1)) + 1;
w |= (((w & -w) / (v & -v)) >> 1) - 1;
v = w & blockMask;
}
}
 
static bool IsValidPattern(ref int pattern, ref int len) {
bool isNumber = (pattern & 1) == 0;
pattern >>= 1;
len--;
if (isNumber) return true;
IsValidPattern(ref pattern, ref len);
IsValidPattern(ref pattern, ref len);
return len == 0;
}
 
static Expr CreateExpression(int pattern) {
return Create();
 
Expr Create() {
bool isNumber = (pattern & 1) == 0;
pattern >>= 1;
if (isNumber) return new Const(0);
Expr right = Create();
Expr left = Create();
return new Binary('*', left, right);
}
}
 
static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences) {
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from acc in accumulator
from item in sequence
select acc.Concat(new [] { item }));
}
 
private static List<int> helper = new List<int>();
public static IEnumerable<T[]> Permutations<T>(params T[] input) {
if (input == null || input.Length == 0) yield break;
helper.Clear();
for (int i = 0; i < input.Length; i++) helper.Add(i);
while (true) {
yield return input;
int cursor = helper.Count - 2;
while (cursor >= 0 && helper[cursor] > helper[cursor + 1]) cursor--;
if (cursor < 0) break;
int i = helper.Count - 1;
while (i > cursor && helper[i] < helper[cursor]) i--;
(helper[cursor], helper[i]) = (helper[i], helper[cursor]);
(input[cursor], input[i]) = (input[i], input[cursor]);
int firstIndex = cursor + 1;
for (int lastIndex = helper.Count - 1; lastIndex > firstIndex; ++firstIndex, --lastIndex) {
(helper[firstIndex], helper[lastIndex]) = (helper[lastIndex], helper[firstIndex]);
(input[firstIndex], input[lastIndex]) = (input[lastIndex], input[firstIndex]);
}
}
}
 
static Expr WithOperators(this Expr expr, char[] operators) {
int i = 0;
SetOperators(expr, operators, ref i);
return expr;
 
static void SetOperators(Expr expr, char[] operators, ref int i) {
if (expr is Binary b) {
b.Symbol = operators[i++];
SetOperators(b.Right, operators, ref i);
SetOperators(b.Left, operators, ref i);
}
}
}
 
static Expr WithValues(this Expr expr, int[] values) {
int i = 0;
SetValues(expr, values, ref i);
return expr;
 
static void SetValues(Expr expr, int[] values, ref int i) {
if (expr is Binary b) {
SetValues(b.Left, values, ref i);
SetValues(b.Right, values, ref i);
} else {
expr.Value = values[i++];
}
}
}
 
static bool HasPreferredTree(this Expr expr) => expr switch {
Const _ => true,
// a / b * c => a * c / b
((_, '/' ,_), '*', _) => false,
// c + a * b => a * b + c
(var l, '+', (_, '*' ,_) r) when l.Depth < r.Depth => false,
// c + a / b => a / b + c
(var l, '+', (_, '/' ,_) r) when l.Depth < r.Depth => false,
// a * (b + c) => (b + c) * a
(var l, '*', (_, '+' ,_) r) when l.Depth < r.Depth => false,
// a * (b - c) => (b - c) * a
(var l, '*', (_, '-' ,_) r) when l.Depth < r.Depth => false,
// (a +- b) + (c */ d) => ((c */ d) + a) +- b
((_, var p, _), '+', (_, var q, _)) when "+-".Contains(p) && "*/".Contains(q) => false,
// a + (b + c) => (a + b) + c
(var l, '+', (_, '+' ,_) r) => false,
// a + (b - c) => (a + b) - c
(var l, '+', (_, '-' ,_) r) => false,
// a - (b + c) => (a - b) + c
(_, '-', (_, '+', _)) => false,
// a * (b * c) => (a * b) * c
(var l, '*', (_, '*' ,_) r) => false,
// a * (b / c) => (a * b) / c
(var l, '*', (_, '/' ,_) r) => false,
// a / (b / c) => (a * c) / b
(var l, '/', (_, '/' ,_) r) => false,
// a - (b - c) * d => (c - b) * d + a
(_, '-', ((_, '-' ,_), '*', _)) => false,
// a - (b - c) / d => (c - b) / d + a
(_, '-', ((_, '-' ,_), '/', _)) => false,
// a - (b - c) => a + c - b
(_, '-', (_, '-', _)) => false,
// (a - b) + c => (a + c) - b
((_, '-', var b), '+', var c) => false,
 
(var l, _, var r) => l.HasPreferredTree() && r.HasPreferredTree()
};
 
static bool HasPreferredValues(this Expr expr) => expr switch {
Const _ => true,
 
// -a + b => b - a
(var l, '+', var r) when l.Value < 0 && r.Value >= 0 => false,
// b * a => a * b
(var l, '*', var r) when l.Depth == r.Depth && l.Value > r.Value => false,
// b + a => a + b
(var l, '+', var r) when l.Depth == r.Depth && l.Value > r.Value => false,
// (b o c) * (a o d) => (a o d) * (b o c)
((var a, _, _) l, '*', (var c, _, _) r) when l.Value == r.Value && l.Depth == r.Depth && a.Value < c.Value => false,
// (b o c) + (a o d) => (a o d) + (b o c)
((var a, var p, _) l, '+', (var c, var q, _) r) when l.Value == r.Value && l.Depth == r.Depth && a.Value < c.Value => false,
// (a * c) * b => (a * b) * c
((_, '*', var c), '*', var b) when b.Value < c.Value => false,
// (a + c) + b => (a + b) + c
((_, '+', var c), '+', var b) when b.Value < c.Value => false,
// (a - b) - c => (a - c) - b
((_, '-', var b), '-', var c) when b.Value < c.Value => false,
// a / 1 => a * 1
(_, '/', var b) when b.Value == 1 => false,
// a * b / b => a + b - b
((_, '*', var b), '/', var c) when b.Value == c.Value => false,
// a * 1 * 1 => a + 1 - 1
((_, '*', var b), '*', var c) when b.Value == 1 && c.Value == 1 => false,
 
(var l, _, var r) => l.HasPreferredValues() && r.HasPreferredValues()
};
 
private struct Fraction : IEquatable<Fraction>, IComparable<Fraction>
{
public readonly int Numerator, Denominator;
 
public Fraction(int numerator, int denominator)
=> (Numerator, Denominator) = (numerator, denominator) switch
{
(_, 0) => (Math.Sign(numerator), 0),
(0, _) => (0, 1),
(_, var d) when d < 0 => (-numerator, -denominator),
_ => (numerator, denominator)
};
 
public static implicit operator Fraction(int i) => new Fraction(i, 1);
public static Fraction operator +(Fraction a, Fraction b) =>
new Fraction(a.Numerator * b.Denominator + a.Denominator * b.Numerator, a.Denominator * b.Denominator);
public static Fraction operator -(Fraction a, Fraction b) =>
new Fraction(a.Numerator * b.Denominator + a.Denominator * -b.Numerator, a.Denominator * b.Denominator);
public static Fraction operator *(Fraction a, Fraction b) =>
new Fraction(a.Numerator * b.Numerator, a.Denominator * b.Denominator);
public static Fraction operator /(Fraction a, Fraction b) =>
new Fraction(a.Numerator * b.Denominator, a.Denominator * b.Numerator);
 
public static bool operator ==(Fraction a, Fraction b) => a.CompareTo(b) == 0;
public static bool operator !=(Fraction a, Fraction b) => a.CompareTo(b) != 0;
public static bool operator <(Fraction a, Fraction b) => a.CompareTo(b) < 0;
public static bool operator >(Fraction a, Fraction b) => a.CompareTo(b) > 0;
public static bool operator <=(Fraction a, Fraction b) => a.CompareTo(b) <= 0;
public static bool operator >=(Fraction a, Fraction b) => a.CompareTo(b) >= 0;
 
public bool Equals(Fraction other) => Numerator == other.Numerator && Denominator == other.Denominator;
public override string ToString() => Denominator == 1 ? Numerator.ToString() : $"[{Numerator}/{Denominator}]";
 
public int CompareTo(Fraction other) => (Numerator, Denominator, other.Numerator, other.Denominator) switch {
var ( n1, d1, n2, d2) when n1 == n2 && d1 == d2 => 0,
( 0, 0, _, _) => (-1),
( _, _, 0, 0) => 1,
var ( n1, d1, n2, d2) when d1 == d2 => n1.CompareTo(n2),
(var n1, 0, _, _) => Math.Sign(n1),
( _, _, var n2, 0) => Math.Sign(n2),
var ( n1, d1, n2, d2) => (n1 * d2).CompareTo(n2 * d1)
};
}
 
private abstract class Expr
{
protected Expr(char symbol) => Symbol = symbol;
public char Symbol { get; set; }
public abstract Fraction Value { get; set; }
public abstract int Depth { get; }
public abstract void Deconstruct(out Expr left, out char symbol, out Expr right);
}
 
private sealed class Const : Expr
{
public Const(Fraction value) : base('c') => Value = value;
public override Fraction Value { get; set; }
public override int Depth => 0;
public override void Deconstruct(out Expr left, out char symbol, out Expr right) => (left, symbol, right) = (this, Symbol, this);
public override string ToString() => Value.ToString();
}
 
private sealed class Binary : Expr
{
public Binary(char symbol, Expr left, Expr right) : base(symbol) => (Left, Right) = (left, right);
public Expr Left { get; }
public Expr Right { get; }
public override int Depth => Math.Max(Left.Depth, Right.Depth) + 1;
public override void Deconstruct(out Expr left, out char symbol, out Expr right) => (left, symbol, right) = (Left, Symbol, Right);
 
public override Fraction Value {
get => Symbol switch {
'*' => Left.Value * Right.Value,
'/' => Left.Value / Right.Value,
'+' => Left.Value + Right.Value,
'-' => Left.Value - Right.Value,
_ => throw new InvalidOperationException() };
set {}
}
 
public override string ToString() => Symbol switch {
'*' => ToString("+-".Contains(Left.Symbol), "+-".Contains(Right.Symbol)),
'/' => ToString("+-".Contains(Left.Symbol), "*/+-".Contains(Right.Symbol)),
'+' => ToString(false, false),
'-' => ToString(false, "+-".Contains(Right.Symbol)),
_ => $"[{Value}]"
};
 
private string ToString(bool wrapLeft, bool wrapRight) =>
$"{(wrapLeft ? $"({Left})" : $"{Left}")} {Symbol} {(wrapRight ? $"({Right})" : $"{Right}")}";
}
}</syntaxhighlight>
{{out}}
<pre>
(1 + 2) * (1 + 7) = 24
 
(1 + 3) * (2 + 4) = 24
1 * 2 * 3 * 4 = 24
(1 + 2 + 3) * 4 = 24
 
(5 - 1) * (2 + 4) = 24
(2 + 5 - 1) * 4 = 24
 
(7 * 7 - 1) / 2 = 24
 
4 / (1 - 5 / 6) = 24
6 / (5 / 4 - 1) = 24
 
8 / (3 - 8 / 3) = 24
 
Cannot make 24 with 4, 4, 5, 9
 
5 * 5 - 5 / 5 = 24
 
(8 - 6) * (5 + 7) = 24
6 * 8 / (7 - 5) = 24
(5 + 7 - 8) * 6 = 24
 
6 + 6 + 6 + 6 = 24
6 * 6 - 6 - 6 = 24
 
6 * 8 / (9 - 7) = 24
 
(9 / 9 + 9) * (9 / 9 + 9) = 100</pre>
 
=={{header|Ceylon}}==
Don't forget to import ceylon.random in your module.ceylon file.
<syntaxhighlight lang="ceylon">import ceylon.random {
DefaultRandom
}
 
shared sealed class Rational(numerator, denominator = 1) satisfies Numeric<Rational> {
shared Integer numerator;
shared Integer denominator;
Integer gcd(Integer a, Integer b) => if (b == 0) then a else gcd(b, a % b);
shared Rational inverted => Rational(denominator, numerator);
shared Rational simplified =>
let (largestFactor = gcd(numerator, denominator))
Rational(numerator / largestFactor, denominator / largestFactor);
divided(Rational other) => (this * other.inverted).simplified;
negated => Rational(-numerator, denominator).simplified;
plus(Rational other) =>
let (top = numerator*other.denominator + other.numerator*denominator,
bottom = denominator * other.denominator)
Rational(top, bottom).simplified;
times(Rational other) =>
Rational(numerator * other.numerator, denominator * other.denominator).simplified;
shared Integer integer => numerator / denominator;
shared Float float => numerator.float / denominator.float;
string => denominator == 1 then numerator.string else "``numerator``/``denominator``";
shared actual Boolean equals(Object that) {
if (is Rational that) {
value simplifiedThis = this.simplified;
value simplifiedThat = that.simplified;
return simplifiedThis.numerator==simplifiedThat.numerator &&
simplifiedThis.denominator==simplifiedThat.denominator;
} else {
return false;
}
}
}
 
shared Rational? rational(Integer numerator, Integer denominator = 1) =>
if (denominator == 0)
then null
else Rational(numerator, denominator).simplified;
 
shared Rational numeratorOverOne(Integer numerator) => Rational(numerator);
 
shared abstract class Operation(String lexeme) of addition | subtraction | multiplication | division {
shared formal Rational perform(Rational left, Rational right);
string => lexeme;
}
 
shared object addition extends Operation("+") {
perform(Rational left, Rational right) => left + right;
}
shared object subtraction extends Operation("-") {
perform(Rational left, Rational right) => left - right;
}
shared object multiplication extends Operation("*") {
perform(Rational left, Rational right) => left * right;
}
shared object division extends Operation("/") {
perform(Rational left, Rational right) => left / right;
}
 
shared Operation[] operations = `Operation`.caseValues;
 
shared interface Expression of NumberExpression | OperationExpression {
shared formal Rational evaluate();
}
 
shared class NumberExpression(Rational number) satisfies Expression {
evaluate() => number;
string => number.string;
}
shared class OperationExpression(Expression left, Operation op, Expression right) satisfies Expression {
evaluate() => op.perform(left.evaluate(), right.evaluate());
string => "(``left`` ``op`` ``right``)";
}
 
shared void run() {
value twentyfour = numeratorOverOne(24);
value random = DefaultRandom();
function buildExpressions({Rational*} numbers, Operation* ops) {
assert (is NumberExpression[4] numTuple = numbers.collect(NumberExpression).tuple());
assert (is Operation[3] opTuple = ops.sequence().tuple());
value [a, b, c, d] = numTuple;
value [op1, op2, op3] = opTuple;
value opExp = OperationExpression; // this is just to give it a shorter name
return [
opExp(opExp(opExp(a, op1, b), op2, c), op3, d),
opExp(opExp(a, op1, opExp(b, op2, c)), op3, d),
opExp(a, op1, opExp(opExp(b, op2, c), op3, d)),
opExp(a, op1, opExp(b, op2, opExp(c, op3, d)))
];
}
print("Please enter your 4 numbers to see how they form 24 or enter the letter r for random numbers.");
if (exists line = process.readLine()) {
Rational[] chosenNumbers;
if (line.trimmed.uppercased == "R") {
chosenNumbers = random.elements(1..9).take(4).collect((Integer element) => numeratorOverOne(element));
print("The random numbers are ``chosenNumbers``");
} else {
chosenNumbers = line.split().map(Integer.parse).narrow<Integer>().collect(numeratorOverOne);
}
value expressions = {
for (numbers in chosenNumbers.permutations)
for (op1 in operations)
for (op2 in operations)
for (op3 in operations)
for (exp in buildExpressions(numbers, op1, op2, op3))
if (exp.evaluate() == twentyfour)
exp
};
print("The solutions are:");
expressions.each(print);
}
}</syntaxhighlight>
 
=={{header|Clojure}}==
<langsyntaxhighlight Clojurelang="clojure">(ns rosettacode.24game.solve
(:require [clojure.math.combinatorics :as c]
[clojure.walk :as w]))
Line 1,140 ⟶ 2,484:
(map println)
doall
count))</langsyntaxhighlight>
 
The function <code>play24</code> works by substituting the given digits and the four operations into the binary tree patterns (o (o n n) (o n n)), (o (o (o n n) n) n), and (o n (o n (o n n))).
The substitution is the complex part of the program: two pairs of nested maps (the function) are used to substitute in operations and digits, which are replaced into the tree patterns.
 
=={{header|COBOL}}==
<syntaxhighlight lang="cobol"> >>SOURCE FORMAT FREE
*> This code is dedicated to the public domain
*> This is GNUCobol 2.0
identification division.
program-id. twentyfoursolve.
environment division.
configuration section.
repository. function all intrinsic.
input-output section.
file-control.
select count-file
assign to count-file-name
file status count-file-status
organization line sequential.
data division.
file section.
fd count-file.
01 count-record pic x(7).
 
working-storage section.
01 count-file-name pic x(64) value 'solutioncounts'.
01 count-file-status pic xx.
 
01 command-area.
03 nd pic 9.
03 number-definition.
05 n occurs 4 pic 9.
03 number-definition-9 redefines number-definition
pic 9(4).
03 command-input pic x(16).
03 command pic x(5).
03 number-count pic 9999.
03 l1 pic 99.
03 l2 pic 99.
03 expressions pic zzz,zzz,zz9.
 
01 number-validation.
03 px pic 99.
03 permutations 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'.
05 permutation occurs 24 pic x(4).
03 cpx pic 9.
03 current-permutation pic x(4).
03 od1 pic 9.
03 od2 pic 9.
03 od3 pic 9.
03 operator-definitions pic x(4) value '+-*/'.
03 cox pic 9.
03 current-operators pic x(3).
03 rpn-forms value
'nnonono'
& 'nnonnoo'
& 'nnnonoo'
& 'nnnoono'
& 'nnnnooo'.
05 rpn-form occurs 5 pic x(7).
03 rpx pic 9.
03 current-rpn-form pic x(7).
 
01 calculation-area.
03 oqx pic 99.
03 output-queue pic x(7).
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.
03 divide-by-zero-error pic x.
 
01 totals.
03 s pic 999.
03 s-lim pic 999 value 600.
03 s-max pic 999 value 0.
03 solution occurs 600 pic x(7).
03 sc pic 999.
03 sc1 pic 999.
03 sc2 pic 9.
03 sc-max pic 999 value 0.
03 sc-lim pic 999 value 600.
03 solution-counts value zeros.
05 solution-count occurs 600 pic 999.
03 ns pic 9999.
03 ns-max pic 9999 value 0.
03 ns-lim pic 9999 value 6561.
03 number-solutions occurs 6561.
05 ns-number pic x(4).
05 ns-count pic 999.
03 record-counts pic 9999.
03 total-solutions pic 9999.
 
01 infix-area.
03 i pic 9.
03 i-s pic 9.
03 i-s1 pic 9.
03 i-work pic x(16).
03 i-stack occurs 7 pic x(13).
 
procedure division.
start-twentyfoursolve.
display 'start twentyfoursolve'
perform display-instructions
perform get-command
perform until command-input = spaces
display space
initialize command number-count
unstring command-input delimited by all space
into command number-count
move command-input to number-definition
move spaces to command-input
evaluate command
when 'h'
when 'help'
perform display-instructions
when 'list'
if ns-max = 0
perform load-solution-counts
end-if
perform list-counts
when 'show'
if ns-max = 0
perform load-solution-counts
end-if
perform show-numbers
when other
if number-definition-9 not numeric
display 'invalid number'
else
perform get-solutions
perform display-solutions
end-if
end-evaluate
if command-input = spaces
perform get-command
end-if
end-perform
display 'exit twentyfoursolve'
stop run
.
display-instructions.
display space
display 'enter a number <n> as four integers from 1-9 to see its solutions'
display 'enter list to see counts of solutions for all numbers'
display 'enter show <n> to see numbers having <n> solutions'
display '<enter> ends the program'
.
get-command.
display space
move spaces to command-input
display '(h for help)?' with no advancing
accept command-input
.
ask-for-more.
display space
move 0 to l1
add 1 to l2
if l2 = 10
display 'more (<enter>)?' with no advancing
accept command-input
move 0 to l2
end-if
.
list-counts.
add 1 to sc-max giving sc
display 'there are ' sc ' solution counts'
display space
display 'solutions/numbers'
move 0 to l1
move 0 to l2
perform varying sc from 1 by 1 until sc > sc-max
or command-input <> spaces
if solution-count(sc) > 0
subtract 1 from sc giving sc1 *> offset to capture zero counts
display sc1 '/' solution-count(sc) space with no advancing
add 1 to l1
if l1 = 8
perform ask-for-more
end-if
end-if
end-perform
if l1 > 0
display space
end-if
.
show-numbers. *> with number-count solutions
add 1 to number-count giving sc1 *> offset for zero count
evaluate true
when number-count >= sc-max
display 'no number has ' number-count ' solutions'
exit paragraph
when solution-count(sc1) = 1 and number-count = 1
display '1 number has 1 solution'
when solution-count(sc1) = 1
display '1 number has ' number-count ' solutions'
when number-count = 1
display solution-count(sc1) ' numbers have 1 solution'
when other
display solution-count(sc1) ' numbers have ' number-count ' solutions'
end-evaluate
display space
move 0 to l1
move 0 to l2
perform varying ns from 1 by 1 until ns > ns-max
or command-input <> spaces
if ns-count(ns) = number-count
display ns-number(ns) space with no advancing
add 1 to l1
if l1 = 14
perform ask-for-more
end-if
end-if
end-perform
if l1 > 0
display space
end-if
.
display-solutions.
evaluate s-max
when 0 display number-definition ' has no solutions'
when 1 display number-definition ' has 1 solution'
when other display number-definition ' has ' s-max ' solutions'
end-evaluate
display space
move 0 to l1
move 0 to l2
perform varying s from 1 by 1 until s > s-max
or command-input <> spaces
*> convert rpn solution(s) to infix
move 0 to i-s
perform varying i from 1 by 1 until i > 7
if solution(s)(i:1) >= '1' and <= '9'
add 1 to i-s
move solution(s)(i:1) to i-stack(i-s)
else
subtract 1 from i-s giving i-s1
move spaces to i-work
string '(' i-stack(i-s1) solution(s)(i:1) i-stack(i-s) ')'
delimited by space into i-work
move i-work to i-stack(i-s1)
subtract 1 from i-s
end-if
end-perform
display solution(s) space i-stack(1) space space with no advancing
add 1 to l1
if l1 = 3
perform ask-for-more
end-if
end-perform
if l1 > 0
display space
end-if
.
load-solution-counts.
move 0 to ns-max *> numbers and their solution count
move 0 to sc-max *> solution counts
move spaces to count-file-status
open input count-file
if count-file-status <> '00'
perform create-count-file
move 0 to ns-max *> numbers and their solution count
move 0 to sc-max *> solution counts
open input count-file
end-if
read count-file
move 0 to record-counts
move zeros to solution-counts
perform until count-file-status <> '00'
add 1 to record-counts
perform increment-ns-max
move count-record to number-solutions(ns-max)
add 1 to ns-count(ns-max) giving sc *> offset 1 for zero counts
if sc > sc-lim
display 'sc ' sc ' exceeds sc-lim ' sc-lim
stop run
end-if
if sc > sc-max
move sc to sc-max
end-if
add 1 to solution-count(sc)
read count-file
end-perform
close count-file
.
create-count-file.
open output count-file
display 'Counting solutions for all numbers'
display 'We will examine 9*9*9*9 numbers'
display 'For each number we will examine 4! permutations of the digits'
display 'For each permutation we will examine 4*4*4 combinations of operators'
display 'For each permutation and combination we will examine 5 rpn forms'
display 'We will count the number of unique solutions for the given number'
display 'Each number and its counts will be written to file ' trim(count-file-name)
compute expressions = 9*9*9*9*factorial(4)*4*4*4*5
display 'So we will evaluate ' trim(expressions) ' statements'
display 'This will take a few minutes'
display 'In the future if ' trim(count-file-name) ' exists, this step will be bypassed'
move 0 to record-counts
move 0 to total-solutions
perform varying n(1) from 1 by 1 until n(1) = 0
perform varying n(2) from 1 by 1 until n(2) = 0
display n(1) n(2) '..' *> show progress
perform varying n(3) from 1 by 1 until n(3) = 0
perform varying n(4) from 1 by 1 until n(4) = 0
perform get-solutions
perform increment-ns-max
move number-definition to ns-number(ns-max)
move s-max to ns-count(ns-max)
move number-solutions(ns-max) to count-record
write count-record
add s-max to total-solutions
add 1 to record-counts
add 1 to ns-count(ns-max) giving sc *> offset by 1 for zero counts
if sc > sc-lim
display 'error: ' sc ' solution count exceeds ' sc-lim
stop run
end-if
add 1 to solution-count(sc)
end-perform
end-perform
end-perform
end-perform
close count-file
display record-counts ' numbers and counts written to ' trim(count-file-name)
display total-solutions ' total solutions'
display space
.
increment-ns-max.
if ns-max >= ns-lim
display 'error: numbers exceeds ' ns-lim
stop run
end-if
add 1 to ns-max
.
get-solutions.
move 0 to s-max
perform varying px from 1 by 1 until px > 24
move permutation(px) to current-permutation
perform varying od1 from 1 by 1 until od1 > 4
move operator-definitions(od1:1) to current-operators(1:1)
perform varying od2 from 1 by 1 until od2 > 4
move operator-definitions(od2:1) to current-operators(2:1)
perform varying od3 from 1 by 1 until od3 > 4
move operator-definitions(od3:1) to current-operators(3:1)
perform varying rpx from 1 by 1 until rpx > 5
move rpn-form(rpx) to current-rpn-form
move 0 to cpx cox
move spaces to output-queue
perform varying oqx from 1 by 1 until oqx > 7
if current-rpn-form(oqx:1) = 'n'
add 1 to cpx
move current-permutation(cpx:1) to nd
move n(nd) to output-queue(oqx:1)
else
add 1 to cox
move current-operators(cox:1) to output-queue(oqx:1)
end-if
end-perform
perform evaluate-rpn
if divide-by-zero-error = space
and 24 * top-denominator = top-numerator
perform varying s from 1 by 1 until s > s-max
or solution(s) = output-queue
continue
end-perform
if s > s-max
if s >= s-lim
display 'error: solutions ' s ' for ' number-definition ' exceeds ' s-lim
stop run
end-if
move s to s-max
move output-queue to solution(s-max)
end-if
end-if
end-perform
end-perform
end-perform
end-perform
end-perform
.
evaluate-rpn.
move space to divide-by-zero-error
move 0 to rsx *> stack depth
perform varying oqx from 1 by 1 until oqx > 7
if output-queue(oqx:1) >= '1' and <= '9'
*> push the digit onto the stack
add 1 to rsx
move top-numerator to numerator(rsx)
move top-denominator to denominator(rsx)
move output-queue(oqx:1) to top-numerator
move 1 to top-denominator
else
*> apply the operation
evaluate output-queue(oqx:1)
when '+'
compute top-numerator = top-numerator * denominator(rsx)
+ top-denominator * numerator(rsx)
compute top-denominator = top-denominator * denominator(rsx)
when '-'
compute top-numerator = top-denominator * numerator(rsx)
- top-numerator * denominator(rsx)
compute top-denominator = top-denominator * denominator(rsx)
when '*'
compute top-numerator = top-numerator * numerator(rsx)
compute top-denominator = top-denominator * denominator(rsx)
when '/'
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
.
end program twentyfoursolve.</syntaxhighlight>
 
{{out}}
<pre>
prompt$ cobc -xj twentyfoursolve.cob
start twentyfoursolve
 
enter a number <n> as four integers from 1-9 to see its solutions
enter list to see counts of solutions for all numbers
enter show <n> to see numbers having <n> solutions
<enter> ends the program
 
(h for help)?5678
 
5678 has 026 solutions
 
57+8-6* (((5+7)-8)*6) 57+86-* ((5+7)*(8-6)) 578-+6* ((5+(7-8))*6)
58-7+6* (((5-8)+7)*6) 587--6* ((5-(8-7))*6) 657+8-* (6*((5+7)-8))
6578-+* (6*(5+(7-8))) 658-7+* (6*((5-8)+7)) 6587--* (6*(5-(8-7)))
675+8-* (6*((7+5)-8)) 6758-+* (6*(7+(5-8))) 675-/8* ((6/(7-5))*8)
675-8// (6/((7-5)/8)) 678-5+* (6*((7-8)+5)) 6785--* (6*(7-(8-5)))
6875-/* (6*(8/(7-5))) 68*75-/ ((6*8)/(7-5)) 75+8-6* (((7+5)-8)*6)
75+86-* ((7+5)*(8-6)) 758-+6* ((7+(5-8))*6) 86-57+* ((8-6)*(5+7))
86-75+* ((8-6)*(7+5)) 8675-/* (8*(6/(7-5))) 86*75-/ ((8*6)/(7-5))
875-/6* ((8/(7-5))*6) 875-6// (8/((7-5)/6))
 
(h for help)?
</pre>
 
=={{header|CoffeeScript}}==
<langsyntaxhighlight lang="coffeescript">
# This program tries to find some way to turn four digits into an arithmetic
# expression that adds up to 24.
Line 1,234 ⟶ 3,053:
solution = solve_24_game a, b, c, d
console.log "Solution for #{[a,b,c,d]}: #{solution ? 'no solution'}"
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,257 ⟶ 3,076:
=={{header|Common Lisp}}==
 
<langsyntaxhighlight lang="lisp">(defconstant +ops+ '(* / + -))
 
(defun digits ()
Line 1,312 ⟶ 3,131:
digits which evaluates to 24. The first form found is returned, or
NIL if there is no solution."
(solvable-p digits))</langsyntaxhighlight>
 
{{out}}
Line 1,330 ⟶ 3,149:
This uses the Rational struct and permutations functions of two other Rosetta Code Tasks.
{{trans|Scala}}
<langsyntaxhighlight lang="d">import std.stdio, std.algorithm, std.range, std.typeconsconv, std.convstring,
std.stringconcurrency, permutations2, arithmetic_rational;
 
string solve(in int target, in int[] problem) {
static struct ComputeAllOperationsT { Rational r; string e; }
//static struct T { Rational r; string e; }
alias T = Tuple!(Rational,"r", string,"e");
Rational[] L;
 
Generator!T computeAllOperations(in Rational[] L) {
int opApply(in int delegate(ref T) dg) {
return new typeof(return)({
int result;
if (!L.empty) {
 
immutable x = L[0];
if (!L.empty) {
auto x = if (L[0];.length == 1) {
auto xs = L[1 .. $] yield(T(x, x.text));
if (L.length == 1) } else {
T aux = T foreach (x,const texto; computeAllOperations(xL.dropOne)); {
result immutable y = dg(aux)o.r;
auto sub = [T(x * y, "*"), T(x + y, "+"), T(x - y, "-")];
} else {
OUTER: foreach (o; ComputeAllOperations if (xs)y) {sub ~= [T(x / y, "/")];
auto y = o.r foreach (const e; sub)
auto sub = [T(x * y, "*"), yield(T(x + ye.r, format("+"(%s%s%s)", T(x, - ye.e, "-"o.e)))];
if (y) sub ~= [T(x/y, "/")]; }
foreach (e; sub) { }
auto aux = T(e.r, format("(%s%s%s)", x, e.e, o.e));
result = dg(aux); if (result) break OUTER;
}
});
}
}
 
return result;
}
}
 
foreach (const p; problem.map!Rational.array.permutations!false)
 
foreach (pconst sol; problem.map!Rational.array.permutationscomputeAllOperations(p))
foreach if (sol;.r ComputeAllOperations(p)== target)
if (sol.r == target) return sol.e;
return "No return sol.esolution";
return "No solution";
}
 
void main() {
foreach (const prob; [[6, 7, 9, 5], [3, 3, 8, 8], [1, 1, 1, 1]])
writeln(prob, ": ", solve(24, prob));
}</langsyntaxhighlight>
{{out}}
<pre>[6, 7, 9, 5]: (6+(9*(7-5)))
[3, 3, 8, 8]: (8/(3-(8/3)))
[1, 1, 1, 1]: No solution</pre>
 
=={{header|EchoLisp}}==
The program takes n numbers - not limited to 4 - builds the all possible legal rpn expressions according to the game rules, and evaluates them. Time saving : 4 5 + is the same as 5 4 + . Do not generate twice. Do not generate expressions like 5 6 * + which are not legal.
 
<syntaxhighlight lang="scheme">
;; use task [[RPN_to_infix_conversion#EchoLisp]] to print results
(define (rpn->string rpn)
(if (vector? rpn)
(infix->string (rpn->infix rpn))
"😥 Not found"))
 
 
(string-delimiter "")
(define OPS #(* + - // )) ;; use float division
(define-syntax-rule (commutative? op) (or (= op *) (= op +)))
 
;; ---------------------------------
;; calc rpn -> num value or #f if bad rpn
;; rpn is a vector of ops or numbers
;; ----------------------------------
(define (calc rpn)
(define S (stack 'S))
(for ((token rpn))
(if (procedure? token)
(let [(op2 (pop S)) (op1 (pop S))]
(if (and op1 op2)
(push S (apply token (list op1 op2)))
(push S #f))) ;; not-well formed
(push S token ))
#:break (not (stack-top S)))
(if (= 1 (stack-length S)) (pop S) #f))
;; check for legal rpn -> #f if not legal
(define (rpn? rpn)
(define S (stack 'S))
(for ((token rpn))
(if (procedure? token)
(push S (and (pop S) (pop S)))
(push S token ))
#:break (not (stack-top S)))
(stack-top S))
;; --------------------------------------
;; build-rpn : push next rpn op or number
;; dleft is number of not used digits
;; ---------------------------------------
(define count 0)
 
(define (build-rpn into: rpn depth maxdepth digits ops dleft target &hit )
(define cmpop #f)
(cond
;; tooo long
[(> (++ count) 200_000) (set-box! &hit 'not-found)]
;; stop on first hit
[(unbox &hit) &hit]
;; partial rpn must be legal
[(not (rpn? rpn)) #f]
;; eval rpn if complete
[(> depth maxdepth)
(when (= target (calc rpn)) (set-box! &hit rpn))]
;; else, add a digit to rpn
[else
[when (< depth maxdepth) ;; digits anywhere except last
(for [(d digits) (i 10)]
#:continue (zero? d)
(vector-set! digits i 0) ;; mark used
(vector-set! rpn depth d)
(build-rpn rpn (1+ depth) maxdepth digits ops (1- dleft) target &hit)
(vector-set! digits i d)) ;; mark unused
] ;; add digit
;; or, add an op
;; ops anywhere except positions 0,1
[when (and (> depth 1) (<= (+ depth dleft) maxdepth));; cutter : must use all digits
(set! cmpop
(and (number? [rpn (1- depth)])
(number? [rpn (- depth 2)])
(> [rpn (1- depth)] [rpn (- depth 2)])))
(for [(op ops)]
#:continue (and cmpop (commutative? op)) ;; cutter : 3 4 + === 4 3 +
(vector-set! rpn depth op)
(build-rpn rpn (1+ depth) maxdepth digits ops dleft target &hit)
(vector-set! rpn depth 0))] ;; add op
] ; add something to rpn vector
)) ; build-rpn
 
;;------------------------
;;gen24 : num random numbers
;;------------------------
(define (gen24 num maxrange)
(->> (append (range 1 maxrange)(range 1 maxrange)) shuffle (take num)))
 
;;-------------------------------------------
;; try-rpn : sets starter values for build-rpn
;;-------------------------------------------
(define (try-rpn digits target)
(set! digits (list-sort > digits)) ;; seems to accelerate things
(define rpn (make-vector (1- (* 2 (length digits)))))
(define &hit (box #f))
(set! count 0)
(build-rpn rpn starter-depth: 0
max-depth: (1- (vector-length rpn))
(list->vector digits)
OPS
remaining-digits: (length digits)
target &hit )
(writeln target '= (rpn->string (unbox &hit)) 'tries= count))
 
;; -------------------------------
;; (task numdigits target maxrange)
;; --------------------------------
(define (task (numdigits 4) (target 24) (maxrange 10))
(define digits (gen24 numdigits maxrange))
(writeln digits '→ target)
(try-rpn digits target))
</syntaxhighlight>
 
{{out}}
<pre>
(task 4) ;; standard 24-game
(7 9 2 4) → 24
24 = 9 + 7 + 4 * 2 tries= 35
 
(task 4)
(1 9 3 4) → 24
24 = 9 + (4 + 1) * 3 tries= 468
(task 5 ) ;; 5 digits
(4 8 6 9 8) → 24
24 = 9 * 8 * (8 / (6 * 4)) tries= 104
 
(task 5 100) ;; target = 100
(5 6 5 1 3) → 100
100 = (6 + (5 * 3 - 1)) * 5 tries= 10688
 
(task 5 (random 100))
(1 1 8 6 8) → 31
31 = 8 * (6 - 1) - (8 + 1) tries= 45673
 
(task 6 (random 100)) ;; 6 digits
(7 2 7 8 3 1) → 40
40 = 8 / (7 / (7 * (3 + 2 * 1))) tries= 154
 
(task 6 (random 1000) 100) ;; 6 numbers < 100 , target < 1000
(19 15 83 74 61 48) → 739
739 = (83 + (74 - (61 + 48))) * 15 + 19 tries= 29336
 
(task 6 (random 1000) 100) ;; 6 numbers < 100
(73 29 65 78 22 43) → 1
1 = 😥 Not found tries= 200033
 
(task 7 (random 1000) 100) ;; 7 numbers < 100
(7 55 94 4 71 58 93) → 705
705 = 94 + 93 + 71 + 58 + 55 * 7 + 4 tries= 5982
 
(task 6 (random -100) 10) ;; negative target
(5 9 7 3 6 3) → -54
-54 = 9 * (7 + (6 - 5 * 3)) * 3 tries= 2576
</pre>
 
=={{header|Elixir}}==
{{trans|Ruby}}
<syntaxhighlight lang="elixir">defmodule Game24 do
@expressions [ ["((", "", ")", "", ")", ""],
["(", "(", "", "", "))", ""],
["(", "", ")", "(", "", ")"],
["", "((", "", "", ")", ")"],
["", "(", "", "(", "", "))"] ]
def solve(digits) do
dig_perm = permute(digits) |> Enum.uniq
operators = perm_rep(~w[+ - * /], 3)
for dig <- dig_perm, ope <- operators, expr <- @expressions,
check?(str = make_expr(dig, ope, expr)),
do: str
end
defp check?(str) do
try do
{val, _} = Code.eval_string(str)
val == 24
rescue
ArithmeticError -> false # division by zero
end
end
defp permute([]), do: [[]]
defp permute(list) do
for x <- list, y <- permute(list -- [x]), do: [x|y]
end
defp perm_rep([], _), do: [[]]
defp perm_rep(_, 0), do: [[]]
defp perm_rep(list, i) do
for x <- list, y <- perm_rep(list, i-1), do: [x|y]
end
defp make_expr([a,b,c,d], [x,y,z], [e0,e1,e2,e3,e4,e5]) do
e0 <> a <> x <> e1 <> b <> e2 <> y <> e3 <> c <> e4 <> z <> d <> e5
end
end
 
case Game24.solve(System.argv) do
[] -> IO.puts "no solutions"
solutions ->
IO.puts "found #{length(solutions)} solutions, including #{hd(solutions)}"
IO.inspect Enum.sort(solutions)
end</syntaxhighlight>
 
{{out}}
<pre>
C:\Elixir>elixir game24.exs 1 1 3 4
found 12 solutions, including ((1+1)*3)*4
["((1+1)*3)*4", "((1+1)*4)*3", "(1+1)*(3*4)", "(1+1)*(4*3)", "(3*(1+1))*4",
"(3*4)*(1+1)", "(4*(1+1))*3", "(4*3)*(1+1)", "3*((1+1)*4)", "3*(4*(1+1))",
"4*((1+1)*3)", "4*(3*(1+1))"]
 
C:\Elixir>elixir game24.exs 6 7 8 9
found 8 solutions, including (6*8)/(9-7)
["(6*8)/(9-7)", "(6/(9-7))*8", "(8*6)/(9-7)", "(8/(9-7))*6", "6*(8/(9-7))",
"6/((9-7)/8)", "8*(6/(9-7))", "8/((9-7)/6)"]
 
C:\Elixir>elixir game24.exs 1 2 2 3
no solutions
</pre>
 
=={{header|ERRE}}==
ERRE hasn't an "EVAL" function so we must write an evaluation routine; this task is solved via "brute-force".
<syntaxhighlight lang="err">
PROGRAM 24SOLVE
 
LABEL 98,99,2540,2550,2560
 
! possible brackets
CONST NBRACKETS=11,ST_CONST$="+-*/^("
 
DIM D[4],PERM[24,4]
DIM BRAKETS$[NBRACKETS]
DIM OP$[3]
DIM STACK$[50]
 
PROCEDURE COMPATTA_STACK
IF NS>1 THEN
R=1
WHILE R<NS DO
IF INSTR(ST_CONST$,STACK$[R])=0 AND INSTR(ST_CONST$,STACK$[R+1])=0 THEN
FOR R1=R TO NS-1 DO
STACK$[R1]=STACK$[R1+1]
END FOR
NS=NS-1
END IF
R=R+1
END WHILE
END IF
END PROCEDURE
 
PROCEDURE CALC_ARITM
L=NS1
WHILE L<=NS2 DO
IF STACK$[L]="^" THEN
IF L>=NS2 THEN GOTO 99 END IF
N1#=VAL(STACK$[L-1]) N2#=VAL(STACK$[L+1]) NOP=NOP-1
IF STACK$[L]="^" THEN
RI#=N1#^N2#
END IF
STACK$[L-1]=STR$(RI#)
N=L
WHILE N<=NS2-2 DO
STACK$[N]=STACK$[N+2]
N=N+1
END WHILE
NS2=NS2-2
L=NS1-1
END IF
L=L+1
END WHILE
 
L=NS1
WHILE L<=NS2 DO
IF STACK$[L]="*" OR STACK$[L]="/" THEN
IF L>=NS2 THEN GOTO 99 END IF
N1#=VAL(STACK$[L-1]) N2#=VAL(STACK$[L+1]) NOP=NOP-1
IF STACK$[L]="*" THEN
RI#=N1#*N2#
ELSE
IF N2#<>0 THEN RI#=N1#/N2# ELSE NERR=6 RI#=0 END IF
END IF
STACK$[L-1]=STR$(RI#)
N=L
WHILE N<=NS2-2 DO
STACK$[N]=STACK$[N+2]
N=N+1
END WHILE
NS2=NS2-2
L=NS1-1
END IF
L=L+1
END WHILE
 
L=NS1
WHILE L<=NS2 DO
IF STACK$[L]="+" OR STACK$[L]="-" THEN
EXIT IF L>=NS2
N1#=VAL(STACK$[L-1]) N2#=VAL(STACK$[L+1]) NOP=NOP-1
IF STACK$[L]="+" THEN RI#=N1#+N2# ELSE RI#=N1#-N2# END IF
STACK$[L-1]=STR$(RI#)
N=L
WHILE N<=NS2-2 DO
STACK$[N]=STACK$[N+2]
N=N+1
END WHILE
NS2=NS2-2
L=NS1-1
END IF
L=L+1
END WHILE
99:
IF NOP<2 THEN ! precedenza tra gli operatori
DB#=VAL(STACK$[NS1])
ELSE
IF NOP<3 THEN
DB#=VAL(STACK$[NS1+2])
ELSE
DB#=VAL(STACK$[NS1+4])
END IF
END IF
END PROCEDURE
 
PROCEDURE SVOLGI_PAR
NPA=NPA-1
FOR J=NS TO 1 STEP -1 DO
EXIT IF STACK$[J]="("
END FOR
IF J=0 THEN
NS1=1 NS2=NS CALC_ARITM NERR=7
ELSE
FOR R=J TO NS-1 DO
STACK$[R]=STACK$[R+1]
END FOR
NS1=J NS2=NS-1 CALC_ARITM
IF NS1=2 THEN
NS1=1 STACK$[1]=STACK$[2]
END IF
NS=NS1
COMPATTA_STACK
END IF
END PROCEDURE
 
PROCEDURE MYEVAL(EXPRESSION$,DB#,NERR->DB#,NERR)
 
NOP=0 NPA=0 NS=1 K$="" NERR=0
STACK$[1]="@" ! init stack
 
FOR W=1 TO LEN(EXPRESSION$) DO
LOOP
CODE=ASC(MID$(EXPRESSION$,W,1))
IF (CODE>=48 AND CODE<=57) OR CODE=46 THEN
K$=K$+CHR$(CODE)
W=W+1 IF W>LEN(EXPRESSION$) THEN GOTO 98 END IF
ELSE
EXIT IF K$=""
IF NS>1 OR (NS=1 AND STACK$[1]<>"@") THEN NS=NS+1 END IF
IF FLAG=0 THEN
STACK$[NS]=K$
ELSE
STACK$[NS]=STR$(VAL(K$)*FLAG)
END IF
K$="" FLAG=0
EXIT
END IF
END LOOP
IF CODE=43 THEN K$="+" END IF
IF CODE=45 THEN K$="-" END IF
IF CODE=42 THEN K$="*" END IF
IF CODE=47 THEN K$="/" END IF
IF CODE=94 THEN K$="^" END IF
 
CASE CODE OF
43,45,42,47,94-> ! +-*/^
IF MID$(EXPRESSION$,W+1,1)="-" THEN FLAG=-1 W=W+1 END IF
IF INSTR(ST_CONST$,STACK$[NS])<>0 THEN
NERR=5
ELSE
NS=NS+1 STACK$[NS]=K$ NOP=NOP+1
IF NOP>=2 THEN
FOR J=NS TO 1 STEP -1 DO
IF STACK$[J]<>"(" THEN GOTO 2540 END IF
IF J<NS-2 THEN GOTO 2550 ELSE GOTO 2560 END IF
2540: END FOR
2550: NS1=J+1 NS2=NS CALC_ARITM
NS=NS2 STACK$[NS]=K$
REGISTRO_X#=VAL(STACK$[NS-1])
END IF
END IF
2560: END ->
 
40-> ! (
IF NS>1 OR (NS=1 AND STACK$[1]<>"@") THEN NS=NS+1 END IF
STACK$[NS]="(" NPA=NPA+1
IF MID$(EXPRESSION$,W+1,1)="-" THEN FLAG=-1 W=W+1 END IF
END ->
 
41-> ! )
SVOLGI_PAR
IF NERR=7 THEN
NERR=0 NOP=0 NPA=0 NS=1
ELSE
IF NERR=0 OR NERR=1 THEN
DB#=VAL(STACK$[NS])
REGISTRO_X#=DB#
ELSE
NOP=0 NPA=0 NS=1
END IF
END IF
END ->
 
OTHERWISE
NERR=8
END CASE
K$=""
END FOR
98:
IF K$<>"" THEN
IF NS>1 OR (NS=1 AND STACK$[1]<>"@") THEN NS=NS+1 END IF
IF FLAG=0 THEN STACK$[NS]=K$ ELSE STACK$[NS]=STR$(VAL(K$)*FLAG) END IF
END IF
 
IF INSTR(ST_CONST$,STACK$[NS])<>0 THEN
NERR=6
ELSE
WHILE NPA<>0 DO
SVOLGI_PAR
END WHILE
IF NERR<>7 THEN NS1=1 NS2=NS CALCARITM END IF
END IF
 
NS=1 NOP=0 NPA=0
 
END PROCEDURE
 
BEGIN
PRINT(CHR$(12);) ! CLS
 
! possible brackets
DATA("4#4#4#4")
DATA("(4#4)#4#4")
DATA("4#(4#4)#4")
DATA("4#4#(4#4)")
DATA("(4#4)#(4#4)")
DATA("(4#4#4)#4")
DATA("4#(4#4#4)")
DATA("((4#4)#4)#4")
DATA("(4#(4#4))#4")
DATA("4#((4#4)#4)")
DATA("4#(4#(4#4))")
FOR I=1 TO NBRACKETS DO
READ(BRAKETS$[I])
END FOR
 
INPUT("ENTER 4 DIGITS: ",A$)
ND=0
FOR I=1 TO LEN(A$) DO
C$=MID$(A$,I,1)
IF INSTR("123456789",C$)>0 THEN
ND=ND+1
D[ND]=VAL(C$)
END IF
END FOR
! precompute permutations. dumb way.
NPERM=1*2*3*4
N=0
FOR I=1 TO 4 DO
FOR J=1 TO 4 DO
FOR K=1 TO 4 DO
FOR L=1 TO 4 DO
! valid permutation (no dupes)
IF I<>J AND I<>K AND I<>L AND J<>K AND J<>L AND K<>L THEN
N=N+1
! actually,we can as well permute given digits
PERM[N,1]=D[I]
PERM[N,2]=D[J]
PERM[N,3]=D[K]
PERM[N,4]=D[L]
END IF
END FOR
END FOR
END FOR
END FOR
 
! operations: full search
COUNT=0
OPS$="+-*/"
FOR OP1=1 TO 4 DO
OP$[1]=MID$(OPS$,OP1,1)
FOR OP2=1 TO 4 DO
OP$[2]=MID$(OPS$,OP2,1)
FOR OP3=1 TO 4 DO
OP$[3]=MID$(OPS$,OP3,1)
! substitute all brackets
FOR T=1 TO NBRACKETS DO
TMPL$=BRAKETS$[T]
! now,substitute all digits: permutations.
FOR P=1 TO NPERM DO
RES$=""
NOP=0
ND=0
FOR I=1 TO LEN(TMPL$) DO
C$=MID$(TMPL$,I,1)
CASE C$ OF
"#"-> ! operations
NOP=NOP+1
RES$=RES$+OP$[NOP]
END ->
"4"-> ! digits
ND=NOP+1
RES$=RES$+MID$(STR$(PERM[P,ND]),2)
END ->
OTHERWISE ! brackets goes here
RES$=RES$+C$
END CASE
END FOR
! eval here
MY_EVAL(RES$,DB#,NERR->DB#,NERR)
IF DB#=24 AND NERR=0 THEN
PRINT("24=";RES$)
COUNT=COUNT+1
END IF
END FOR
END FOR
END FOR
END FOR
END FOR
 
IF COUNT=0 THEN
PRINT("If you see this, probably task cannot be solved with these digits")
ELSE
PRINT("Total=";COUNT)
END IF
 
END PROGRAM
</syntaxhighlight>
{{out}}
<pre>
ENTER 4 DIGITS: ? 6759
24=6+(7-5)*9
24=6+((7-5)*9)
24=6+9*(7-5)
24=6+(9*(7-5))
24=6-(5-7)*9
24=6-((5-7)*9)
24=(7-5)*9+6
24=((7-5)*9)+6
24=6-9*(5-7)
24=6-(9*(5-7))
24=9*(7-5)+6
24=(9*(7-5))+6
Total= 12
</pre>
 
=={{header|Euler Math Toolbox}}==
Line 1,386 ⟶ 3,753:
Via brute force.
 
<syntaxhighlight lang="euler math toolbox">
<lang Euler Math Toolbox>
>function try24 (v) ...
$n=cols(v);
Line 1,409 ⟶ 3,776:
$return 0;
$endfunction
</syntaxhighlight>
</lang>
 
<syntaxhighlight lang="euler math toolbox">
<lang Euler Math Toolbox>
>try24([1,2,3,4]);
Solved the problem
Line 1,432 ⟶ 3,799:
-1+5=4
3-4=-1
</syntaxhighlight>
</lang>
 
 
=={{header|F_Sharp|F#}}==
Line 1,439 ⟶ 3,805:
It eliminates all duplicate solutions which result from transposing equal digits.
The basic solution is an adaption of the OCaml program.
<langsyntaxhighlight lang="fsharp">open System
 
let rec gcd x y = if x = y || x = 0 then y else if x < y then gcd y x else gcd y (x-y)
Line 1,547 ⟶ 3,913:
|> Seq.groupBy id
|> Seq.iter (fun x -> printfn "%s" (fst x))
0</langsyntaxhighlight>
{{out}}
<pre>>solve24 3 3 3 4
Line 1,573 ⟶ 3,939:
3 * 8 / (9 - 8)
3 / ((9 - 8) / 8)</pre>
 
=={{header|Factor}}==
Factor is well-suited for this task due to its homoiconicity and because it is a reverse-Polish notation evaluator. All we're doing is grouping each permutation of digits with three selections of the possible operators into quotations (blocks of code that can be stored like sequences). Then we <code>call</code> each quotation and print out the ones that equal 24. The <code>recover</code> word is an exception handler that is used to intercept divide-by-zero errors and continue gracefully by removing those quotations from consideration.
<syntaxhighlight lang="factor">USING: continuations grouping io kernel math math.combinatorics
prettyprint quotations random sequences sequences.deep ;
IN: rosetta-code.24-game
 
: 4digits ( -- seq ) 4 9 random-integers [ 1 + ] map ;
 
: expressions ( digits -- exprs )
all-permutations [ [ + - * / ] 3 selections
[ append ] with map ] map flatten 7 group ;
 
: 24= ( exprs -- )
>quotation dup call( -- x ) 24 = [ . ] [ drop ] if ;
 
: 24-game ( -- )
4digits dup "The numbers: " write . "The solutions: "
print expressions [ [ 24= ] [ 2drop ] recover ] each ;
24-game</syntaxhighlight>
{{out}}
<pre>
The numbers: { 4 9 3 1 }
The solutions:
[ 4 9 3 1 * - * ]
[ 4 9 3 1 / - * ]
[ 4 9 1 3 * - * ]
[ 4 1 9 3 - * * ]
[ 4 1 9 3 - / / ]
[ 9 3 4 1 + * + ]
[ 9 3 1 4 + * + ]
[ 1 4 9 3 - * * ]
[ 1 4 9 3 * - - ]
[ 1 4 3 9 * - - ]
 
The numbers: { 1 7 4 9 }
The solutions:
 
The numbers: { 1 5 6 8 }
The solutions:
[ 6 1 5 8 - - * ]
[ 6 1 8 5 - + * ]
[ 6 8 1 5 - + * ]
[ 6 8 5 1 - - * ]
</pre>
 
=={{header|Fortran}}==
<langsyntaxhighlight Fortranlang="fortran">program solve_24
use helpers
implicit none
Line 1,643 ⟶ 4,055:
end function op
 
end program solve_24</langsyntaxhighlight>
 
<langsyntaxhighlight Fortranlang="fortran">module helpers
 
contains
Line 1,716 ⟶ 4,128:
end subroutine nextpermutation
 
end module helpers</langsyntaxhighlight>
{{out}} (using g95):
<pre> 3 6 7 9 : 3 *(( 6 - 7 )+ 9 )
Line 1,731 ⟶ 4,143:
2 4 6 8 : (( 2 / 4 )* 6 )* 8
</pre>
 
 
=={{header|FutureBasic}}==
This programme gives just the first-found (simplest) solution. To see the exhaustive list, we would remove the '''if k > 0 then exit fn''' statements.
<syntaxhighlight lang="futurebasic>
 
begin globals
Short k
end globals
 
void local fn eval( t as CFStringRef )
CFMutableStringRef s = fn MutableStringNew
ExpressionRef x = fn ExpressionWithFormat( t )
CFRange r = fn CFRangeMake(0, fn StringLength( t ) )
CFNumberRef n = fn ExpressionValueWithObject( x, Null, Null )
Float f = dblval( n )
if f = 24 // found, so clean up
MutableStringSetString( s, t ) // duplicate string and pretend it was integers all along
MutableStringReplaceOccurrencesOfString( s, @".000000", @"", Null, r )
print s; @" = 24" : k ++
end if
end fn
 
 
clear local fn work( t as CFStringRef )
Short a, b, c, d, e, f, g
CGFloat n(3)
CFStringRef s, os = @"*/+-", o(3)
print t, : k = 0
// Put digits (as floats) and operators (as strings) in arrays
for a = 0 to 3 : s = mid( t, a, 1 ) : n(a) = fn StringFloatValue( s ) : o(a) = mid( os, a, 1 ) : next
// Permutions for the digits ...
for d = 0 to 3 : for e = 0 to 3 : for f = 0 to 3 : for g = 0 to 3
if d != e and d != f and d != g and e != f and e != g and f != g // ... without duplications
// Combinations for the operators (3 from 4, with replacement)
for a = 0 to 3 : for b = 0 to 3 : for c = 0 to 3
fn eval( fn StringWithFormat( @"%f %@ %f %@ %f %@ %f", n(d), o(a), n(e), o(b), n(f), o(c), n(g) ) ) : if k > 0 then exit fn
fn eval( fn StringWithFormat( @"%f %@ ( %f %@ %f ) %@ %f", n(d), o(a), n(e), o(b), n(f), o(c), n(g) ) ) : if k > 0 then exit fn
fn eval( fn StringWithFormat( @"%f %@ %f %@ ( %f %@ %f )", n(d), o(a), n(e), o(b), n(f), o(c), n(g) ) ) : if k > 0 then exit fn
fn eval( fn StringWithFormat( @"%f %@ ( %f %@ %f %@ %f )", n(d), o(a), n(e), o(b), n(f), o(c), n(g) ) ) : if k > 0 then exit fn
fn eval( fn StringWithFormat( @"( %f %@ %f ) %@ %f %@ %f", n(d), o(a), n(e), o(b), n(f), o(c), n(g) ) ) : if k > 0 then exit fn
fn eval( fn StringWithFormat( @"( %f %@ %f %@ %f ) %@ %f", n(d), o(a), n(e), o(b), n(f), o(c), n(g) ) ) : if k > 0 then exit fn
fn eval( fn StringWithFormat( @"%f %@ ( %f %@ ( %f %@ %f ) )", n(d), o(a), n(e), o(b), n(f), o(c), n(g) ) ) : if k > 0 then exit fn
fn eval( fn StringWithFormat( @"( %f %@ %f ) %@ ( %f %@ %f )", n(d), o(a), n(e), o(b), n(f), o(c), n(g) ) ) : if k > 0 then exit fn
fn eval( fn StringWithFormat( @"( %f %@ ( %f %@ %f )) %@ %f", n(d), o(a), n(e), o(b), n(f), o(c), n(g) ) ) : if k > 0 then exit fn
fn eval( fn StringWithFormat( @"( ( %f %@ %f ) %@ %f ) %@ %f", n(d), o(a), n(e), o(b), n(f), o(c), n(g) ) ) : if k > 0 then exit fn
fn eval( fn StringWithFormat( @"%f %@ ( ( %f %@ %f ) %@ %f )", n(d), o(a), n(e), o(b), n(f), o(c), n(g) ) ) : if k > 0 then exit fn
next : next : next
end if
next : next : next : next
end fn
 
 
window 1, @"24 Game", ( 0, 0, 250, 250 )
fn work(@"3388")
fn work(@"1346")
fn work(@"8752")
 
handleevents
 
</syntaxhighlight>
{{out}}
 
[[File:FB 24.jpg]]
 
=={{header|GAP}}==
<langsyntaxhighlight lang="gap"># Solution in '''RPN'''
check := function(x, y, z)
local r, c, s, i, j, k, a, b, p;
Line 1,816 ⟶ 4,292:
# A tricky one:
Player24([3,3,8,8]);
"8383/-/"</langsyntaxhighlight>
 
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 1,990 ⟶ 4,465:
}
}
}</langsyntaxhighlight>
{{out}}
<pre> 8 6 7 6: No solution
Line 2,005 ⟶ 4,480:
 
=={{header|Gosu}}==
<syntaxhighlight lang="gosu">
<lang Gosu>
uses java.lang.Integer
uses java.lang.Double
Line 2,116 ⟶ 4,591:
print( "No solution!" )
}
</syntaxhighlight>
</lang>
 
=={{header|Haskell}}==
 
<langsyntaxhighlight lang="haskell">import Data.List
import Data.Ratio
import Control.Monad
Line 2,169 ⟶ 4,644:
nub $ permutations $ map Constant r4
 
main = getArgs >>= mapM_ print . solve 24 . map (toEnum . read)</langsyntaxhighlight>
 
Example use:
Line 2,187 ⟶ 4,662:
(8 / (2 / (9 - 3)))</pre>
===Alternative version===
<langsyntaxhighlight lang="haskell">import Control.Applicative
import Data.List
import Text.PrettyPrint
Line 2,228 ⟶ 4,703:
 
main = mapM_ (putStrLn . render . toDoc) $ solve 24 [2,3,8,9]</langsyntaxhighlight>
{{out}}
<pre>((8 / 2) * (9 - 3))
Line 2,244 ⟶ 4,719:
(((9 - 3) * 8) / 2)</pre>
 
== {{header|Icon}} and {{header|Unicon}} ==
This shares code with and solves the [[24_game#Icon_and_Unicon|24 game]]. A series of pattern expressions are built up and then populated with the permutations of the selected digits. Equations are skipped if they have been seen before. The procedure 'eval' was modified to catch zero divides. The solution will find either all occurrences or just the first occurrence of a solution.
 
<langsyntaxhighlight Iconlang="icon">invocable all
link strings # for csort, deletec, permutes
 
Line 2,322 ⟶ 4,797:
suspend 2(="(", E(), =")") | # parenthesized subexpression, or ...
tab(any(&digits)) # just a value
end</langsyntaxhighlight>
 
 
Line 2,329 ⟶ 4,804:
 
=={{header|J}}==
<langsyntaxhighlight Jlang="j">perm=: (A.&i.~ !) 4
ops=: ' ',.'+-*%' {~ >,{i.each 4 4 4
cmask=: 1 + 0j1 * i.@{:@$@[ e. ]
Line 2,337 ⟶ 4,812:
parens=: ], 0 paren 3, 0 paren 5, 2 paren 5, [: 0 paren 7 (0 paren 3)
all=: [: parens [:,/ ops ,@,."1/ perm { [:;":each
answer=: ({.@#~ 24 = ".)@all</langsyntaxhighlight>
 
This implementation tests all 7680 candidate sentences.
Line 2,351 ⟶ 4,826:
 
The answer will be either a suitable J sentence or blank if none can be found. "J sentence" means that, for example, the sentence <code>8*7-4*1</code> is equivalent to the sentence <code>8*(7-(4*1))</code>. [Many infix languages use operator precedence to make polynomials easier to express without parenthesis, but J has other mechanisms for expressing polynomials and minimal operator precedence makes the language more regular.]
 
Here is an alternative version that supports multi-digit numbers. It prefers expressions without parens, but searches for ones with if needed.
 
<syntaxhighlight lang="j">ops=: > , { 3#<'+-*%'
perms=: [: ":"0 [: ~. i.@!@# A. ]
build=: 1 : '(#~ 24 = ".) @: u'
 
combp=: dyad define
'a b c d'=. y['f g h'=. x
('(',a,f,b,g,c,')',h,d),('(',a,f,b,')',g,c,h,d),(a,f,'(',b,g,c,')',h,d),:('((',a,f,b,')',g,c,')',h,d)
)
 
math24=: monad define
assert. 4 = # y NB. prefer expressions without parens & fallback if needed
es=. ([: ,/ ops ([: , (' ',[) ,. ])"1 2/ perms) build y
if. 0 = #es do. es =. ([: ,/ [: ,/ ops combp"1 2/ perms) build y end.
es -."1 ' '
)</syntaxhighlight>
 
{{out}}
<pre> math24 2 3 5 12
12%3-5%2
math24 2 3 8 9
8*9-2*3
8*9-3*2
8%2%9-3
math24 3 6 6 11
(6+6*11)%3
(6+11*6)%3
((6*11)+6)%3
((11*6)+6)%3
</pre>
 
=={{header|Java}}==
{{works with|Java|7}}
Playable version, will print solution on request.
 
<lang java>import java.util.*;
Note that this version does not extend to different digit ranges.
<syntaxhighlight lang="java">import java.util.*;
 
public class Game24Player {
Line 2,618 ⟶ 5,127:
res.add(Arrays.asList((i / npow), (i % npow) / n, i % n));
}
}</langsyntaxhighlight>
 
{{out}}
Line 2,662 ⟶ 5,171:
=={{header|JavaScript}}==
This is a translation of the C code.
<langsyntaxhighlight lang="javascript">var ar=[],order=[0,1,2],op=[],val=[];
var NOVAL=9999,oper="+-*/",out;
 
Line 2,765 ⟶ 5,274:
solve24("1234");
solve24("6789");
solve24("1127");</langsyntaxhighlight>
 
Examples:
Line 2,772 ⟶ 5,281:
((6*8)/((9-7)))
(((1+7))*(2+1))</pre>
 
=={{header|jq}}==
{{works with|jq|1.4}}
The following solution is generic: the objective (e.g. 24) is specified as
the argument to solve/1, and the user may specify any number of numbers.
 
'''Infrastructure:'''
<syntaxhighlight lang="jq"># Generate a stream of the permutations of the input array.
def permutations:
if length == 0 then []
else range(0;length) as $i
| [.[$i]] + (del(.[$i])|permutations)
end ;
 
# Generate a stream of arrays of length n,
# with members drawn from the input array.
def take(n):
length as $l |
if n == 1 then range(0;$l) as $i | [ .[$i] ]
else take(n-1) + take(1)
end;
 
# Emit an array with elements that alternate between those in the input array and those in short,
# starting with the former, and using nothing if "short" is too too short.
def intersperse(short):
. as $in
| reduce range(0;length) as $i
([]; . + [ $in[$i], (short[$i] // empty) ]);
 
# Emit a stream of all the nested triplet groupings of the input array elements,
# e.g. [1,2,3,4,5] =>
# [1,2,[3,4,5]]
# [[1,2,3],4,5]
#
def triples:
. as $in
| if length == 3 then .
elif length == 1 then $in[0]
elif length < 3 then empty
else
(range(0; (length-1) / 2) * 2 + 1) as $i
| ($in[0:$i] | triples) as $head
| ($in[$i+1:] | triples) as $tail
| [$head, $in[$i], $tail]
end;</syntaxhighlight>
'''Evaluation and pretty-printing of allowed expressions'''
<syntaxhighlight lang="jq"># Evaluate the input, which must be a number or a triple: [x, op, y]
def eval:
if type == "array" then
.[1] as $op
| if .[0] == null or .[2] == null then null
else
(.[0] | eval) as $left | (.[2] | eval) as $right
| if $left == null or $right == null then null
elif $op == "+" then $left + $right
elif $op == "-" then $left - $right
elif $op == "*" then $left * $right
elif $op == "/" then
if $right == 0 then null
else $left / $right
end
else "invalid arithmetic operator: \($op)" | error
end
end
else .
end;
 
def pp:
"\(.)" | explode | map([.] | implode | if . == "," then " " elif . == "\"" then "" else . end) | join("");</syntaxhighlight>
 
'''24 Game''':
<syntaxhighlight lang="jq">def OPERATORS: ["+", "-", "*", "/"];
 
# Input: an array of 4 digits
# o: an array of 3 operators
# Output: a stream
def EXPRESSIONS(o):
intersperse( o ) | triples;
 
def solve(objective):
length as $length
| [ (OPERATORS | take($length-1)) as $poperators
| permutations | EXPRESSIONS($poperators)
| select( eval == objective)
] as $answers
| if $answers|length > 3 then "That was too easy. I found \($answers|length) answers, e.g. \($answers[0] | pp)"
elif $answers|length > 1 then $answers[] | pp
else "You lose! There are no solutions."
end
;
 
solve(24), "Please try again."</syntaxhighlight>
{{out}}
<syntaxhighlight lang="sh">$ jq -r -f Solve.jq
[1,2,3,4]
That was too easy. I found 242 answers, e.g. [4 * [1 + [2 + 3]]]
Please try again.
[1,2,3,40,1]
That was too easy. I found 636 answers, e.g. [[[1 / 2] * 40] + [3 + 1]]
Please try again.
[3,8,9]
That was too easy. I found 8 answers, e.g. [[8 / 3] * 9]
Please try again.
[4,5,6]
You lose! There are no solutions.
Please try again.
[1,2,3,4,5,6]
That was too easy. I found 197926 answers, e.g. [[2 * [1 + 4]] + [3 + [5 + 6]]]
Please try again.</syntaxhighlight>
 
=={{header|Julia}}==
 
<lang julia>function solve24(nums)
For julia version 0.5 and higher, the Combinatorics package must be installed and imported (`using Combinatorics`). Combinatorial functions like `nthperm` have been moved from Base to that package and are not available by default anymore.
<syntaxhighlight lang="julia">function solve24(nums)
length(nums) != 4 && error("Input must be a 4-element Array")
syms = [+,-,*,/]
Line 2,792 ⟶ 5,412:
end
return "0"
end</langsyntaxhighlight>
{{out}}
<pre>julia> solve24([6,for 8,i 2,in 8])1:10
nums = rand(1:9, 4)
"(6+8)+(2+8)"
println("solve24($nums) -> $(solve24(nums))")
end
solve24([9,4,4,5]) -> 0
solve24([1,7,2,7]) -> ((7*7)-1)/2
solve24([5,7,5,4]) -> 4*(7-(5/5))
solve24([1,4,6,6]) -> 6+(6*(4-1))
solve24([2,3,7,3]) -> ((2+7)*3)-3
solve24([8,7,9,7]) -> 0
solve24([1,6,2,6]) -> 6+(6*(1+2))
solve24([7,9,4,1]) -> (7-4)*(9-1)
solve24([6,4,2,2]) -> (2-2)+(6*4)
solve24([5,7,9,7]) -> (5+7)*(9-7)</pre>
 
=={{header|Kotlin}}==
julia> solve24([4, 2, 8, 1])
{{trans|C}}
"8*(4+(1-2))"
<syntaxhighlight lang="scala">// version 1.1.3
 
import java.util.Random
julia> solve24([3, 1, 9, 9])#
"(9-1)*(9/3)"
 
const val N_CARDS = 4
julia> solve24([5, 7, 5, 1])#
const val SOLVE_GOAL = 24
"0"
const val MAX_DIGIT = 9
 
class Frac(val num: Int, val den: Int)
julia> solve24([5, 8, 4, 1])
"8+(4*(5-1))"
 
enum class OpType { NUM, ADD, SUB, MUL, DIV }
julia> solve24([8, 3, 4, 9])
"(8+3)+(4+9)"
 
class Expr(
julia> solve24([3, 7, 4, 4])#
var op: OpType = OpType.NUM,
"4*(3+(7-4))"
var left: Expr? = null,
var right: Expr? = null,
var value: Int = 0
)
 
fun showExpr(e: Expr?, prec: OpType, isRight: Boolean) {
julia> solve24([5, 6, 4, 1])
if (e == null) return
"4/(1-(5/6))"
val op = when (e.op) {
OpType.NUM -> { print(e.value); return }
OpType.ADD -> " + "
OpType.SUB -> " - "
OpType.MUL -> " x "
OpType.DIV -> " / "
}
 
if ((e.op == prec && isRight) || e.op < prec) print("(")
julia> solve24([5, 5, 9, 8])
showExpr(e.left, e.op, false)
"(8-9)+(5*5)"</pre>
print(op)
showExpr(e.right, e.op, true)
if ((e.op == prec && isRight) || e.op < prec) print(")")
}
 
fun evalExpr(e: Expr?): Frac {
if (e == null) return Frac(0, 1)
if (e.op == OpType.NUM) return Frac(e.value, 1)
val l = evalExpr(e.left)
val r = evalExpr(e.right)
return when (e.op) {
OpType.ADD -> Frac(l.num * r.den + l.den * r.num, l.den * r.den)
OpType.SUB -> Frac(l.num * r.den - l.den * r.num, l.den * r.den)
OpType.MUL -> Frac(l.num * r.num, l.den * r.den)
OpType.DIV -> Frac(l.num * r.den, l.den * r.num)
else -> throw IllegalArgumentException("Unknown op: ${e.op}")
}
}
 
fun solve(ea: Array<Expr?>, len: Int): Boolean {
if (len == 1) {
val final = evalExpr(ea[0])
if (final.num == final.den * SOLVE_GOAL && final.den != 0) {
showExpr(ea[0], OpType.NUM, false)
return true
}
}
 
val ex = arrayOfNulls<Expr>(N_CARDS)
for (i in 0 until len - 1) {
for (j in i + 1 until len) ex[j - 1] = ea[j]
val node = Expr()
ex[i] = node
for (j in i + 1 until len) {
node.left = ea[i]
node.right = ea[j]
for (k in OpType.values().drop(1)) {
node.op = k
if (solve(ex, len - 1)) return true
}
node.left = ea[j]
node.right = ea[i]
node.op = OpType.SUB
if (solve(ex, len - 1)) return true
node.op = OpType.DIV
if (solve(ex, len - 1)) return true
ex[j] = ea[j]
}
ex[i] = ea[i]
}
return false
}
 
fun solve24(n: IntArray) =
solve (Array(N_CARDS) { Expr(value = n[it]) }, N_CARDS)
 
fun main(args: Array<String>) {
val r = Random()
val n = IntArray(N_CARDS)
for (j in 0..9) {
for (i in 0 until N_CARDS) {
n[i] = 1 + r.nextInt(MAX_DIGIT)
print(" ${n[i]}")
}
print(": ")
println(if (solve24(n)) "" else "No solution")
}
}</syntaxhighlight>
 
Sample output:
<pre>
8 4 1 7: (8 - 4) x (7 - 1)
6 1 4 1: ((6 + 1) - 1) x 4
8 8 5 4: (8 / 8 + 5) x 4
9 6 9 8: 8 / ((9 - 6) / 9)
6 6 9 6: (6 x 6) / 9 x 6
9 9 7 7: No solution
1 1 2 5: No solution
6 9 4 1: 6 x (9 - 4 - 1)
7 7 6 4: 7 + 7 + 6 + 4
4 8 8 4: 4 + 8 + 8 + 4
</pre>
 
=={{header|Liberty BASIC}}==
<langsyntaxhighlight lang="lb">dim d(4)
input "Enter 4 digits: "; a$
nD=0
Line 2,944 ⟶ 5,668:
exit function
[handler]
end function</langsyntaxhighlight>
 
=={{header|Lua}}==
Line 2,950 ⟶ 5,674:
Generic solver: pass card of any size with 1st argument and target number with second.
 
<langsyntaxhighlight lang="lua">
local SIZE = #arg[1]
local GOAL = tonumber(arg[2]) or 24
Line 3,025 ⟶ 5,749:
 
permgen(input, SIZE)
</syntaxhighlight>
</lang>
 
{{out}}
Line 3,063 ⟶ 5,787:
</pre>
 
=={{header|Mathematica}} / {{header|Wolfram Language}}==
The code:
<syntaxhighlight lang="mathematica">
<lang Mathematica>
treeR[n_] := Table[o[trees[a], trees[n - a]], {a, 1, n - 1}]
treeR[1] := n
Line 3,081 ⟶ 5,805:
Permutations[Array[v, 4]], 1]],
Quiet[(# /. v[q_] :> val[[q]]) == 24] &] /.
Table[v[q] -> val[[q]], {q, 4}])]</langsyntaxhighlight>
 
The <code>treeR</code> method recursively computes all possible operator trees for a certain number of inputs. It does this by tabling all combinations of distributions of inputs across the possible values. (For example, <code>treeR[4]</code> is allotted 4 inputs, so it returns <code>{o[treeR[3],treeR[1]],o[treeR[2],treeR[2]],o[treeR[1],treeR[3]]}</code>, where <code>o</code> is the operator (generic at this point).
Line 3,115 ⟶ 5,839:
**For each result, turn the expression into a string (for easy manipulation), strip the "<code>HoldForm</code>" wrapper, replace numbers like "-1*7" with "-7" (a idiosyncrasy of the conversion process), and remove any lingering duplicates. Some duplicates will still remain, notably constructs like "3 - 3" vs. "-3 + 3" and trivially similar expressions like "(8*3)*(6-5)" vs "(8*3)/(6-5)". Example run input and outputs:
 
<langsyntaxhighlight Mathematicalang="mathematica">game24play[RandomInteger[{1, 9}, 4]]</langsyntaxhighlight>
 
{{out}}
Line 3,137 ⟶ 5,861:
*<code>Permutations[Array[v, n]]</code> returns <math>n!</math> permutations.
Therefore, the size of the working set is <math>64 \cdot n!\, C_{n-1} = 64 \cdot (n-1)!!!! = 64 \frac{(2n-2)!}{(n-1)!}</math>, where <math>n!!!!</math> is the [[wp:quadruple factorial|quadruple factorial]]. It goes without saying that this number increases very fast. For this game, the total is 7680 elements. For higher numbers of inputs, it is {7 680, 107 520, 1 935 360, 42 577 920, 1 107 025 920, ...}.
 
An alternative solution operates on Mathematica expressions directly without using any inert intermediate form for the expression tree, but by using <code>Hold</code> to prevent Mathematica from evaluating the expression tree.
 
<syntaxhighlight lang="mathematica">evaluate[HoldForm[op_[l_, r_]]] := op[evaluate[l], evaluate[r]];
evaluate[x_] := x;
combine[l_, r_ /; evaluate[r] != 0] := {HoldForm[Plus[l, r]],
HoldForm[Subtract[l, r]], HoldForm[Times[l, r]],
HoldForm[Divide[l, r]] };
combine[l_, r_] := {HoldForm[Plus[l, r]], HoldForm[Subtract[l, r]],
HoldForm[Times[l, r]]};
split[items_] :=
Table[{items[[1 ;; i]], items[[i + 1 ;; Length[items]]]}, {i, 1,
Length[items] - 1}];
expressions[{x_}] := {x};
expressions[items_] :=
Flatten[Table[
Flatten[Table[
combine[l, r], {l, expressions[sp[[1]]]}, {r,
expressions[sp[[2]]]}], 2], {sp, split[items]}]];
 
(* Must use all atoms in given order. *)
solveMaintainOrder[goal_, items_] :=
Select[expressions[items], (evaluate[#] == goal) &];
(* Must use all atoms, but can permute them. *)
solveCanPermute[goal_, items_] :=
Flatten[Table[
solveMaintainOrder[goal, pitems], {pitems,
Permutations[items]}]];
(* Can use any subset of atoms. *)
solveSubsets[goal_, items_] :=
Flatten[Table[
solveCanPermute[goal, is], {is,
Subsets[items, {1, Length[items]}]}], 2];
 
(* Demonstration to find all the ways to create 1/5 from {2, 3, 4, 5}. *)
solveMaintainOrder[1/5, Range[2, 5]]
solveCanPermute[1/5, Range[2, 5]]
solveSubsets[1/5, Range[2, 5]]</syntaxhighlight>
 
=={{header|Nim}}==
 
{{trans|Python Succinct}}
{{works with|Nim Compiler|0.19.4}}
 
<syntaxhighlight lang="nim">import algorithm, sequtils, strformat
 
type
Operation = enum
opAdd = "+"
opSub = "-"
opMul = "*"
opDiv = "/"
 
const Ops = @[opAdd, opSub, opMul, opDiv]
 
func opr(o: Operation, a, b: float): float =
case o
of opAdd: a + b
of opSub: a - b
of opMul: a * b
of opDiv: a / b
 
func solve(nums: array[4, int]): string =
func `~=`(a, b: float): bool =
abs(a - b) <= 1e-5
 
result = "not found"
let sortedNums = nums.sorted.mapIt float it
for i in product Ops.repeat 3:
let (x, y, z) = (i[0], i[1], i[2])
var nums = sortedNums
while true:
let (a, b, c, d) = (nums[0], nums[1], nums[2], nums[3])
if x.opr(y.opr(a, b), z.opr(c, d)) ~= 24.0:
return fmt"({a:0} {y} {b:0}) {x} ({c:0} {z} {d:0})"
if x.opr(a, y.opr(b, z.opr(c, d))) ~= 24.0:
return fmt"{a:0} {x} ({b:0} {y} ({c:0} {z} {d:0}))"
if x.opr(y.opr(z.opr(c, d), b), a) ~= 24.0:
return fmt"(({c:0} {z} {d:0}) {y} {b:0}) {x} {a:0}"
if x.opr(y.opr(b, z.opr(c, d)), a) ~= 24.0:
return fmt"({b:0} {y} ({c:0} {z} {d:0})) {x} {a:0}"
if not nextPermutation(nums): break
 
proc main() =
for nums in [
[9, 4, 4, 5],
[1, 7, 2, 7],
[5, 7, 5, 4],
[1, 4, 6, 6],
[2, 3, 7, 3],
[8, 7, 9, 7],
[1, 6, 2, 6],
[7, 9, 4, 1],
[6, 4, 2, 2],
[5, 7, 9, 7],
[3, 3, 8, 8], # Difficult case requiring precise division
]:
echo fmt"solve({nums}) -> {solve(nums)}"
 
when isMainModule: main()</syntaxhighlight>
 
{{out}}
<pre>
solve([9, 4, 4, 5]) -> not found
solve([1, 7, 2, 7]) -> ((7 * 7) - 1) / 2
solve([5, 7, 5, 4]) -> 4 * (7 - (5 / 5))
solve([1, 4, 6, 6]) -> 6 - (6 * (1 - 4))
solve([2, 3, 7, 3]) -> (7 - 3) * (2 * 3)
solve([8, 7, 9, 7]) -> not found
solve([1, 6, 2, 6]) -> (6 - 2) / (1 / 6)
solve([7, 9, 4, 1]) -> (1 - 9) * (4 - 7)
solve([6, 4, 2, 2]) -> 2 * (4 / (2 / 6))
solve([5, 7, 9, 7]) -> (5 + 7) * (9 - 7)
solve([3, 3, 8, 8]) -> 8 / (3 - (8 / 3))
</pre>
 
=={{header|OCaml}}==
 
<langsyntaxhighlight lang="ocaml">type expression =
| Const of float
| Sum of expression * expression (* e1 + e2 *)
Line 3,209 ⟶ 6,048:
| x::xs -> comp x xs
| [] -> assert false
) all</langsyntaxhighlight>
 
<pre>
Line 3,225 ⟶ 6,064:
 
Note: the <code>permute</code> function was taken from [http://faq.perl.org/perlfaq4.html#How_do_I_permute_N_e here]
<langsyntaxhighlight Perllang="perl"># Fischer-Krause ordered permutation generator
# http://faq.perl.org/perlfaq4.html#How_do_I_permute_N_e
sub permute :prototype(&@) {
my $code = shift;
my @idx = 0..$#_;
Line 3,278 ⟶ 6,117:
}
}
}</langsyntaxhighlight>
{{out}}
<pre>E:\Temp>24solve.pl
Line 3,306 ⟶ 6,145:
E:\Temp></pre>
 
=={{header|Perl 6Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">-- demo\rosetta\24_game_solve.exw</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #000080;font-style:italic;">-- The following 5 parse expressions are possible.
-- Obviously numbers 1234 represent 24 permutations from
-- {1,2,3,4} to {4,3,2,1} of indexes to the real numbers.
-- Likewise "+-*" is like "123" representing 64 combinations
-- from {1,1,1} to {4,4,4} of indexes to "+-*/".
-- Both will be replaced if/when the strings get printed.
-- Last hint is because of no precedence, just parenthesis.
--</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">OPS</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"+-*/"</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">expressions</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"1+(2-(3*4))"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"1+((2-3)*4)"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"(1+2)-(3*4)"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"(1+(2-3))*4"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"((1+2)-3)*4"</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- (equivalent to "1+2-3*4")
-- The above represented as three sequential operations (the result gets
-- left in &lt;(map)1&gt;, ie vars[perms[operations[i][3][1]]] aka vars[lhs]):</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">operations</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'*'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'-'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'+'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">}},</span> <span style="color: #000080;font-style:italic;">--3*=4; 2-=3; 1+=2</span>
<span style="color: #0000FF;">{{</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'-'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'*'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'+'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">}},</span> <span style="color: #000080;font-style:italic;">--2-=3; 2*=4; 1+=2</span>
<span style="color: #0000FF;">{{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'+'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'*'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'-'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">}},</span> <span style="color: #000080;font-style:italic;">--1+=2; 3*=4; 1-=3</span>
<span style="color: #0000FF;">{{</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'-'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'+'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'*'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">}},</span> <span style="color: #000080;font-style:italic;">--2-=3; 1+=2; 1*=4</span>
<span style="color: #0000FF;">{{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'+'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'-'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'*'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">}}}</span> <span style="color: #000080;font-style:italic;">--1+=2; 1-=3; 1*=4</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">evalopset</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">opset</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">perms</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ops</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">vars</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- invoked 5*24*64 = 7680 times, to try all possible expressions/vars/operators
-- (btw, vars is copy-on-write, like all parameters not explicitly returned, so
-- we can safely re-use it without clobbering the callee version.)
-- (update: with js made that illegal and reported it correctly and forced the
-- addition of the deep_copy(), all exactly the way it should.)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">lhs</span><span style="color: #0000FF;">,</span><span style="color: #000000;">op</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rhs</span>
<span style="color: #000000;">vars</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">vars</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">opset</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">lhs</span><span style="color: #0000FF;">,</span><span style="color: #000000;">op</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rhs</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">opset</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">lhs</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">perms</span><span style="color: #0000FF;">[</span><span style="color: #000000;">lhs</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">op</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ops</span><span style="color: #0000FF;">[</span><span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">op</span><span style="color: #0000FF;">,</span><span style="color: #000000;">OPS</span><span style="color: #0000FF;">)]</span>
<span style="color: #000000;">rhs</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">perms</span><span style="color: #0000FF;">[</span><span style="color: #000000;">rhs</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'+'</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">vars</span><span style="color: #0000FF;">[</span><span style="color: #000000;">lhs</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">vars</span><span style="color: #0000FF;">[</span><span style="color: #000000;">rhs</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'-'</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">vars</span><span style="color: #0000FF;">[</span><span style="color: #000000;">lhs</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">vars</span><span style="color: #0000FF;">[</span><span style="color: #000000;">rhs</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'*'</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">vars</span><span style="color: #0000FF;">[</span><span style="color: #000000;">lhs</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">*=</span> <span style="color: #000000;">vars</span><span style="color: #0000FF;">[</span><span style="color: #000000;">rhs</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'/'</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">vars</span><span style="color: #0000FF;">[</span><span style="color: #000000;">rhs</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">1e300</span><span style="color: #0000FF;">*</span><span style="color: #000000;">1e300</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">vars</span><span style="color: #0000FF;">[</span><span style="color: #000000;">lhs</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">/=</span> <span style="color: #000000;">vars</span><span style="color: #0000FF;">[</span><span style="color: #000000;">rhs</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">vars</span><span style="color: #0000FF;">[</span><span style="color: #000000;">lhs</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">nSolutions</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">xSolutions</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">success</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">expr</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">perms</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ops</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">vars</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">expr</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">expr</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">>=</span><span style="color: #008000;">'1'</span> <span style="color: #008080;">and</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;"><=</span><span style="color: #008000;">'9'</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">expr</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">vars</span><span style="color: #0000FF;">[</span><span style="color: #000000;">perms</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">-</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">]]+</span><span style="color: #008000;">'0'</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">,</span><span style="color: #000000;">OPS</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">expr</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ops</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">expr</span><span style="color: #0000FF;">,</span><span style="color: #000000;">xSolutions</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- avoid duplicates for eg {1,1,2,7} because this has found
-- the "same" solution but with the 1st and 2nd 1s swapped,
-- and likewise whenever an operator is used more than once.</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"success: %s = %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">expr</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">sprint</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">)})</span>
<span style="color: #000000;">nSolutions</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">xSolutions</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">xSolutions</span><span style="color: #0000FF;">,</span><span style="color: #000000;">expr</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">tryperms</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">perms</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ops</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">vars</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">operations</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000080;font-style:italic;">-- 5 parse expressions</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">evalopset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">operations</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">perms</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ops</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">vars</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">round</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1e9</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- fudge tricky 8/(3-(8/3)) case</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">=</span><span style="color: #000000;">24</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">success</span><span style="color: #0000FF;">(</span><span style="color: #000000;">expressions</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">perms</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ops</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">vars</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">tryops</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">ops</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">vars</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">factorial</span><span style="color: #0000FF;">(</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000080;font-style:italic;">-- 24 var permutations</span>
<span style="color: #000000;">tryperms</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">permute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">}),</span><span style="color: #000000;">ops</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">vars</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">global</span> <span style="color: #008080;">procedure</span> <span style="color: #000000;">solve24</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">vars</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">nSolutions</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #000000;">xSolutions</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">op1</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">op2</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">op3</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
<span style="color: #000080;font-style:italic;">-- 64 operator combinations</span>
<span style="color: #000000;">tryops</span><span style="color: #0000FF;">({</span><span style="color: #000000;">OPS</span><span style="color: #0000FF;">[</span><span style="color: #000000;">op1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">OPS</span><span style="color: #0000FF;">[</span><span style="color: #000000;">op2</span><span style="color: #0000FF;">],</span><span style="color: #000000;">OPS</span><span style="color: #0000FF;">[</span><span style="color: #000000;">op3</span><span style="color: #0000FF;">]},</span><span style="color: #000000;">vars</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n%d solutions\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">nSolutions</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #000000;">solve24</span><span style="color: #0000FF;">({</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">})</span>
<span style="color: #000080;font-style:italic;">--solve24({6,4,6,1})
--solve24({3,3,8,8})
--solve24({6,9,7,4})</span>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
success: (1+2)*(7+1) = 24
success: (1+7)*(1+2) = 24
success: (1+2)*(1+7) = 24
success: (2+1)*(7+1) = 24
success: (7+1)*(1+2) = 24
success: (2+1)*(1+7) = 24
success: (1+7)*(2+1) = 24
success: (7+1)*(2+1) = 24
 
8 solutions
A loose translation of the Perl entry. Does not return every possible permutation of the possible solutions. Filters out duplicates (from repeated digits) and only reports the solution for a particular order of digits and operators with the fewest parenthesis (avoids reporting duplicate solutions only differing by unnecessary parenthesis).
</pre>
 
=={{header|Picat}}==
Since Perl 6 uses Rational numbers for division (whenever possible) there is no loss of precision as is common with floating point division. So a comparison like (1 + 7) / (1 / 3) == 24 "Just Works"<sup>&trade;</sup>
<syntaxhighlight lang="picat">main =>
foreach (_ in 1..10)
Nums = [D : _ in 1..4, D = random() mod 9 + 1],
NumExps = [(D,D) : D in Nums],
println(Nums),
(solve(NumExps) -> true; println("No solution")),
nl
end.
 
solve([(Num,Exp)]), Num =:= 24 =>
<lang Perl6>my @digits;
println(Exp).
my $amount = 4;
solve(NumExps) =>
select((Num1,Exp1),NumExps,NumExps1),
select((Num2,Exp2),NumExps1,NumExps2),
member(Op, ['+','-','*','/']),
(Op == '/' -> Num2 =\= 0; true),
Num3 = apply(Op,Num1,Num2),
Exp3 =.. [Op,Exp1,Exp2],
solve([(Num3,Exp3)|NumExps2]).
</syntaxhighlight>
 
{{trans|Raku}}
# Get $amount digits from the user,
<syntaxhighlight lang="picat">import util.
# ask for more if they don't supply enough
while @digits.elems < $amount {
@digits ,= (prompt "Enter {$amount - @digits} digits from 1 to 9, "
~ '(repeats allowed): ').comb(/<[1..9]>/);
}
# Throw away any extras
@digits = @digits[^$amount];
 
main =>
# Generate combinations of operators
Target=24,
my @op = <+ - * />;
Nums = [5,6,7,8],
my @ops = map {my $a = $_; map {my $b = $_; map {[$a,$b,$_]}, @op}, @op}, @op;
All=findall(Expr, solve_num(Nums,Target,Expr)),
foreach(Expr in All) println(Expr.flatten()) end,
println(len=All.length),
nl.
 
% A string based approach, inspired by - among others - the Raku solution.
# Enough sprintf formats to cover most precedence orderings
solve_num(Nums, Target,Expr) =>
my @formats = (
Patterns = [
'%d %s %d %s %d %s %d',
'(%d %s %d) %s %d %s %d' "A X B Y C Z D",
'(%d %s %d %s %d "(A X B) %sY C Z %d'D",
' "((%dA %sX %d)B %sY %dC) %sZ %d'D",
'(%d %s %d) %s "(%d(A %sX %dB)' Y C) Z D",
'%d %s "(%dA %sX %dB) Y (C %sZ %dD)'",
'%d %s (%d %s "A X (%dB %sY %d)C Z D)'",
"A X (B Y (C Z D))"
);
],
permutation(Nums,[A,B,C,D]),
Syms = [+,-,*,/],
member(X ,Syms),
member(Y ,Syms),
member(Z ,Syms),
member(Pattern,Patterns),
Expr = replace_all(Pattern,
"ABCDXYZ",
[A,B,C,D,X,Y,Z]),
catch(Target =:= Expr.eval(), E, ignore(E)).
 
eval(Expr) = parse_term(Expr.flatten()).apply().
# Brute force test the different permutations
for unique permutations @digits -> @p {
for @ops -> @o {
for @formats -> $format {
my $string = sprintf $format, @p[0], @o[0],
@p[1], @o[1], @p[2], @o[2], @p[3];
my $result = try { eval($string) };
say "$string = 24" and last if $result and $result == 24;
}
}
}
 
ignore(_E) => fail. % ignore zero_divisor errors
# Perl 6 translation of Fischer-Krause ordered permutation algorithm
sub permutations (@array) {
my @index = ^@array;
my $last = @index[*-1];
my (@permutations, $rev, $fwd);
loop {
push @permutations, [@array[@index]];
$rev = $last;
--$rev while $rev and @index[$rev-1] > @index[$rev];
return @permutations unless $rev;
$fwd = $rev;
push @index, @index.splice($rev).reverse;
++$fwd while @index[$rev-1] > @index[$fwd];
@index[$rev-1,$fwd] = @index[$fwd,$rev-1];
}
}
 
% Replace all occurrences in S with From -> To.
# Only return unique sub-arrays
replace_all(S,From,To) = Res =>
sub unique (@array) {
R = S,
my %h = map { $_.Str => $_ }, @array;
foreach({F,T} in zip(From,To))
%h.values;
R := replace(R, F,T.to_string())
}
end,
</lang>
Res = R.</syntaxhighlight>
 
{{out}}
<pre>
Picat> main
Enter 4 digits from 1 to 9, (repeats allowed): 3711
3 * (7 + 1 * 1) = 24
3 * (7 + 1 / 1) = 24
3 * (7 * 1 + 1) = 24
3 * (7 / 1 + 1) = 24
(3 + 1) * (7 - 1) = 24
3 * (1 + 7 * 1) = 24
3 * (1 + 7 / 1) = 24
(3 * 1) * (7 + 1) = 24
(3 / 1) * (7 + 1) = 24
3 / (1 / (7 + 1)) = 24
3 * (1 + 1 * 7) = 24
(3 * 1) * (1 + 7) = 24
3 * (1 / 1 + 7) = 24
(3 / 1) * (1 + 7) = 24
3 / (1 / (1 + 7)) = 24
(7 + 1) * 3 * 1 = 24
(7 + 1) * 3 / 1 = 24
(7 - 1) * (3 + 1) = 24
(7 + 1) * 1 * 3 = 24
(7 + 1) / 1 * 3 = 24
(7 + 1) / (1 / 3) = 24
(7 - 1) * (1 + 3) = 24
(7 * 1 + 1) * 3 = 24
(7 / 1 + 1) * 3 = 24
(1 + 3) * (7 - 1) = 24
(1 * 3) * (7 + 1) = 24
(1 * 3) * (1 + 7) = 24
(1 + 7) * 3 * 1 = 24
(1 + 7) * 3 / 1 = 24
(1 + 7) * 1 * 3 = 24
(1 + 7) / 1 * 3 = 24
(1 + 7) / (1 / 3) = 24
(1 * 7 + 1) * 3 = 24
(1 + 1 * 7) * 3 = 24
(1 * 1 + 7) * 3 = 24
(1 / 1 + 7) * 3 = 24
 
(5 + 7 - 8) * 6
Enter 4 digits from 1 to 9, (repeats allowed): 5 5 5 5
((5 *+ 57) - 58) / 5 =* 246
(5 + 7) * (8 - 6)
(5 - 8 + 7) * 6
((5 - 8) + 7) * 6
6 * (5 + 7 - 8)
6 * (5 + (7 - 8))
6 * (5 - 8 + 7)
6 * (5 - (8 - 7))
6 * (7 + 5 - 8)
6 * (7 + (5 - 8))
6 * (7 - 8 + 5)
6 * (7 - (8 - 5))
(6 * 8) / (7 - 5)
6 * (8 / (7 - 5))
(7 + 5 - 8) * 6
((7 + 5) - 8) * 6
(7 + 5) * (8 - 6)
(7 - 8 + 5) * 6
((7 - 8) + 5) * 6
(8 - 6) * (5 + 7)
(8 - 6) * (7 + 5)
(8 * 6) / (7 - 5)
8 * (6 / (7 - 5))
len = 24</pre>
 
Another approach:
Enter 4 digits from 1 to 9, (repeats allowed): 8833
 
8 / (3 - 8 / 3) = 24
<syntaxhighlight lang="picat">import util.
</pre>
 
main =>
Target=24,
Nums = [5,6,7,8],
_ = findall(Expr, solve_num2(Nums,Target)),
nl.
 
solve_num2(Nums, Target) =>
Syms = [+,-,*,/],
Perms = permutations([I.to_string() : I in Nums]),
Seen = new_map(), % weed out duplicates
foreach(X in Syms,Y in Syms, Z in Syms)
foreach(P in Perms)
[A,B,C,D] = P,
if catch(check(A,X,B,Y,C,Z,D,Target,Expr),E,ignore(E)),
not Seen.has_key(Expr) then
println(Expr.flatten()=Expr.eval().round()),
Seen.put(Expr,1)
end
end
end.
 
to_string2(Expr) = [E.to_string() : E in Expr].flatten().
 
ignore(_E) => fail. % ignore zero_divisor errors
 
check(A,X,B,Y,C,Z,D,Target,Expr) ?=>
Expr = ["(",A,Y,B,")",X,"(",C,Z,D,")"].to_string2(),
Target =:= Expr.eval().
 
check(A,X,B,Y,C,Z,D,Target,Expr) ?=>
Expr = [A,X,"(",B,Y,"(",C,Z,D,")",")"].to_string2(),
Target =:= Expr.eval().
 
check(A,X,B,Y,C,Z,D,Target,Expr) ?=>
Expr = ["(","(",C,Z,D,")",Y,B,")",X,A].to_string2(),
Target =:= Expr.eval().
 
check(A,X,B,Y,C,Z,D,Target,Expr) ?=>
Expr = ["(",B,Y,"(",C,Z,D,")",")",X,A].to_string2(),
Target =:= Expr.eval().
 
check(A,X,B,Y,C,Z,D,Target,Expr) =>
Expr = [A,X,"(","(",B,Y,C,")", Z,D,")"].to_string2(),
Target =:= Expr.eval().</syntaxhighlight>
 
{{out}}
<pre>> main
6*(5+(7-8)) = 24
6*(7+(5-8)) = 24
(5+7)*(8-6) = 24
(7+5)*(8-6) = 24
6*((7-8)+5) = 24
6*((5-8)+7) = 24
((5+7)-8)*6 = 24
((7+5)-8)*6 = 24
(8-6)*(5+7) = 24
(8-6)*(7+5) = 24
6*(7-(8-5)) = 24
6*(5-(8-7)) = 24
6*(8/(7-5)) = 24
8*(6/(7-5)) = 24
6/((7-5)/8) = 24
8/((7-5)/6) = 24
(6*8)/(7-5) = 24
(8*6)/(7-5) = 24</pre>
 
=={{header|PicoLisp}}==
We use Pilog (PicoLisp Prolog) to solve this task
<langsyntaxhighlight PicoLisplang="picolisp">(be play24 (@Lst @Expr) # Define Pilog rule
(permute @Lst (@A @B @C @D))
(member @Op1 (+ - * /))
Line 3,441 ⟶ 6,464:
(println @X) ) )
 
(play24 5 6 7 8) # Call 'play24' function</langsyntaxhighlight>
{{out}}
<pre>(* (+ 5 7) (- 8 6))
Line 3,460 ⟶ 6,483:
Note
This example uses the math module:
<langsyntaxhighlight ProDOSlang="prodos">editvar /modify -random- = <10
:a
editvar /newvar /withothervar /value=-random- /title=1
Line 3,494 ⟶ 6,517:
printline you could have done it by doing -c-
stoptask
goto :b</langsyntaxhighlight>
 
{{out}}
Line 3,515 ⟶ 6,538:
rdiv/2 is use instead of //2 to enable the program to solve difficult cases as [3 3 8 8].
 
<langsyntaxhighlight Prologlang="prolog">play24(Len, Range, Goal) :-
game(Len, Range, Goal, L, S),
maplist(my_write, L),
Line 3,605 ⟶ 6,628:
 
my_write(V) :-
format('~w ', [V]).</langsyntaxhighlight>
{{out}}
<pre>?- play24(4,9, 24).
Line 3,662 ⟶ 6,685:
</pre>
===Minimal version===
{{incorrect|Prolog|Does not follow 24 game rules for division: <quote>Division should use floating point or rational arithmetic, etc, to preserve remainders.</quote>}}
{{Works with|GNU Prolog|1.4.4}}
Little efforts to remove dublicatesduplicates (e.g. output for [4,6,9,9]).
<langsyntaxhighlight lang="prolog">:- initialization(main).
 
solve(N,Xs,Ast) :-
Line 3,685 ⟶ 6,709:
 
test(T) :- solve(24, [2,3,8,9], T).
main :- forall(test(T), (write(T), nl)), halt.</langsyntaxhighlight>
{{Output}}
<pre>(9-3)*8//2
Line 3,702 ⟶ 6,726:
 
=={{header|Python}}==
==={{header|Python}} Original===
The function is called '''solve''', and is integrated into the game player.
The docstring of the solve function shows examples of its use when isolated at the Python command line.
<syntaxhighlight lang="python">'''
<lang Python>'''
The 24 Game Player
Line 3,862 ⟶ 6,887:
print ("Thank you and goodbye")
main()</langsyntaxhighlight>
 
{{out}}
Line 3,887 ⟶ 6,912:
Thank you and goodbye</pre>
 
====Difficult case requiring precise division====
 
The digits 3,3,8 and 8 have a solution that is not equal to 24 when using Pythons double-precision floating point because of a division in all answers.
Line 3,913 ⟶ 6,938:
Expression 1: ?
Solution found: 8 / ( 3 - 8 / 3 )</pre>
 
==={{header|Python}} Succinct===
Based on the Julia example above.
<syntaxhighlight lang="python"># -*- coding: utf-8 -*-
import operator
from itertools import product, permutations
 
def mydiv(n, d):
return n / d if d != 0 else 9999999
 
syms = [operator.add, operator.sub, operator.mul, mydiv]
op = {sym: ch for sym, ch in zip(syms, '+-*/')}
 
def solve24(nums):
for x, y, z in product(syms, repeat=3):
for a, b, c, d in permutations(nums):
if round(x(y(a,b),z(c,d)),5) == 24:
return f"({a} {op[y]} {b}) {op[x]} ({c} {op[z]} {d})"
elif round(x(a,y(b,z(c,d))),5) == 24:
return f"{a} {op[x]} ({b} {op[y]} ({c} {op[z]} {d}))"
elif round(x(y(z(c,d),b),a),5) == 24:
return f"(({c} {op[z]} {d}) {op[y]} {b}) {op[x]} {a}"
elif round(x(y(b,z(c,d)),a),5) == 24:
return f"({b} {op[y]} ({c} {op[z]} {d})) {op[x]} {a}"
return '--Not Found--'
 
if __name__ == '__main__':
#nums = eval(input('Four integers in the range 1:9 inclusive, separated by commas: '))
for nums in [
[9,4,4,5],
[1,7,2,7],
[5,7,5,4],
[1,4,6,6],
[2,3,7,3],
[8,7,9,7],
[1,6,2,6],
[7,9,4,1],
[6,4,2,2],
[5,7,9,7],
[3,3,8,8], # Difficult case requiring precise division
]:
print(f"solve24({nums}) -> {solve24(nums)}")</syntaxhighlight>
 
{{out}}
<pre>solve24([9, 4, 4, 5]) -> --Not Found--
solve24([1, 7, 2, 7]) -> ((7 * 7) - 1) / 2
solve24([5, 7, 5, 4]) -> 4 * (7 - (5 / 5))
solve24([1, 4, 6, 6]) -> 6 + (6 * (4 - 1))
solve24([2, 3, 7, 3]) -> ((2 + 7) * 3) - 3
solve24([8, 7, 9, 7]) -> --Not Found--
solve24([1, 6, 2, 6]) -> 6 + (6 * (1 + 2))
solve24([7, 9, 4, 1]) -> (7 - 4) * (9 - 1)
solve24([6, 4, 2, 2]) -> (2 - 2) + (6 * 4)
solve24([5, 7, 9, 7]) -> (5 + 7) * (9 - 7)
solve24([3, 3, 8, 8]) -> 8 / (3 - (8 / 3))</pre>
 
==={{header|Python}} Recursive ===
This works for any amount of numbers by recursively picking two and merging them using all available operands until there is only one value left.
<syntaxhighlight lang="python"># -*- coding: utf-8 -*-
# Python 3
from operator import mul, sub, add
 
 
def div(a, b):
if b == 0:
return 999999.0
return a / b
 
ops = {mul: '*', div: '/', sub: '-', add: '+'}
 
def solve24(num, how, target):
if len(num) == 1:
if round(num[0], 5) == round(target, 5):
yield str(how[0]).replace(',', '').replace("'", '')
else:
for i, n1 in enumerate(num):
for j, n2 in enumerate(num):
if i != j:
for op in ops:
new_num = [n for k, n in enumerate(num) if k != i and k != j] + [op(n1, n2)]
new_how = [h for k, h in enumerate(how) if k != i and k != j] + [(how[i], ops[op], how[j])]
yield from solve24(new_num, new_how, target)
 
tests = [
[1, 7, 2, 7],
[5, 7, 5, 4],
[1, 4, 6, 6],
[2, 3, 7, 3],
[1, 6, 2, 6],
[7, 9, 4, 1],
[6, 4, 2, 2],
[5, 7, 9, 7],
[3, 3, 8, 8], # Difficult case requiring precise division
[8, 7, 9, 7], # No solution
[9, 4, 4, 5], # No solution
]
for nums in tests:
print(nums, end=' : ')
try:
print(next(solve24(nums, nums, 24)))
except StopIteration:
print("No solution found")
</syntaxhighlight>
 
{{out}}
<pre>[1, 7, 2, 7] : (((7 * 7) - 1) / 2)
[5, 7, 5, 4] : (4 * (7 - (5 / 5)))
[1, 4, 6, 6] : (6 - (6 * (1 - 4)))
[2, 3, 7, 3] : ((2 * 3) * (7 - 3))
[1, 6, 2, 6] : ((1 * 6) * (6 - 2))
[7, 9, 4, 1] : ((7 - 4) * (9 - 1))
[6, 4, 2, 2] : ((6 * 4) * (2 / 2))
[5, 7, 9, 7] : ((5 + 7) * (9 - 7))
[3, 3, 8, 8] : (8 / (3 - (8 / 3)))
[8, 7, 9, 7] : No solution found
[9, 4, 4, 5] : No solution found</pre>
 
===Python: using tkinter===
 
<syntaxhighlight lang="python">
''' Python 3.6.5 code using Tkinter graphical user interface.
Combination of '24 game' and '24 game/Solve'
allowing user or random selection of 4-digit number
and user or computer solution.
Note that all computer solutions are displayed'''
 
from tkinter import *
from tkinter import messagebox
from tkinter.scrolledtext import ScrolledText
# 'from tkinter import scrolledtext' in later versions?
import random
import itertools
 
# ************************************************
 
class Game:
def __init__(self, gw):
self.window = gw
self.digits = '0000'
 
a1 = "(Enter '4 Digits' & click 'My Digits'"
a2 = "or click 'Random Digits')"
self.msga = a1 + '\n' + a2
 
b1 = "(Enter 'Solution' & click 'Check Solution'"
b2 = "or click 'Show Solutions')"
self.msgb = b1 + '\n' + b2
 
# top frame:
self.top_fr = Frame(gw,
width=600,
height=100,
bg='dodger blue')
self.top_fr.pack(fill=X)
 
self.hdg = Label(self.top_fr,
text=' 24 Game ',
font='arial 22 bold',
fg='navy',
bg='lemon chiffon')
self.hdg.place(relx=0.5, rely=0.5,
anchor=CENTER)
 
self.close_btn = Button(self.top_fr,
text='Quit',
bd=5,
bg='navy',
fg='lemon chiffon',
font='arial 12 bold',
command=self.close_window)
self.close_btn.place(relx=0.07, rely=0.5,
anchor=W)
 
self.clear_btn = Button(self.top_fr,
text='Clear',
bd=5,
bg='navy',
fg='lemon chiffon',
font='arial 12 bold',
command=self.clear_screen)
self.clear_btn.place(relx=0.92, rely=0.5,
anchor=E)
 
# bottom frame:
self.btm_fr = Frame(gw,
width=600,
height=500,
bg='lemon chiffon')
self.btm_fr.pack(fill=X)
self.msg = Label(self.btm_fr,
text=self.msga,
font='arial 16 bold',
fg='navy',
bg='lemon chiffon')
self.msg.place(relx=0.5, rely=0.1,
anchor=CENTER)
 
self.user_dgt_btn = Button(self.btm_fr,
text='My Digits',
width=12,
bd=5,
bg='navy',
fg='lemon chiffon',
font='arial 12 bold',
command=self.get_digits)
self.user_dgt_btn.place(relx=0.07, rely=0.2,
anchor=W)
 
self.rdm_dgt_btn = Button(self.btm_fr,
text='Random Digits',
width=12,
bd=5,
bg='navy',
fg='lemon chiffon',
font='arial 12 bold',
command=self.gen_digits)
self.rdm_dgt_btn.place(relx=0.92, rely=0.2,
anchor=E)
 
self.dgt_fr = LabelFrame(self.btm_fr,
text=' 4 Digits ',
bg='dodger blue',
fg='navy',
bd=4,
relief=RIDGE,
font='arial 12 bold')
self.dgt_fr.place(relx=0.5, rely=0.27,
anchor=CENTER)
 
self.digit_ent = Entry(self.dgt_fr,
justify='center',
font='arial 16 bold',
fg='navy',
disabledforeground='navy',
bg='lemon chiffon',
disabledbackground='lemon chiffon',
bd=4,
width=6)
self.digit_ent.grid(row=0, column=0,
padx=(8,8),
pady=(8,8))
self.chk_soln_btn = Button(self.btm_fr,
text='Check Solution',
state='disabled',
width=14,
bd=5,
bg='navy',
fg='lemon chiffon',
font='arial 12 bold',
command=self.check_soln)
self.chk_soln_btn.place(relx=0.07, rely=.42,
anchor=W)
 
self.show_soln_btn = Button(self.btm_fr,
text='Show Solutions',
state='disabled',
width=14,
bd=5,
bg='navy',
fg='lemon chiffon',
font='arial 12 bold',
command=self.show_soln)
self.show_soln_btn.place(relx=0.92, rely=.42,
anchor=E)
 
self.soln_fr = LabelFrame(self.btm_fr,
text=' Solution ',
bg='dodger blue',
fg='navy',
bd=4,
relief=RIDGE,
font='arial 12 bold')
self.soln_fr.place(relx=0.07, rely=0.58,
anchor=W)
 
self.soln_ent = Entry(self.soln_fr,
justify='center',
font='arial 16 bold',
fg='navy',
disabledforeground='navy',
bg='lemon chiffon',
disabledbackground='lemon chiffon',
state='disabled',
bd=4,
width=15)
self.soln_ent.grid(row=0, column=0,
padx=(8,8), pady=(8,8))
 
self.solns_fr = LabelFrame(self.btm_fr,
text=' Solutions ',
bg='dodger blue',
fg='navy',
bd=4,
relief=RIDGE,
font='arial 12 bold')
self.solns_fr.place(relx=0.92, rely=0.5,
anchor='ne')
 
self.solns_all = ScrolledText(self.solns_fr,
font='courier 14 bold',
state='disabled',
fg='navy',
bg='lemon chiffon',
height=8,
width=14)
self.solns_all.grid(row=0, column=0,
padx=(8,8), pady=(8,8))
 
# validate '4 Digits' entry.
# save if valid and switch screen to solution mode.
def get_digits(self):
txt = self.digit_ent.get()
if not(len(txt) == 4 and txt.isdigit()):
self.err_msg('Please enter 4 digits (eg 1357)')
return
self.digits = txt # save
self.reset_one() # to solution mode
return
 
# generate 4 random digits, display them,
# save them, and switch screen to solution mode.
def gen_digits(self):
self.digit_ent.delete(0, 'end')
self.digits = ''.join([random.choice('123456789')
for i in range(4)])
self.digit_ent.insert(0, self.digits) # display
self.reset_one() # to solution mode
return
 
# switch screen from get digits to solution mode:
def reset_one(self):
self.digit_ent.config(state='disabled')
self.user_dgt_btn.config(state='disabled')
self.rdm_dgt_btn.config(state='disabled')
self.msg.config(text=self.msgb)
self.chk_soln_btn.config(state='normal')
self.show_soln_btn.config(state='normal')
self.soln_ent.config(state='normal')
return
 
# edit user's solution:
def check_soln(self):
txt = self.soln_ent.get() # user's expression
d = '' # save digits in expression
dgt_op = 'd' # expecting d:digit or o:operation
for t in txt:
if t not in '123456789+-*/() ':
self.err_msg('Invalid character found: ' + t)
return
if t.isdigit():
if dgt_op == 'd':
d += t
dgt_op = 'o'
else:
self.err_msg('Need operator between digits')
return
if t in '+-*/':
if dgt_op == 'o':
dgt_op = 'd'
else:
self.err_msg('Need digit befor operator')
return
if sorted(d) != sorted(self.digits):
self.err_msg("Use each digit in '4 Digits' once")
return
try:
# round covers up Python's
# representation of floats
if round(eval(txt),5) == 24:
messagebox.showinfo(
'Success',
'YOUR SOLUTION IS VADLID!')
self.show_soln() # show all solutions
return
except:
self.err_msg('Invalid arithmetic expression')
return
messagebox.showinfo(
'Failure',
'Your expression does not yield 24')
return
 
# show all solutions:
def show_soln(self):
# get all sets of 3 operands: ('+', '+', '*'), ...)
ops = ['+-*/', '+-*/', '+-*/']
combs = [p for p in itertools.product(*ops)]
# get unique permutations for requested 4 digits:
d = self.digits
perms = set([''.join(p) for p in itertools.permutations(d)])
 
# list of all (hopefully) expressions for
# 4 operands and 3 operations:
formats = ['Aop1Bop2Cop3D',
'(Aop1Bop2C)op3D',
'((Aop1B)op2C)op3D',
'(Aop1(Bop2C))op3D',
'Aop1Bop2(Cop3D)',
'Aop1(Bop2C)op3D',
'(Aop1B)op2Cop3D',
'(Aop1B)op2(Cop3D)',
'Aop1(Bop2Cop3D)',
'Aop1((Bop2C)op3D)',
'Aop1(Bop2(Cop3D))']
 
lox = [] # list of valid expressions
for fm in formats: # pick a format
for c in combs: # plug in 3 ops
f = fm.replace('op1', c[0])
f = f.replace('op2', c[1])
f = f.replace('op3', c[2])
for A, B, C, D in perms: # plug in 4 digits
x = f.replace('A', A)
x = x.replace('B', B)
x = x.replace('C', C)
x = x.replace('D', D)
try: # evaluate expression
# round covers up Python's
# representation of floats
if round(eval(x),5) == 24:
lox.append(' ' + x)
except ZeroDivisionError: # can ignore these
continue
if lox:
txt = '\n'.join(x for x in lox)
else:
txt =' No Solution'
self.solns_all.config(state='normal')
self.solns_all.insert('end', txt) # show solutions
self.solns_all.config(state='disabled')
 
self.chk_soln_btn.config(state='disabled')
self.show_soln_btn.config(state='disabled')
self.soln_ent.config(state='disabled')
return
 
def err_msg(self, msg):
messagebox.showerror('Error Message', msg)
return
 
# restore screen to it's 'initial' state:
def clear_screen(self):
self.digits = ''
self.digit_ent.config(state='normal')
self.user_dgt_btn.config(state='normal')
self.rdm_dgt_btn.config(state='normal')
self.digit_ent.delete(0, 'end')
self.chk_soln_btn.config(state='disabled')
self.show_soln_btn.config(state='disabled')
self.soln_ent.config(state='normal')
self.soln_ent.delete(0, 'end')
self.soln_ent.config(state='disabled')
self.msg.config(text=self.msga)
self.clear_solns_all()
return
 
# clear the 'Solutions' frame.
# note: state must be 'normal' to change data
def clear_solns_all(self):
self.solns_all.config(state='normal')
self.solns_all.delete(1.0, 'end')
self.solns_all.config(state='disabled')
return
def close_window(self):
self.window.destroy()
 
# ************************************************
 
root = Tk()
root.title('24 Game')
root.geometry('600x600+100+50')
root.resizable(False, False)
g = Game(root)
root.mainloop()
</syntaxhighlight>
 
=={{header|Quackery}}==
 
<code>permutations</code> is defined at [[Permutations#Quackery]] and <code>uniquewith</code> is defined at [[Remove duplicate elements#Quackery]].
 
<syntaxhighlight lang="quackery"> [ ' [ 0 1 2 3 ]
permutations ] constant is numorders ( --> [ )
 
[ []
4 3 ** times
[ [] i^
3 times
[ 4 /mod 4 +
rot join swap ]
drop
nested join ] ] constant is oporders ( --> [ )
 
[ [] numorders witheach
[ oporders witheach
[ dip dup join nested
rot swap join swap ]
drop ] ] constant is allorders ( --> [ )
 
[ [] unrot witheach
[ dip dup peek
swap dip [ nested join ] ]
drop ] is reorder ( [ [ --> [ )
 
[ ' [ [ 0 1 4 2 5 3 6 ]
[ 0 1 4 2 3 5 6 ]
[ 0 1 2 4 3 5 6 ] ]
witheach
[ dip dup reorder swap ]
4 pack ] is orderings ( [ --> [ )
 
[ witheach
[ dup number? iff n->v done
dup ' + = iff
[ drop v+ ] done
dup ' - = iff
[ drop v- ] done
' * = iff v* done
v/ ]
24 n->v v- v0= ] is 24= ( [ --> b )
 
[ 4 pack sort
[] swap
' [ + - * / ] join
allorders witheach
[ dip dup reorder orderings
witheach
[ dup 24= iff
[ rot swap
nested join swap ]
else drop ] ]
drop
uniquewith
[ dip unbuild unbuild $> ]
dup size
dup 0 = iff
[ 2drop say "No solutions." ]
done
dup 1 = iff
[ drop say "1 solution." ]
else
[ echo say " solutions." ]
unbuild
2 split nip
-2 split drop nest$ 90 wrap$ ] is solve ( n n n n --> )</syntaxhighlight>
 
{{out}}
 
As a dialogue in the Quackery shell.
 
<pre>/O> 8 8 3 3 solve
...
1 solution.
[ 8 3 8 3 / - / ]
Stack empty.
 
/O> 7 7 9 4 solve
...
No solutions.
Stack empty.
 
/O> 8 7 6 5 solve
...
22 solutions.
[ 5 7 + 8 6 - * ] [ 5 7 + 8 - 6 * ] [ 5 8 - 7 + 6 * ] [ 6 5 7 8 - + * ] [ 6 5 7 + 8 - * ]
[ 6 5 8 7 - - * ] [ 6 5 8 - 7 + * ] [ 6 7 5 8 - + * ] [ 6 7 5 + 8 - * ] [ 6 7 5 - 8 / / ]
[ 6 7 8 5 - - * ] [ 6 7 8 - 5 + * ] [ 6 8 7 5 - / * ] [ 6 8 * 7 5 - / ] [ 7 5 + 8 6 - * ]
[ 7 5 + 8 - 6 * ] [ 7 8 - 5 + 6 * ] [ 8 6 7 5 - / * ] [ 8 6 - 5 7 + * ] [ 8 6 - 7 5 + * ]
[ 8 6 * 7 5 - / ] [ 8 7 5 - 6 / / ]
Stack empty.
</pre>
 
=={{header|R}}==
This uses exhaustive search and makes use of R's ability to work with expressions as data. It is in principle general for any set of operands and binary operators.
<syntaxhighlight lang="r">
<lang r>
library(gtools)
 
Line 3,951 ⟶ 7,551:
return(NA)
}
</syntaxhighlight>
</lang>
{{out}}
<syntaxhighlight lang="r">
<lang r>
> solve24()
8 * (4 - 2 + 1)
Line 3,966 ⟶ 7,566:
> solve24(ops=c('-', '/')) #restricted set of operators
(8 - 2)/(1/4)
</syntaxhighlight>
</lang>
 
=={{header|Racket}}==
The sequence of all possible variants of expressions with given numbers ''n1, n2, n3, n4'' and operations ''o1, o2, o3''.
<langsyntaxhighlight lang="racket">
(define (in-variants n1 o1 n2 o2 n3 o3 n4)
(let ([o1n (object-name o1)]
Line 3,987 ⟶ 7,587:
`(,n1 ,o1n ((,n2 ,o3n ,n3) ,o2n ,n4))
`(,n1 ,o1n (,n2 ,o2n (,n3 ,o3n ,n4))))))))
</syntaxhighlight>
</lang>
 
Search for all solutions using brute force:
<langsyntaxhighlight lang="racket">
(define (find-solutions numbers (goal 24))
(define in-operations (list + - * /))
Line 4,006 ⟶ 7,606:
 
(define (remove-from numbers . n) (foldr remq numbers n))
</syntaxhighlight>
</lang>
 
Examples:
Line 4,028 ⟶ 7,628:
 
In order to find just one solution effectively one needs to change <tt>for*/list</tt> to <tt>for*/first</tt> in the function <tt>find-solutions</tt>.
 
=={{header|Raku}}==
(formerly Perl 6)
 
===With EVAL===
A loose translation of the Perl entry. Does not return every possible permutation of the possible solutions. Filters out duplicates (from repeated digits) and only reports the solution for a particular order of digits and operators with the fewest parenthesis (avoids reporting duplicate solutions only differing by unnecessary parenthesis). Does not guarantee the order in which results are returned.
 
Since Raku uses Rational numbers for division (whenever possible) there is no loss of precision as is common with floating point division. So a comparison like (1 + 7) / (1 / 3) == 24 "Just Works"<sup>&trade;</sup>
 
<syntaxhighlight lang="raku" line>use MONKEY-SEE-NO-EVAL;
 
my @digits;
my $amount = 4;
 
# Get $amount digits from the user,
# ask for more if they don't supply enough
while @digits.elems < $amount {
@digits.append: (prompt "Enter {$amount - @digits} digits from 1 to 9, "
~ '(repeats allowed): ').comb(/<[1..9]>/);
}
# Throw away any extras
@digits = @digits[^$amount];
 
# Generate combinations of operators
my @ops = [X,] <+ - * /> xx 3;
 
# Enough sprintf formats to cover most precedence orderings
my @formats = (
'%d %s %d %s %d %s %d',
'(%d %s %d) %s %d %s %d',
'(%d %s %d %s %d) %s %d',
'((%d %s %d) %s %d) %s %d',
'(%d %s %d) %s (%d %s %d)',
'%d %s (%d %s %d %s %d)',
'%d %s (%d %s (%d %s %d))',
);
 
# Brute force test the different permutations
@digits.permutations».join.unique».comb.race.map: -> @p {
for @ops -> @o {
for @formats -> $format {
my $result = .EVAL given my $string = sprintf $format, roundrobin(@p, @o, :slip);
say "$string = 24" and last if $result and $result == 24;
}
}
}</syntaxhighlight>
{{out}}
<pre>
Enter 4 digits from 1 to 9, (repeats allowed): 3711
(1 + 7) * 3 * 1 = 24
(1 + 7) * 3 / 1 = 24
(1 * 3) * (1 + 7) = 24
3 * (1 + 1 * 7) = 24
(3 * 1) * (1 + 7) = 24
3 * (1 / 1 + 7) = 24
(3 / 1) * (1 + 7) = 24
3 / (1 / (1 + 7)) = 24
(1 + 7) * 1 * 3 = 24
(1 + 7) / 1 * 3 = 24
(1 + 7) / (1 / 3) = 24
(1 * 7 + 1) * 3 = 24
(7 + 1) * 3 * 1 = 24
(7 + 1) * 3 / 1 = 24
(7 - 1) * (3 + 1) = 24
(1 + 1 * 7) * 3 = 24
(1 * 1 + 7) * 3 = 24
(1 / 1 + 7) * 3 = 24
(3 + 1) * (7 - 1) = 24
3 * (1 + 7 * 1) = 24
3 * (1 + 7 / 1) = 24
(3 * 1) * (7 + 1) = 24
(3 / 1) * (7 + 1) = 24
3 / (1 / (7 + 1)) = 24
(1 + 3) * (7 - 1) = 24
(1 * 3) * (7 + 1) = 24
(7 + 1) * 1 * 3 = 24
(7 + 1) / 1 * 3 = 24
(7 + 1) / (1 / 3) = 24
(7 - 1) * (1 + 3) = 24
(7 * 1 + 1) * 3 = 24
(7 / 1 + 1) * 3 = 24
3 * (7 + 1 * 1) = 24
3 * (7 + 1 / 1) = 24
3 * (7 * 1 + 1) = 24
3 * (7 / 1 + 1) = 24
 
Enter 4 digits from 1 to 9, (repeats allowed): 5 5 5 5
5 * 5 - 5 / 5 = 24
 
Enter 4 digits from 1 to 9, (repeats allowed): 8833
8 / (3 - 8 / 3) = 24
</pre>
 
===No EVAL===
Alternately, a version that doesn't use EVAL. More general case. Able to handle 3 or 4 integers, able to select the goal value.
 
<syntaxhighlight lang="raku" line>my %*SUB-MAIN-OPTS = :named-anywhere;
 
sub MAIN (*@parameters, Int :$goal = 24) {
my @numbers;
if +@parameters == 1 {
@numbers = @parameters[0].comb(/\d/);
USAGE() and exit unless 2 < @numbers < 5;
} elsif +@parameters > 4 {
USAGE() and exit;
} elsif +@parameters == 3|4 {
@numbers = @parameters;
USAGE() and exit if @numbers.any ~~ /<-[-\d]>/;
} else {
USAGE();
exit if +@parameters == 2;
@numbers = 3,3,8,8;
say 'Running demonstration with: ', |@numbers, "\n";
}
solve @numbers, $goal
}
 
sub solve (@numbers, $goal = 24) {
my @operators = < + - * / >;
my @ops = [X] @operators xx (@numbers - 1);
my @perms = @numbers.permutations.unique( :with(&[eqv]) );
my @order = (^(@numbers - 1)).permutations;
my @sol;
@sol[250]; # preallocate some stack space
 
my $batch = ceiling +@perms/4;
 
my atomicint $i;
@perms.race(:batch($batch)).map: -> @p {
for @ops -> @o {
for @order -> @r {
my $result = evaluate(@p, @o, @r);
@sol[$i⚛++] = $result[1] if $result[0] and $result[0] == $goal;
}
}
}
@sol.=unique;
say @sol.join: "\n";
my $pl = +@sol == 1 ?? '' !! 's';
my $sg = $pl ?? '' !! 's';
say +@sol, " equation{$pl} evaluate{$sg} to $goal using: {@numbers}";
}
 
sub evaluate ( @digit, @ops, @orders ) {
my @result = @digit.map: { [ $_, $_ ] };
my @offset = 0 xx +@orders;
 
for ^@orders {
my $this = @orders[$_];
my $order = $this - @offset[$this];
my $op = @ops[$this];
my $result = op( $op, @result[$order;0], @result[$order+1;0] );
return [ NaN, Str ] unless defined $result;
my $string = "({@result[$order;1]} $op {@result[$order+1;1]})";
@result.splice: $order, 2, [ $[ $result, $string ] ];
@offset[$_]++ if $order < $_ for ^@offset;
}
@result[0];
}
 
multi op ( '+', $m, $n ) { $m + $n }
multi op ( '-', $m, $n ) { $m - $n }
multi op ( '/', $m, $n ) { $n == 0 ?? fail() !! $m / $n }
multi op ( '*', $m, $n ) { $m * $n }
 
my $txt = "\e[0;96m";
my $cmd = "\e[0;92m> {$*EXECUTABLE-NAME} {$*PROGRAM-NAME}";
sub USAGE {
say qq:to
'========================================================================'
{$txt}Supply 3 or 4 integers on the command line, and optionally a value
to equate to.
 
Integers may be all one group: {$cmd} 2233{$txt}
Or, separated by spaces: {$cmd} 2 4 6 7{$txt}
 
If you wish to supply multi-digit or negative numbers, you must
separate them with spaces: {$cmd} -2 6 12{$txt}
 
If you wish to use a different equate value,
supply a new --goal parameter: {$cmd} --goal=17 2 -3 1 9{$txt}
 
If you don't supply any parameters, will use 24 as the goal, will run a
demo and will show this message.\e[0m
========================================================================
}</syntaxhighlight>
{{out}}
When supplied 1399 on the command line:
<pre>(((9 - 1) / 3) * 9)
((9 - 1) / (3 / 9))
((9 / 3) * (9 - 1))
(9 / (3 / (9 - 1)))
((9 * (9 - 1)) / 3)
(9 * ((9 - 1) / 3))
(((9 - 1) * 9) / 3)
((9 - 1) * (9 / 3))
8 equations evaluate to 24 using: 1 3 9 9</pre>
 
=={{header|REXX}}==
<langsyntaxhighlight lang="rexx">/*REXX program to helphelps the user find solutions to the game of 24. */
/* start-of-help
/* ┌──────────────────────────────────────────────────────────────────┐
┌───────────────────────────────────────────────────────────────────────┐
│ Argument is either of two forms: ssss ==or== ssss-ffff │
Argument is either of three forms: (blank)~
│ ssss │~
│ where one or both strings must be exactly four numerals (digits) │
│ ssss,tot │~
│ comprised soley of the numerals (digits) 1 ──> 9 (no zeroes). │
ssss-ffff~
In SSSS-FFFF SSSS is the start ssss-ffff,tot~
-ssss FFFF is the start.~
│ +ssss │~
└──────────────────────────────────────────────────────────────────┘ */
parse arg orig /*get the guess from the argument. */ │~
│ where SSSS and/or FFFF must be exactly four numerals (digits) │~
parse var orig start '-' finish /*get the start and finish (maybe). */
│ comprised soley of the numerals (digits) 1 ──> 9 (no zeroes). │~
start=space(start,0) /*remove any blanks from the START. */
│ │~
finish=space(finish,0) /*remove any blanks from the FINISH. */
│ SSSS is the start, │~
finish=word(finish start,1) /*if no FINISH specified, use START.*/
digs=123456789 /*numerals (digits) that can be used FFFF is the start. */ │~
│ │~
call validate start
│ │~
call validate finish
│ If ssss has a leading plus (+) sign, it is used as the number, and │~
opers='+-*/' /*define the legal arithmetic operators*/
ops=length(opers)│ the user is prompted to find a solution. /* ... and the count of them (length). */│~
do j=1 for ops /*define a version for fast execution. */ │~
│ If ssss has a leading minus (-) sign, a solution is looked for and │~
o.j=substr(opers,j,1)
│ the user is told there is a solution (but no solutions are shown). │~
end /*j*/
finds=0 /*number of found solutions (so far). */ │~
│ If no argument is specified, this program finds a four digits (no │~
x.=0 /*a method to hold unique expressions. */
│ zeroes) which has at least one solution, and shows the digits to │~
indent=left('',30) /*used to indent display of solutions. */
the user, requesting that they enter a solution. /*alternative: indent=copies(' ',30) */│~
Lpar='(' /*a string to make REXX code prettier. */ │~
│ If tot is entered, it is the desired answer. The default is 24. │~
Rpar=')' /*ditto. */
│ │~
│ A solution to be entered can be in the form of: │
│ │
│ digit1 operator digit2 operator digit3 operator digit4 │
│ │
│ where DIGITn is one of the digits shown (in any order), and │
│ OPERATOR can be any one of: + - * / │
│ │
│ Parentheses () may be used in the normal manner for grouping, as │
│ well as brackets [] or braces {}. Blanks can be used anywhere. │
│ │
│ I.E.: for the digits 3448 the following could be entered. │
│ │
│ 3*8 + (4-4) │
└───────────────────────────────────────────────────────────────────────┘
end-of-help */
numeric digits 12 /*where rational arithmetic is needed. */
parse arg orig /*get the guess from the command line*/
orig= space(orig, 0) /*remove all blanks from ORIG. */
negatory= left(orig,1)=='-' /*=1, suppresses showing. */
pository= left(orig,1)=='+' /*=1, force $24 to use specific number.*/
if pository | negatory then orig=substr(orig,2) /*now, just use the absolute vaue. */
parse var orig orig ',' ?? /*get ?? (if specified, def=24). */
parse var orig start '-' finish /*get start and finish (maybe). */
opers= '*' || "/+-" /*legal arith. opers;order is important*/
ops= length(opers) /*the number of arithmetic operators. */
groupsym= '()[]{}' /*allowed grouping symbols. */
indent= left('', 30) /*indents display of solutions. */
show= 1 /*=1, shows solutions (semifore). */
digs= 123456789 /*numerals/digs that can be used. */
abuttals = 0 /*=1, allows digit abutal: 12+12 */
if ??=='' then ??= 24 /*the name of the game. */
??= ?? / 1 /*normalize the answer. */
@abc= 'abcdefghijklmnopqrstuvwxyz' /*the Latin alphabet in order. */
@abcu= @abc; upper @abcu /*an uppercase version of @abc. */
x.= 0 /*method used to not re-interpret. */
do j=1 for ops; o.j=substr(opers, j, 1)
end /*j*/ /*used for fast execution. */
y= ??
if \datatype(??,'N') then do; call ger "isn't numeric"; exit 13; end
if start\=='' & \pository then do; call ranger start,finish; exit 13; end
show= 0 /*stop SOLVE blabbing solutions. */
do forever while \negatory /*keep truckin' until a solution. */
x.= 0 /*way to hold unique expressions. */
rrrr= random(1111, 9999) /*get a random set of digits. */
if pos(0, rrrr)\==0 then iterate /*but don't the use of zeroes. */
if solve(rrrr)\==0 then leave /*try to solve for these digits. */
end /*forever*/
 
if left(orig,1)=='+' dothen grrrr=start to finish /*processuse what's specified. a (possible) range of values.*/
show= 1 /*enable SOLVE to show solutions. */
if pos(0,g)\==0 then iterate /*ignore values with zero in them. */
rrrr= sortc(rrrr) /*sort four elements. */
rd.= 0
do j=1 for 9 /*count for each digit in RRRR. */
_= substr(rrrr, j, 1); rd._= countchars(rrrr, _)
end
do guesses=1; say
say 'Using the digits' rrrr", enter an expression that equals" ?? ' (? or QUIT):'
pull y; y= space(y, 0)
if countchars(y, @abcu)>2 then exit /*the user must be desperate. */
helpstart= 0
if y=='?' then do j=1 for sourceline() /*use a lazy way to show help. */
_= sourceline(j)
if p(_)=='start-of-help' then do; helpstart=1; iterate; end
if p(_)=='end-of-help' then iterate guesses
if \helpstart then iterate
if right(_,1)=='~' then iterate
say ' ' _
end
 
_v= verify(y, digs || opers || groupsym) do _=1 for 4 /*any illegal characters? /*define versions for faster execution.*/
if _v\==0 then do; call ger 'invalid character:' g._=substr(gy,_ _v, 1); iterate; end
if y='' then do; end call validate /*_*/y; iterate; end
 
do ij=1 for length(y)-1 forwhile ops\abuttals /*check for two digits adjacent. /*insert an operator after 1st number. */
if \datatype(substr(y,j,1), 'W') then iterate
do j=1 for ops /*insert an operator after 2nd number. */
if datatype(substr(y,j+1,1),'W') then do
do k=1 for ops /*insert an operator after 2nd number. */
do m=0 to 3; L.= /*assume no left parenthesis so far. */ call ger 'invalid use of digit abuttal' substr(y,j,2)
do n=m+1 to 4 /*match left paren with a right paren. */ iterate guesses
L.m=Lpar /*define a left paren, m=0 means ignore*/ end
end /*j*/
R.="" /*un-define all right parenthesis. */
if m==1 & n==2 then L.="" /*special case: (n)+ ... */
else if m\==0 then R.n=Rpar /*no (, no )*/
e= L.1 g.1 o.i L.2 g.2 o.j L.3 g.3 R.3 o.k g.4 R.4
e=space(e,0) /*remove all blanks from the expression*/
 
yd= countchars(y, digs) /*(below) change expression: count of legal digits 123456789 */
if yd<4 then do; call ger 'not enough digits entered.'; iterate guesses; end
/* /(yyy) ===> /div(yyy) */
if yd>4 then do; call ger 'too many digits entered.' ; iterate guesses; end
/*Enables to check for division by zero*/
origE=e /*keep old version for the display. */
if pos('/(',e)\==0 then e=changestr('/(',e,"/div(")
/*The above could be replaced by: */
/* e=changestr('/(',e,"/div(") */
 
do j=1 for length(groupsym) by 2
/*INTERPRET stresses REXX's groin, so */
if countchars(y,substr(groupsym,j ,1))\==,
/* try to avoid repeated heavy lifting.*/
countchars(y,substr(groupsym,j+1,1)) then do
if x.e then iterate /*was the expression already used? */
x.e=1 /*mark this expression as unique. */ call ger 'mismatched' substr(groupsym,j,2)
/*have REXX do the heavy lifting (ugh).*/ iterate guesses
interpret 'x=' e /*... strain... */ end
end /*j*/
x=x/1 /*remove trailing decimal points(maybe)*/
 
if x\==24 then iterate /*Not correct? Try again. */
do k=1 for 2 finds=finds+1 /*bumpcheck for ** and // number of found solutions. */
_= copies( substr( _=translate(origEopers, ']['k, "1)(") /*show [], not (2). */
if pos(_, y)\==0 saythen indentdo; call ger 'aillegal solutionoperator:' _; iterate guesses; /*display a solution. */end
end /*nk*/
 
do j=1 for 9; if rd.j==0 then iterate; _d= countchars(y, j)
if _d==rd.j then iterate
if _d<rd.j then call ger 'not enough' j "digits, must be" rd.j
else call ger 'too many' j "digits, must be" rd.j
iterate guesses
end /*j*/
 
y= translate(y, '()()', "[]{}")
interpret 'ans=(' y ") / 1"
if ans==?? then leave guesses
say right('incorrect, ' y'='ans, 50)
end /*guesses*/
 
say; say center('┌─────────────────────┐', 79)
say center('│ │', 79)
say center('│ congratulations ! │', 79)
say center('│ │', 79)
say center('└─────────────────────┘', 79)
say
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
countchars: procedure; arg x,c /*count of characters in X. */
return length(x) - length( space( translate(x, ,c ), 0) )
/*──────────────────────────────────────────────────────────────────────────────────────*/
ranger: parse arg ssss,ffff /*parse args passed to this sub. */
ffff= p(ffff ssss) /*create a FFFF if necessary. */
do g=ssss to ffff /*process possible range of values. */
if pos(0, g)\==0 then iterate /*ignore any G with zeroes. */
sols= solve(g); wols= sols
if sols==0 then wols= 'No' /*un-geek number of solutions (if any).*/
if negatory & sols\==0 then wols='A' /*found only the first solution? */
say
say wols 'solution's(sols) "found for" g
if ??\==24 then say 'for answers that equal' ??
end
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
solve: parse arg qqqq; finds= 0 /*parse args passed to this sub. */
if \validate(qqqq) then return -1
parse value '( (( )) )' with L LL RR R /*assign some static variables. */
nq.= 0
do jq=1 for 4; _= substr(qqqq,jq,1) /*count the number of each digit. */
nq._= nq._ + 1
end /*jq*/
 
do gggg=1111 to 9999
if pos(0, gggg)\==0 then iterate /*ignore values with zeroes. */
if verify(gggg, qqqq)\==0 then iterate
if verify(qqqq, gggg)\==0 then iterate
ng.= 0
do jg=1 for 4; _= substr(gggg, jg, 1) /*count the number of each digit. */
g.jg= _; ng._= ng._ + 1
end /*jg*/
do kg=1 for 9 /*verify each number has same # digits.*/
if nq.kg\==ng.kg then iterate gggg
end /*kg*/
do i =1 for ops /*insert operator after 1st numeral. */
do j =1 for ops /* " " " 2nd " */
do k=1 for ops /* " " " 3rd " */
do m=0 for 10; !.= /*nullify all grouping symbols (parens)*/
select
when m==1 then do; !.1=L; !.3=R; end
when m==2 then do; !.1=L; !.5=R; end
when m==3 then do; !.1=L; !.3=R; !.4=L; !.6=R; end
when m==4 then do; !.1=L; !.2=L; !.6=RR; end
when m==5 then do; !.1=LL; !.5=R; !.6=R; end
when m==6 then do; !.2=L; !.5=R; end
when m==7 then do; !.2=L; !.6=R; end
when m==8 then do; !.2=L; !.4=L; !.6=RR; end
when m==9 then do; !.2=LL; !.5=R; !.6=R; end
otherwise nop
end /*select*/
 
e= space(!.1 g.1 o.i !.2 g.2 !.3 o.j !.4 g.3 !.5 o.k g.4 !.6, 0)
if x.e then iterate /*was the expression already used? */
x.e= 1 /*mark this expression as being used. */
/*(below) change the expression: /(yyy) ===> /div(yyy) */
origE= e /*keep original version for the display*/
pd= pos('/(', e) /*find pos of /( in E. */
if pd\==0 then do /*Found? Might have possible ÷ by zero*/
eo= e
lr= lastpos(')', e) /*find last right ) */
lm= pos('-', e, pd+1) /*find - after ( */
if lm>pd & lm<lr then e= changestr('/(',e,"/div(") /*change*/
if eo\==e then if x.e then iterate /*expression already used?*/
x.e= 1 /*mark this expression as being used. */
end
interpret 'x=(' e ") / 1" /*have REXX do the heavy lifting here. */
if x\==?? then do /*Not correct? Then try again. */
numeric digits 9; x= x / 1 /*re-do evaluation.*/
numeric digits 12 /*re-instate digits*/
if x\==?? then iterate /*Not correct? Then try again. */
end
finds= finds + 1 /*bump number of found solutions. */
if \show | negatory then return finds
_= translate(origE, '][', ")(") /*show [], not (). */
if show then say indent 'a solution for' g':' ??"=" _ /*show solution.*/
end /*m*/
end /*k*/
end /*j*/
end /*i*/
end /*ggggg*/
return finds
/*──────────────────────────────────────────────────────────────────────────────────────*/
sortc: procedure; arg nnnn; L= length(nnnn) /*sorts the chars NNNN */
do i=1 for L /*build array of digs from NNNN, */
a.i= substr(nnnn, i, 1) /*enabling SORT to sort an array. */
end /*i*/
 
do j=1 for L /*very simple sort, it's a small array*/
sols=finds
if sols==0 then sols='No' /*make the sentence not_= so geek-likea. */j
do k=j+1 to L
say; say sols 'unique solution's(finds) "found for" orig /*pluralize.*/
if a.k<_ then do; a.j= a.k; a.k= _; _= a.k; end
exit
end /*k*/
/*───────────────────────────DIV subroutine─────────────────────────────*/
div: procedure; parse arg q /*tests if dividing by 0 (zero). end /*j*/
v= a.1
if q=0 then q=1e9 /*if dividing by zero, change divisor. */
return q do m=2 to L; v= v || a.m /*changingbuild a string of digs from A.m Q invalidates the expression*/
end /*m*/
/*───────────────────────────GER subroutine─────────────────────────────*/
return v
ger: say; say '*** error! ***'; if _\=='' then say 'guess=' _
/*──────────────────────────────────────────────────────────────────────────────────────*/
say arg(1); say; exit 13
validate: parse arg y; errCode= 0; _v= verify(y, digs)
/*───────────────────────────S subroutine───────────────────────────────*/
s: if arg(1)==1 then return ''; return 's' /*simple pluralizer.*/ select
when y=='' then call ger 'no digits entered.'
/*───────────────────────────validate subroutine────────────────────────*/
when length(y)<4 then call ger 'not enough digits entered, must be 4'
validate: parse arg y; errCode=0; _v=verify(y,digs)
when length(y)>4 then call ger 'too many digits entered, must be 4'
select
when y=='' when pos(0,y)\==0 then call ger "can'not digitsuse entered.'the digit 0 (zero)"
when _v\==0 then call ger 'illegal character:' substr(y,_v,1)
when length(y)<4 then call ger 'not enough digits entered, must be 4'
otherwise nop
when length(y)>4 then call ger 'too many digits entered, must be 4'
end /*select*/
when pos(0,y)\==0 then call ger "can't use the digit 0 (zero)"
return \errCode
when _v\==0 then call ger 'illegal character:' substr(y,_v,1)
/*──────────────────────────────────────────────────────────────────────────────────────*/
otherwise nop
div: procedure; parse arg q; if q=0 then q=1e9; return q /*tests if dividing by zero.*/
end /*select*/
ger: say= '***error*** for argument:' y; say arg(1); errCode= 1; return 0
return \errCode</lang>
p: return word( arg(1), 1)
Some older REXXes don't have a '''changestr''' bif, so one is included here ──► [[CHANGESTR.REX]].
s: if arg(1)==1 then return arg(3); return word( arg(2) 's', 1)</syntaxhighlight>
Some older REXXes don't have a &nbsp; '''changestr''' &nbsp; BIF, so one is included here ──► &nbsp; &nbsp; [[CHANGESTR.REX]].
<br><br>
'''{{out|output'''|text=&nbsp; when using the following input is usedof: &nbsp; &nbsp; <tt> 11111156-12341162 </tt>}}
<pre style="height:30ex;overflow:scroll95ex">
a solution for 1156: 24= [1+1+*5-1]*86
a solution for 1156: 24= [[1+*5-1+2]*6]
a solution for 1156: [1+24= 1*2[5-1]*86
a solution for 1156: [24= 1*[[5-1+2]*86]
a solution for 1156: 24= [1*6]*[5-1+2]*8
a solution for 1156: 24= 1*[6*[5-1/1+2]*8]
a solution for 1156: 24= [5*1+-1*3]*6
a solution for 1156: 24= [1[5*1+3-1]*6]
a solution for 1156: 1*24= [5/1-1+3]*6
a solution for 1156: 24= [1[5/1+3-1]*6]
a solution for 1156: 124= [5-1+3]*1*86
a solution for 1156: 24= [15-1+3*1]*86
a solution for 1156: 24= [15-1+3]*[1*86]
a solution for 1156: 124= [[5-1+[3*81]*6]
a solution for 1156: 1-24= [15-3*81]/1*6
a solution for 1156: 24= [5-1*/1]*3*86
a solution for 1156: 24= [[5-1*/1*3]*86]
a solution for 1156: 24= [5-1*]/[1*3*8/6]
a solution for 1156: 1*24= [5-1*3]*86*1
a solution for 1156: 24= [5-1]*[16*3*81]
a solution for 1156: 24= [5-1]*6/1*[3*8]
a solution for 1156: 24= [5-1]*[6/1*3*8]
a solution for 1156: 24= 5*[6-1/1*3]*8-1
a solution for 1156: 24= [6*1/1]*3*8[5-1]
a solution for 1156: 1/124= [6*[31*85-1]]
a solution for 1156: 1/24= 6*[1/3]*85-1]
a solution for 1156: 24= 6*[1/*[5-1/3/8]]
a solution for 1156: 24= 6*[[1+*5]-1+4]*4
a solution for 1156: 24= [6/1]*[5-1+4*6]
a solution for 1156: 24= 6/[1/[5-1+4]*6]
a solution for 1156: 24= [16-1+4*6]*5-1
a solution for 1156: 24= [6*[5*1-1+[4*6]]
a solution for 1156: 1-24= 6*[5*1-4*61]
a solution for 1156: 124= 6*1[[5*4*61]-1]
a solution for 1156: 24= [16*[5/1-1*4]*6]
a solution for 1156: 24= 6*[5/1*-1*4*6]
a solution for 1156: 124= 6*[[5/1]-1*4]*6
a solution for 1156: 124= [6*[5-1*4*61]]
a solution for 1156: 1*124= 6*[4*65-1]*1
a solution for 1156: 1/24= 6*[5-1*4*61]
a solution for 1156: 24= 6*[5-[1/1*41]]*6
a solution for 1156: 24= 6*[[5-1/1]*4*61]
a solution for 1156: 24= [6*[5-1/1*[4*6]]
a solution for 1156: 1/24= 6*[5-1/4]*6/1
a solution for 1156: 1/24= 6*[5-1/4/61]
a solution for 1156: 24= 6*[5-[1+/1*5]*4]
a solution for 1156: 24= 6*[[5-1*]/1+5]*4
 
a solution: 1*[1+5]*4
47 solutions found for 1156
a solution: [1/1+5]*4
a solution for 1157: 24= [1+1+6]*3[5+7]
a solution for 1157: 1-24= [1+61]*4[7+5]
a solution for 1157: 24= [1-1+65]*4[1-7]
a solution for 1157: 24= [1-1+67]*4[1-5]
a solution for 1157: 124= [5-1+[6]*4[7-1]
a solution for 1157: 1-24= [1-65+7]*4[1+1]
a solution for 1157: 24= [7-1]*[5-1*6*4]
a solution for 1157: 24= [17+5]*[1+1*6]*4
 
a solution: [1*1*6*4]
8 solutions found for 1157
a solution: 1*[1*6]*4
a solution for 1158: 1*24= [5-1-1*6*4]*8
a solution for 1158: 24= [[5-1*-1]*[6*48]
a solution for 1158: 24= 8*[5-[1/+1*6*4]]
a solution for 1158: 24= [8*[5-1/-1*6]*4]
a solution for 1158: 24= 8*[5-1/-1*6*4]
a solution for 1158: 1/124= 8*[6*4[5-1]-1]
 
a solution: 1/[1/6]*4
6 solutions found for 1158
a solution: [1+1*7]*3
 
a solution: [1*1+7]*3
No solutions found for 1159
a solution: 1*[1+7]*3
 
a solution: [1/1+7]*3
No solutions found for 1161
a solution: 1-1+8*3
a solution for 1162: 24= [1-1+81]*32*6
a solution for 1162: 24= [1-1+81]*[2*36]
a solution for 1162: 24= [1-+1+[8*32]*6
a solution for 1162: 1-24= [[1+1-8+2]*36]
a solution for 1162: 24= [1*+1]*86*32
a solution for 1162: 24= [1*+1*8]*3[6*2]
a solution for 1162: 24= [1*+2+1*8*3]*6
a solution for 1162: 1*24= [[1*8+2+1]*36]
a solution for 1162: 124= 2*[1*8*3+1]*6
a solution for 1162: 1*124= 2*[8[1+1]*36]
a solution for 1162: 24= [2+1/+1]*8*36
a solution for 1162: 24= [[2+1/+1*8]*36]
a solution for 1162: 24= [1/12*86]*3[1+1]
a solution for 1162: 1/124= 2*[86*3[1+1]]
a solution for 1162: 1/24= 6*[1/8+1]*32
a solution for 1162: 1/24= 6*[[1+1/8/3]*2]
a solution for 1162: 24= [6*[1+2+1+2]]*6
a solution for 1162: 24= 6*[1+2*1+2]*8
a solution for 1162: 24= 6*[1+2/[1+2]]*8
a solution for 1162: 24= 6*[[1*2+1]*8+2]
a solution for 1162: 124= [6*[1+2+1]*8]
a solution for 1162: 24= 6*[1*2+2+1]*6
a solution for 1162: 124= 6*[21+[2+1]]*6
a solution for 1162: 124= 6*[[1+2*2*6]+1]
a solution for 1162: 24= [1*26*2]*6[1+1]
a solution for 1162: [124= 6*[2*2*6[1+1]]
a solution for 1162: 124= [6*[2*2+1+1]]*6
a solution for 1162: 124= 6*[2*2*6+1+1]
a solution for 1162: 1*224= 6*[2*6+[1+1]]
a solution for 1162: 24= 6*[[1+2+31]+1]*4
a solution: 1*2*3*4
a solution: [1*2*3]*4
a solution: [1*2*3*4]
a solution: 1*[2*3]*4
a solution: 1*[2*3*4]
a solution: 1*2*[3*4]
 
107 unique30 solutions found for 1111-12341162
</pre>
 
=={{header|Ruby}}==
{{trans|Tcl}}
{{works with|Ruby|2.1}}
<lang ruby>class TwentyFourGamePlayer
<syntaxhighlight lang="ruby">class TwentyFourGame
EXPRESSIONS = [
'((%ddr %s %ddr) %s %ddr) %s %ddr',
'(%ddr %s (%ddr %s %ddr)) %s %ddr',
'(%ddr %s %ddr) %s (%ddr %s %ddr)',
'%ddr %s ((%ddr %s %ddr) %s %ddr)',
'%ddr %s (%ddr %s (%ddr %s %ddr))',
]
].map{|expr| [expr, expr.gsub('%d', 'Rational(%d,1)')]}
OPERATORS = [:+, :-, :*, :/].repeated_permutation(3)
OPERATORS = [:+, :-, :*, :/].repeated_permutation(3).to_a
OBJECTIVE = Rational(24,1)
def self.solve(digits)
solutions = []
perms = digits.permutation.to_a.uniq.each do |a,b,c,d|
OPERATORSperms.eachproduct(OPERATORS, EXPRESSIONS) do |(a,b,c,d), (op1,op2,op3), expr|
# evaluate using rational arithmetic
EXPRESSIONS.each do |expr,expr_rat|
text = expr % #[a, evaluateop1, usingb, rationalop2, arithmeticc, op3, d]
value = eval(text) rescue next # catch division by zero
test = expr_rat % [a, op1, b, op2, c, op3, d]
solutions << text.delete("r") if value == 24
value = eval(test) rescue -1 # catch division by zero
if value == OBJECTIVE
solutions << expr % [a, op1, b, op2, c, op3, d]
end
end
end
end
solutions
Line 4,287 ⟶ 8,236:
digits.size == 4 or raise "error: need 4 digits, only have #{digits.size}"
 
solutions = TwentyFourGamePlayerTwentyFourGame.solve(digits)
if solutions.empty?
puts "no solutions"
Line 4,293 ⟶ 8,242:
puts "found #{solutions.size} solutions, including #{solutions.first}"
puts solutions.sort
end</langsyntaxhighlight>
 
{{out}}
Sample output:
<pre>$ ruby 24game.playergame24_solver.rb 1 1 1 1
no solutions
 
$ ruby 24game.playergame24_solver.rb 1 1 2 7
found 8 solutions, including (1 + 2) * (1 + 7)
(1 + 2) * (1 + 7)
Line 4,310 ⟶ 8,259:
(7 + 1) * (2 + 1)
 
$ ruby 24game.playergame24_solver.rb 2 3 8 9
found 12 solutions, including (8 / 2) * (9 - 3)
((9 - 3) * 8) / 2
Line 4,324 ⟶ 8,273:
8 * (9 - (3 * 2))
8 / (2 / (9 - 3))</pre>
 
=={{header|Rust}}==
{{works with|Rust|1.17}}
<syntaxhighlight lang="rust">#[derive(Clone, Copy, Debug)]
enum Operator {
Sub,
Plus,
Mul,
Div,
}
 
#[derive(Clone, Debug)]
struct Factor {
content: String,
value: i32,
}
 
fn apply(op: Operator, left: &[Factor], right: &[Factor]) -> Vec<Factor> {
let mut ret = Vec::new();
for l in left.iter() {
for r in right.iter() {
use Operator::*;
ret.push(match op {
Sub if l.value > r.value => Factor {
content: format!("({} - {})", l.content, r.content),
value: l.value - r.value,
},
Plus => Factor {
content: format!("({} + {})", l.content, r.content),
value: l.value + r.value,
},
Mul => Factor {
content: format!("({} x {})", l.content, r.content),
value: l.value * r.value,
},
Div if l.value >= r.value && r.value > 0 && l.value % r.value == 0 => Factor {
content: format!("({} / {})", l.content, r.content),
value: l.value / r.value,
},
_ => continue,
})
}
}
ret
}
 
fn calc(op: [Operator; 3], numbers: [i32; 4]) -> Vec<Factor> {
fn calc(op: &[Operator], numbers: &[i32], acc: &[Factor]) -> Vec<Factor> {
use Operator::*;
if op.is_empty() {
return Vec::from(acc)
}
let mut ret = Vec::new();
let mono_factor = [Factor {
content: numbers[0].to_string(),
value: numbers[0],
}];
match op[0] {
Mul => ret.extend_from_slice(&apply(op[0], acc, &mono_factor)),
Div => {
ret.extend_from_slice(&apply(op[0], acc, &mono_factor));
ret.extend_from_slice(&apply(op[0], &mono_factor, acc));
},
Sub => {
ret.extend_from_slice(&apply(op[0], acc, &mono_factor));
ret.extend_from_slice(&apply(op[0], &mono_factor, acc));
},
Plus => ret.extend_from_slice(&apply(op[0], acc, &mono_factor)),
}
calc(&op[1..], &numbers[1..], &ret)
}
calc(&op, &numbers[1..], &[Factor { content: numbers[0].to_string(), value: numbers[0] }])
}
 
fn solutions(numbers: [i32; 4]) -> Vec<Factor> {
use std::collections::hash_set::HashSet;
let mut ret = Vec::new();
let mut hash_set = HashSet::new();
for ops in OpIter(0) {
for o in orders().iter() {
let numbers = apply_order(numbers, o);
let r = calc(ops, numbers);
ret.extend(r.into_iter().filter(|&Factor { value, ref content }| value == 24 && hash_set.insert(content.to_owned())))
}
}
ret
}
 
fn main() {
let mut numbers = Vec::new();
if let Some(input) = std::env::args().skip(1).next() {
for c in input.chars() {
if let Ok(n) = c.to_string().parse() {
numbers.push(n)
}
if numbers.len() == 4 {
let numbers = [numbers[0], numbers[1], numbers[2], numbers[3]];
let solutions = solutions(numbers);
let len = solutions.len();
if len == 0 {
println!("no solution for {}, {}, {}, {}", numbers[0], numbers[1], numbers[2], numbers[3]);
return
}
println!("solutions for {}, {}, {}, {}", numbers[0], numbers[1], numbers[2], numbers[3]);
for s in solutions {
println!("{}", s.content)
}
println!("{} solutions found", len);
return
}
}
} else {
println!("empty input")
}
}
 
 
struct OpIter (usize);
 
impl Iterator for OpIter {
type Item = [Operator; 3];
fn next(&mut self) -> Option<[Operator; 3]> {
use Operator::*;
const OPTIONS: [Operator; 4] = [Mul, Sub, Plus, Div];
if self.0 >= 1 << 6 {
return None
}
let f1 = OPTIONS[(self.0 & (3 << 4)) >> 4];
let f2 = OPTIONS[(self.0 & (3 << 2)) >> 2];
let f3 = OPTIONS[(self.0 & (3 << 0)) >> 0];
self.0 += 1;
Some([f1, f2, f3])
}
}
 
fn orders() -> [[usize; 4]; 24] {
[
[0, 1, 2, 3],
[0, 1, 3, 2],
[0, 2, 1, 3],
[0, 2, 3, 1],
[0, 3, 1, 2],
[0, 3, 2, 1],
[1, 0, 2, 3],
[1, 0, 3, 2],
[1, 2, 0, 3],
[1, 2, 3, 0],
[1, 3, 0, 2],
[1, 3, 2, 0],
[2, 0, 1, 3],
[2, 0, 3, 1],
[2, 1, 0, 3],
[2, 1, 3, 0],
[2, 3, 0, 1],
[2, 3, 1, 0],
[3, 0, 1, 2],
[3, 0, 2, 1],
[3, 1, 0, 2],
[3, 1, 2, 0],
[3, 2, 0, 1],
[3, 2, 1, 0]
]
}
 
fn apply_order(numbers: [i32; 4], order: &[usize; 4]) -> [i32; 4] {
[numbers[order[0]], numbers[order[1]], numbers[order[2]], numbers[order[3]]]
}
</syntaxhighlight>
{{out}}
<pre>
$cargo run 5598
solutions for 5, 5, 9, 8
(((5 x 5) - 9) + 8)
(((5 x 5) + 8) - 9)
(((8 - 5) x 5) + 9)
3 solutions found
</pre>
 
=={{header|Scala}}==
A non-interactive player.
 
<langsyntaxhighlight lang="scala">def permute(l: List[Double]): List[List[Double]] = l match {
case Nil => List(Nil)
case x :: xs =>
Line 4,352 ⟶ 8,479:
}
 
def hasSolution(l: List[Double]) = permute(l) flatMap computeAllOperations filter (_._1 == 24) map (_._2)</langsyntaxhighlight>
 
Example:
Line 4,381 ⟶ 8,508:
res11: List[String] = List((4*(5-(2-3))), (2*(4+(5+3))), (2*(5+(4+3))), (2*(5+(3+4))), (2*(4+(3+5))), (2*(3+(4+5))), (2*
(3+(5+4))), (4*(5+(3-2))), (4*(3+(5-2))), (4*(3-(2-5))))
</pre>
 
=={{header|Scheme}}==
This version outputs an S-expression that will '''eval''' to 24 (rather than converting to infix notation).
 
<syntaxhighlight lang="scheme">
#!r6rs
 
(import (rnrs)
(rnrs eval)
(only (srfi :1 lists) append-map delete-duplicates iota))
 
(define (map* fn . lis)
(if (null? lis)
(list (fn))
(append-map (lambda (x)
(apply map*
(lambda xs (apply fn x xs))
(cdr lis)))
(car lis))))
 
(define (insert x li n)
(if (= n 0)
(cons x li)
(cons (car li) (insert x (cdr li) (- n 1)))))
 
(define (permutations li)
(if (null? li)
(list ())
(map* insert (list (car li)) (permutations (cdr li)) (iota (length li)))))
 
(define (evaluates-to-24 expr)
(guard (e ((assertion-violation? e) #f))
(= 24 (eval expr (environment '(rnrs base))))))
 
(define (tree n o0 o1 o2 xs)
(list-ref
(list
`(,o0 (,o1 (,o2 ,(car xs) ,(cadr xs)) ,(caddr xs)) ,(cadddr xs))
`(,o0 (,o1 (,o2 ,(car xs) ,(cadr xs)) ,(caddr xs)) ,(cadddr xs))
`(,o0 (,o1 ,(car xs) (,o2 ,(cadr xs) ,(caddr xs))) ,(cadddr xs))
`(,o0 (,o1 ,(car xs) ,(cadr xs)) (,o2 ,(caddr xs) ,(cadddr xs)))
`(,o0 ,(car xs) (,o1 (,o2 ,(cadr xs) ,(caddr xs)) ,(cadddr xs)))
`(,o0 ,(car xs) (,o1 ,(cadr xs) (,o2 ,(caddr xs) ,(cadddr xs)))))
n))
 
(define (solve a b c d)
(define ops '(+ - * /))
(define perms (delete-duplicates (permutations (list a b c d))))
(delete-duplicates
(filter evaluates-to-24
(map* tree (iota 6) ops ops ops perms))))
</syntaxhighlight>
 
Example output:
<syntaxhighlight lang="scheme">
> (solve 1 3 5 7)
((* (+ 1 5) (- 7 3))
(* (+ 5 1) (- 7 3))
(* (+ 5 7) (- 3 1))
(* (+ 7 5) (- 3 1))
(* (- 3 1) (+ 5 7))
(* (- 3 1) (+ 7 5))
(* (- 7 3) (+ 1 5))
(* (- 7 3) (+ 5 1)))
> (solve 3 3 8 8)
((/ 8 (- 3 (/ 8 3))))
> (solve 3 4 9 10)
()
</syntaxhighlight>
 
=={{header|Sidef}}==
 
'''With eval():'''
 
<syntaxhighlight lang="ruby">var formats = [
'((%d %s %d) %s %d) %s %d',
'(%d %s (%d %s %d)) %s %d',
'(%d %s %d) %s (%d %s %d)',
'%d %s ((%d %s %d) %s %d)',
'%d %s (%d %s (%d %s %d))',
]
var op = %w( + - * / )
var operators = op.map { |a| op.map {|b| op.map {|c| "#{a} #{b} #{c}" } } }.flat
loop {
var input = read("Enter four integers or 'q' to exit: ", String)
input == 'q' && break
if (input !~ /^\h*[1-9]\h+[1-9]\h+[1-9]\h+[1-9]\h*$/) {
say "Invalid input!"
next
}
var n = input.split.map{.to_n}
var numbers = n.permutations
formats.each { |format|
numbers.each { |n|
operators.each { |operator|
var o = operator.split;
var str = (format % (n[0],o[0],n[1],o[1],n[2],o[2],n[3]))
eval(str) == 24 && say str
}
}
}
}</syntaxhighlight>
 
'''Without eval():'''
<syntaxhighlight lang="ruby">var formats = [
{|a,b,c|
Hash(
func => {|d,e,f,g| ((d.$a(e)).$b(f)).$c(g) },
format => "((%d #{a} %d) #{b} %d) #{c} %d"
)
},
{|a,b,c|
Hash(
func => {|d,e,f,g| (d.$a((e.$b(f)))).$c(g) },
format => "(%d #{a} (%d #{b} %d)) #{c} %d",
)
},
{|a,b,c|
Hash(
func => {|d,e,f,g| (d.$a(e)).$b(f.$c(g)) },
format => "(%d #{a} %d) #{b} (%d #{c} %d)",
)
},
{|a,b,c|
Hash(
func => {|d,e,f,g| (d.$a(e)).$b(f.$c(g)) },
format => "(%d #{a} %d) #{b} (%d #{c} %d)",
)
},
{|a,b,c|
Hash(
func => {|d,e,f,g| d.$a(e.$b(f.$c(g))) },
format => "%d #{a} (%d #{b} (%d #{c} %d))",
)
},
];
var op = %w( + - * / )
var blocks = op.map { |a| op.map { |b| op.map { |c| formats.map { |format|
format(a,b,c)
}}}}.flat
loop {
var input = Sys.scanln("Enter four integers or 'q' to exit: ");
input == 'q' && break;
if (input !~ /^\h*[1-9]\h+[1-9]\h+[1-9]\h+[1-9]\h*$/) {
say "Invalid input!"
next
}
var n = input.split.map{.to_n}
var numbers = n.permutations
blocks.each { |block|
numbers.each { |n|
if (block{:func}.call(n...) == 24) {
say (block{:format} % (n...))
}
}
}
}</syntaxhighlight>
 
{{out}}
<pre>
Enter four integers or 'q' to exit: 8 7 9 6
(8 / (9 - 7)) * 6
(6 / (9 - 7)) * 8
(8 * 6) / (9 - 7)
(6 * 8) / (9 - 7)
8 / ((9 - 7) / 6)
6 / ((9 - 7) / 8)
8 * (6 / (9 - 7))
6 * (8 / (9 - 7))
Enter four integers or 'q' to exit: q
</pre>
 
=={{header|Simula}}==
<syntaxhighlight lang="simula">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);
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;
 
INTEGER SOLUTION;
INTEGER D1,D2,D3,D4;
INTEGER O1,O2,O3;
TEXT OPS;
 
OPS :- "+-*/";
 
E :- NEW EXPR;
OUTTEXT("ENTER FOUR INTEGERS: ");
OUTIMAGE;
FOR I := 1 STEP 1 UNTIL 4 DO DIGITS(I) := ININT; !RANDINT(0, 9, SEED);
 
! DIGITS ;
FOR D1 := 1 STEP 1 UNTIL 4 DO
FOR D2 := 1 STEP 1 UNTIL 4 DO IF D2 <> D1 THEN
FOR D3 := 1 STEP 1 UNTIL 4 DO IF D3 <> D2 AND
D3 <> D1 THEN
FOR D4 := 1 STEP 1 UNTIL 4 DO IF D4 <> D3 AND
D4 <> D2 AND
D4 <> D1 THEN
! OPERATORS ;
FOR O1 := 1 STEP 1 UNTIL 4 DO
FOR O2 := 1 STEP 1 UNTIL 4 DO
FOR O3 := 1 STEP 1 UNTIL 4 DO
BEGIN
PROCEDURE P(FMT); TEXT FMT;
BEGIN
INTEGER PLUS;
TRY.SETPOS(1);
WHILE FMT.MORE DO
BEGIN
CHARACTER C;
C := FMT.GETCHAR;
IF (C >= '1') AND (C <= '4') THEN
BEGIN
INTEGER DIG; CHARACTER NCH;
DIG := IF C = '1' THEN DIGITS(D1)
ELSE IF C = '2' THEN DIGITS(D2)
ELSE IF C = '3' THEN DIGITS(D3)
ELSE DIGITS(D4);
NCH := CHAR( DIG + RANK('0') );
TRY.PUTCHAR(NCH);
END
ELSE IF C = '+' THEN
BEGIN
PLUS := PLUS + 1;
OPS.SETPOS(IF PLUS = 1 THEN O1 ELSE
IF PLUS = 2 THEN O2
ELSE O3);
TRY.PUTCHAR(OPS.GETCHAR);
END
ELSE IF (C = '(') OR (C = ')') OR (C = ' ') THEN
TRY.PUTCHAR(C)
ELSE
ERROR("ILLEGAL EXPRESSION");
END;
IF E.EVAL(TRY) THEN
BEGIN
IF ABS(E.RESULT - 24) < 0.001 THEN
BEGIN
SOLUTION := SOLUTION + 1;
OUTTEXT(TRY); OUTTEXT(" = ");
OUTFIX(E.RESULT, 4, 10);
OUTIMAGE;
END;
END
ELSE
BEGIN
IF E.ERR <> "DIV BY ZERO" THEN
BEGIN
OUTTEXT(TRY); OUTIMAGE;
OUTTEXT(E.ERR); OUTIMAGE;
END;
END;
END P;
TEXT TRY;
TRY :- BLANKS(17);
P("(1 + 2) + (3 + 4)");
P("(1 + (2 + 3)) + 4");
P("((1 + 2) + 3) + 4");
P("1 + ((2 + 3) + 4)");
P("1 + (2 + (3 + 4))");
END;
OUTINT(SOLUTION, 0);
OUTTEXT(" SOLUTIONS FOUND");
OUTIMAGE;
END.
</syntaxhighlight>
{{out}}
<pre>
ENTER FOUR INTEGERS: 8 7 9 6
(8 / (9 - 7)) * 6 = 24.0000
8 / ((9 - 7) / 6) = 24.0000
(8 * 6) / (9 - 7) = 24.0000
8 * (6 / (9 - 7)) = 24.0000
(6 * 8) / (9 - 7) = 24.0000
6 * (8 / (9 - 7)) = 24.0000
(6 / (9 - 7)) * 8 = 24.0000
6 / ((9 - 7) / 8) = 24.0000
8 SOLUTIONS FOUND
 
2 garbage collection(s) in 0.0 seconds.
</pre>
 
=={{header|Swift}}==
 
<langsyntaxhighlight lang="swift">
import Darwin
import Foundation
 
var solution = String()""
 
println("24 Game")
Line 4,395 ⟶ 9,018:
 
func randomDigits() -> [Int] {
var result = [Int]();
for var i =in 0; i ..< 4; i++ {
result.append(Int(arc4random_uniform(9)+1))
}
return result;
}
 
Line 4,408 ⟶ 9,031:
 
for digit in digits {
print("\(digit) ")
}
println()
 
// get input from operator
var input = NSString(data:NSFileHandle.fileHandleWithStandardInput().availableData, encoding:NSUTF8StringEncoding)!
 
var enteredDigits = [Double]()
Line 4,423 ⟶ 9,046:
// store input in the appropriate table
for character in inputString {
switch character {
case "1", "2", "3", "4", "5", "6", "7", "8", "9":
let digit = String(character)
enteredDigits.append(Double(digit.toInt()!))
case "+", "-", "*", "/":
enteredOperations.append(character)
case "\n":
println()
default:
println("Invalid expression")
}
}
 
// check value of expression provided by the operator
var value = Double()0.0
 
if enteredDigits.count == 4 && enteredOperations.count == 3 {
value = enteredDigits[0]
for (i, operation) in enumerate(enteredOperations) {
switch operation {
case "+":
value = value + enteredDigits[i+1]
case "-":
value = value - enteredDigits[i+1]
case "*":
value = value * enteredDigits[i+1]
case "/":
value = value / enteredDigits[i+1]
default:
println("This message should never happen!")
}
}
}
}
 
func evaluate(dPerm: [Double], oPerm: [String]) -> Bool {
var value = 0.0
if dPerm.count == 4 && oPerm.count == 3 {
value = dPerm[0]
for (i, operation) in enumerate(oPerm) {
switch operation {
case "+":
value = value + dPerm[i+1]
case "-":
value = value - dPerm[i+1]
case "*":
value = value * dPerm[i+1]
case "/":
value = value / dPerm[i+1]
default:
println("This message should never happen!")
}
}
}
}
return (abs(24 - value) < 0.001)
return (abs(24 - value) < 0.001)
}
 
func isSolvable(inout digits: [Double]) -> Bool {
var result = false
var dPerms = [[Double]]()
permute(&digits, &dPerms, 0);
let total = 4 * 4 * 4
var oPerms = [[String]]()
permuteOperators(&oPerms, 4, total);
var expression = String()
for dig in dPerms {
for digopr in dPermsoPerms {
var expression for= opr in oPerms {""
if evaluate(dig, opr) {
for digit in dig {
expression += "\(digit)"
}
for oper if evaluate(dig,in opr) {
expression += for digit in dig {oper
expression += "\(digit)"
}
for oper in opr {
expression += oper
}
solution = beautify(expression)
result = true
}
expression = ""
}
solution = beautify(expression)
result = true
}
}
}
return result
return result
}
 
func permute(inout lst: [Double], inout res: [[Double]], k: Int) -> Void {
for (var i =in k; i ..< lst.count; i++) {
swap(&lst[i], &lst[k])
permute(&lst, &res, k + 1)
swap(&lst[k], &lst[i])
}
if (k == lst.count) {
res.append(lst)
}
}
 
// n=4, total=64, npow=16
func permuteOperators(inout res: [[String]], n: Int, total: Int) -> Void {
let posOperations = ["+", "-", "*", "/"]
for (var i = 0,let npow = n * n; i < total; i++) {
for i in 0 ..< total {
res.append([posOperations[(i / npow)], posOperations[((i % npow) / n)], posOperations[(i % n)]])
res.append([posOperations[(i / npow)], posOperations[((i % npow) / n)], posOperations[(i % n)]])
}
}
}
 
func beautify(infix: String) -> String {
varlet newString = infix as NSString
var solution = NSMutableString()
 
solution.appendString(newString.substringWithRange(NSMakeRange(0, 1)))
solution.appendString(newString.substringWithRange(NSMakeRange(12, 1)))
solution.appendString(newString.substringWithRange(NSMakeRange(3, 1)))
solution.appendString(newString.substringWithRange(NSMakeRange(13, 1)))
solution.appendString(newString.substringWithRange(NSMakeRange(6, 1)))
solution.appendString(newString.substringWithRange(NSMakeRange(14, 1)))
solution.appendString(newString.substringWithRange(NSMakeRange(9, 1)))
var solution = ""
return solution
solution += newString.substringWithRange(NSMakeRange(0, 1))
solution += newString.substringWithRange(NSMakeRange(12, 1))
solution += newString.substringWithRange(NSMakeRange(3, 1))
solution += newString.substringWithRange(NSMakeRange(13, 1))
solution += newString.substringWithRange(NSMakeRange(6, 1))
solution += newString.substringWithRange(NSMakeRange(14, 1))
solution += newString.substringWithRange(NSMakeRange(9, 1))
return solution
}
 
if value != 24 {
println("The value of the provided expression is \(value) instead of 24!")
if isSolvable(&enteredDigits) {
println("A possible solution could have been " + solution)
} else {
println("Anyway, there was no known solution to this one.")
}
} else {
println("Congratulations, you found a solution!")
}</syntaxhighlight>
}
</lang>
 
{{out}}The program in action:
<pre style="height:30ex;overflow:scroll">
24 Game
Line 4,605 ⟶ 9,227:
This is a complete Tcl script, intended to be invoked from the command line.
{{tcllib|struct::list}}
<langsyntaxhighlight lang="tcl">package require struct::list
# Encoding the various expression trees that are possible
set patterns {
{((A x B) y C) z D}
{(A x (B y C)) z D}
{(A x B) y (C z D)}
{A x ((B y C) z D)}
{A x (B y (C z D))}
}
# Encoding the various permutations of digits
Line 4,620 ⟶ 9,242:
set operations {+ - * /}
 
# Given a list of four integers (precondition not checked!) return a list of
# return a list of solutions to the 24 game using those four integers.
proc find24GameSolutions {values} {
global operations patterns permutations
Line 4,666 ⟶ 9,288:
}
}
print24GameSolutionFor $argv</langsyntaxhighlight>
{{out}}
Demonstrating it in use:
<span style="color:silver">''bash$''</span> <span style="color:brown">tclsh8.4 24player.tcl 3 2 8 9</span>
Line 4,686 ⟶ 9,309:
non-terminal nodes of a tree in every possible way. The <code>value</code> function evaluates a tree and the
<code>format</code> function displays it in a readable form.
<langsyntaxhighlight Ursalalang="ursala">#import std
#import nat
#import rat
Line 4,696 ⟶ 9,319:
format = *^ ~&v?\-+~&h,%zP@d+- ^H/mat@d *v ~&t?\~& :/`(+ --')'
 
game"n" "d" = format* value==("n",1)*~ with_roots/'+-*/' with_leaves/"d"*-1 tree_shapes length "d"</langsyntaxhighlight>
test program:
<langsyntaxhighlight Ursalalang="ursala">#show+
 
test_games = mat` * pad` *K7 pad0 game24* <<2,3,8,9>,<5,7,4,1>,<5,6,7,8>></langsyntaxhighlight>
output:
<pre>
Line 4,732 ⟶ 9,355:
((5-8)+7)*6
</pre>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-dynamic}}
<syntaxhighlight lang="wren">import "random" for Random
import "./dynamic" for Tuple, Enum, Struct
 
var N_CARDS = 4
var SOLVE_GOAL = 24
var MAX_DIGIT = 9
 
var Frac = Tuple.create("Frac", ["num", "den"])
 
var OpType = Enum.create("OpType", ["NUM", "ADD", "SUB", "MUL", "DIV"])
 
var Expr = Struct.create("Expr", ["op", "left", "right", "value"])
 
var showExpr // recursive function
showExpr = Fn.new { |e, prec, isRight|
if (!e) return
if (e.op == OpType.NUM) {
System.write(e.value)
return
}
var op = (e.op == OpType.ADD) ? " + " :
(e.op == OpType.SUB) ? " - " :
(e.op == OpType.MUL) ? " x " :
(e.op == OpType.DIV) ? " / " : e.op
if ((e.op == prec && isRight) || e.op < prec) System.write("(")
showExpr.call(e.left, e.op, false)
System.write(op)
showExpr.call(e.right, e.op, true)
if ((e.op == prec && isRight) || e.op < prec) System.write(")")
}
 
var evalExpr // recursive function
evalExpr = Fn.new { |e|
if (!e) return Frac.new(0, 1)
if (e.op == OpType.NUM) return Frac.new(e.value, 1)
var l = evalExpr.call(e.left)
var r = evalExpr.call(e.right)
var res = (e.op == OpType.ADD) ? Frac.new(l.num * r.den + l.den * r.num, l.den * r.den) :
(e.op == OpType.SUB) ? Frac.new(l.num * r.den - l.den * r.num, l.den * r.den) :
(e.op == OpType.MUL) ? Frac.new(l.num * r.num, l.den * r.den) :
(e.op == OpType.DIV) ? Frac.new(l.num * r.den, l.den * r.num) :
Fiber.abort("Unknown op: %(e.op)")
return res
}
 
var solve // recursive function
solve = Fn.new { |ea, len|
if (len == 1) {
var final = evalExpr.call(ea[0])
if (final.num == final.den * SOLVE_GOAL && final.den != 0) {
showExpr.call(ea[0], OpType.NUM, false)
return true
}
}
var ex = List.filled(N_CARDS, null)
for (i in 0...len - 1) {
for (j in i + 1...len) ex[j - 1] = ea[j]
var node = Expr.new(OpType.NUM, null, null, 0)
ex[i] = node
for (j in i + 1...len) {
node.left = ea[i]
node.right = ea[j]
for (k in OpType.startsFrom+1...OpType.members.count) {
node.op = k
if (solve.call(ex, len - 1)) return true
}
node.left = ea[j]
node.right = ea[i]
node.op = OpType.SUB
if (solve.call(ex, len - 1)) return true
node.op = OpType.DIV
if (solve.call(ex, len - 1)) return true
ex[j] = ea[j]
}
ex[i] = ea[i]
}
return false
}
 
var solve24 = Fn.new { |n|
var l = List.filled(N_CARDS, null)
for (i in 0...N_CARDS) l[i] = Expr.new(OpType.NUM, null, null, n[i])
return solve.call(l, N_CARDS)
}
 
var r = Random.new()
var n = List.filled(N_CARDS, 0)
for (j in 0..9) {
for (i in 0...N_CARDS) {
n[i] = 1 + r.int(MAX_DIGIT)
System.write(" %(n[i])")
}
System.write(": ")
System.print(solve24.call(n) ? "" : "No solution")
}</syntaxhighlight>
 
{{out}}
Sample run:
<pre>
5 4 2 6: (5 + 4) x 2 + 6
5 3 2 9: (5 - 2) x 9 - 3
4 8 4 3: ((4 + 8) - 4) x 3
3 8 4 7: 8 - (3 - 7) x 4
7 9 9 2: No solution
1 6 5 5: (1 + 5) x 5 - 6
3 2 7 8: (8 - (3 - 7)) x 2
2 2 8 8: (2 + 2) x 8 - 8
6 4 2 5: (6 - 2) x 5 + 4
9 2 1 6: 9 x 2 x 1 + 6
</pre>
 
=={{header|Yabasic}}==
<syntaxhighlight lang="yabasic">operators$ = "*+-/"
space$ = " "
 
sub present()
clear screen
print "24 Game"
print "============\n"
print "Computer provide 4 numbers (1 to 9). With operators +, -, * and / you try to\nobtain 24."
print "Use Reverse Polish Notation (first operand and then the operators)"
print "For example: instead of 2 + 4, type 2 4 +\n\n"
end sub
 
repeat
present()
serie$ = sortString$(genSerie$())
valid$ = serie$+operators$
print "If you give up, press ENTER and the program attempts to find a solution."
line input "Write your solution: " input$
if input$ = "" then
print "Thinking ... "
res$ = explorer$()
if res$ = "" print "Can not get 24 with these numbers.."
else
input$ = delSpace$(input$)
inputSort$ = sortString$(input$)
if (right$(inputSort$,4) <> serie$) or (len(inputSort$)<>7) then
print "Syntax error"
else
result = evalInput(input$)
print "Your solution = ",result," is ";
if result = 24 then
print "Correct!"
else
print "Wrong!"
end if
end if
end if
print "\nDo you want to try again? (press N for exit, other key to continue)"
until(upper$(left$(inkey$(),1)) = "N")
 
exit
 
sub genSerie$()
local i, c$, s$
print "The numbers you should use are: ";
i = ran()
for i = 1 to 4
c$ = str$(int(ran(9))+1)
print c$," ";
s$ = s$ + c$
next i
print
return s$
end sub
 
 
sub evalInput(entr$)
local d1, d2, c$, n(4), i
while(entr$<>"")
c$ = left$(entr$,1)
entr$ = mid$(entr$,2)
if instr(serie$,c$) then
i = i + 1
n(i) = val(c$)
elseif instr(operators$,c$) then
d2 = n(i)
n(i) = 0
i = i - 1
if i = 0 return
d1 = n(i)
n(i) = evaluator(d1, d2, c$)
else
print "Invalid symbol"
return
end if
wend
return n(i)
end sub
 
 
sub evaluator(d1, d2, op$)
local t
switch op$
case "+": t = d1 + d2 : break
case "-": t = d1 - d2 : break
case "*": t = d1 * d2 : break
case "/": t = d1 / d2 : break
end switch
return t
end sub
 
 
sub delSpace$(entr$)
local n, i, s$, t$(1)
n = token(entr$,t$()," ")
for i=1 to n
s$ = s$ + t$(i)
next i
return s$
end sub
 
 
sub sortString$(string$)
local signal, n, fin, c$
fin = len(string$)-1
repeat
signal = false
for n = 1 to fin
if mid$(string$,n,1) > mid$(string$,n+1,1) then
signal = true
c$ = mid$(string$,n,1)
mid$(string$,n,1) = mid$(string$,n+1,1)
mid$(string$,n+1,1) = c$
end if
next n
until(signal = false)
return string$
end sub
 
 
sub explorer$()
local d1,d2,o3,x4,x5,x6,o7,p$,result,solution,solutions$,n
for d1 = 1 to 4
for d2 = 1 to 4
for o3 = 1 to 4
for x4 = 1 to 8
for x5 = 1 to 8
for x6 = 1 to 8
for o7 = 1 to 4
p$ = mid$(serie$,d1,1)+mid$(serie$,d2,1)+mid$(operators$,o3,1)
p$ = p$+mid$(valid$,x4,1)+mid$(valid$,x5,1)+mid$(valid$,x6,1)
p$ = p$+mid$(operators$,o7,1)
if not instr(solutions$,p$) then
if validateInput(p$) then
result = evalInput(p$)
if result = 24 then
solution = solution + 1
print "Solution: ",solution," = ";
solutions$ = solutions$ + p$
for n = 1 to 7
print mid$(p$,n,1)," ";
next n
print
end if
end if
end if
next o7
next x6
next x5
next x4
next o3
next d2
next d1
return p$
end sub
 
 
sub validateInput(e$)
local n, inputSort$
inputSort$ = sortString$(e$)
if serie$ <> right$(inputSort$,4) return false
for n=1 to 3
if not instr(operators$,mid$(inputSort$,n,1)) then
return false
end if
next n
return true
end sub</syntaxhighlight>
 
=={{header|zkl}}==
Line 4,737 ⟶ 9,655:
 
File solve24.zkl:
<langsyntaxhighlight lang="zkl">var [const] H=Utils.Helpers;
fcn u(xs){ xs.reduce(fcn(us,s){us.holds(s) and us or us.append(s) },L()) }
var ops=u(H.combosK(3,"+-*/".split("")).apply(H.permute).flatten());
var fs=T(
fcn f0(a,b,c,d,x,y,z){ Op(z)(Op(y)(Op(x)(a,b),c),d) }, // ((AxB)yC)zD
fcn f1(a,b,c,d,x,y,z){ Op(y)(Op(x)(a,b),Op(z)(c,d)) }, // (AxB)y(CzD)
fcn f2(a,b,c,d,x,y,z){ Op(z)(Op(x)(a,Op(y)(b,c)),d) }, // (Ax(ByC))zD
fcn f3(a,b,c,d,x,y,z){ Op(x)(a,Op(z)(Op(y)(b,c),d)) }, // Ax((ByC)zD)
fcn f4(a,b,c,d,x,y,z){ Op(x)(a,Op(y)(b,Op(z)(c,d))) }, // Ax(By(CzD))
);
 
var fts= // format strings for human readable formulas
T("((d.d).d).d", "(d.d).(d.d)", "(d.(d.d)).d", "d.((d.d).d)", "d.(d.(d.d))")
.apply(Tpump(List,T("replace","d","%d"),T("replace",".","%s")));
 
fcn f2s(digits,ops,f){ // formula (fs[n]) to string
fts[f.name[1].toInt()].fmt(digits.zip(ops).flatten().xplode(),digits[3]);
.fmt(H.listZip(digits,ops).flatten().xplode(),digits[3]);
}
 
fcn game24Solver(digitsString){
digits:=digitsString.split("").apply("toFloat");
[[(digits4,ops3,f); H.permute(digits); ops; // list comprehension
fs,{ try{f(digits4.xplode(),ops3.xplode()).closeTo(24,0.001) }
catch(MathError){ False } };
{ f2s(digits4,ops3,f) }]];
}</syntaxhighlight>
}
<syntaxhighlight lang="zkl">solutions:=u(game24Solver(ask(0,"digits: ")));
 
solutions:=u(game24Solver(ask(0,"digits: ")));
println(solutions.len()," solutions:");
solutions.apply2(Console.println);</langsyntaxhighlight>
One trick used is to look at the solving functions name and use the digit in it to index into the formats list.
{{out}}
Line 4,793 ⟶ 9,709:
</pre>
 
[[Category:Puzzles]]
 
{{omit from|GUISS}}
9,482

edits