Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
2
Task/24-game-Solve/00-META.yaml
Normal file
2
Task/24-game-Solve/00-META.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
from: http://rosettacode.org/wiki/24_game/Solve
|
||||
9
Task/24-game-Solve/00-TASK.txt
Normal file
9
Task/24-game-Solve/00-TASK.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
;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 program.
|
||||
|
||||
|
||||
;Related task:
|
||||
* [[Arithmetic Evaluator]]
|
||||
<br><br>
|
||||
40
Task/24-game-Solve/11l/24-game-solve.11l
Normal file
40
Task/24-game-Solve/11l/24-game-solve.11l
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
[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))
|
||||
430
Task/24-game-Solve/AArch64-Assembly/24-game-solve.aarch64
Normal file
430
Task/24-game-Solve/AArch64-Assembly/24-game-solve.aarch64
Normal file
|
|
@ -0,0 +1,430 @@
|
|||
/* 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"
|
||||
198
Task/24-game-Solve/ABAP/24-game-solve.abap
Normal file
198
Task/24-game-Solve/ABAP/24-game-solve.abap
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
data: lv_flag type c,
|
||||
lv_number type i,
|
||||
lt_numbers type table of i.
|
||||
|
||||
constants: c_no_val type i value 9999.
|
||||
|
||||
append 1 to lt_numbers.
|
||||
append 1 to lt_numbers.
|
||||
append 2 to lt_numbers.
|
||||
append 7 to lt_numbers.
|
||||
|
||||
write 'Evaluating 24 with the following input: '.
|
||||
loop at lt_numbers into lv_number.
|
||||
write lv_number.
|
||||
endloop.
|
||||
perform solve_24 using lt_numbers.
|
||||
|
||||
form eval_formula using iv_eval type string changing ev_out type i.
|
||||
call function 'EVAL_FORMULA' "analysis of a syntactically correct formula
|
||||
exporting
|
||||
formula = iv_eval
|
||||
importing
|
||||
value = ev_out
|
||||
exceptions
|
||||
others = 1.
|
||||
|
||||
if sy-subrc <> 0.
|
||||
ev_out = -1.
|
||||
endif.
|
||||
endform.
|
||||
|
||||
" Solve a 24 puzzle.
|
||||
form solve_24 using it_numbers like lt_numbers.
|
||||
data: lv_flag type c,
|
||||
lv_op1 type c,
|
||||
lv_op2 type c,
|
||||
lv_op3 type c,
|
||||
lv_var1 type c,
|
||||
lv_var2 type c,
|
||||
lv_var3 type c,
|
||||
lv_var4 type c,
|
||||
lv_eval type string,
|
||||
lv_result type i,
|
||||
lv_var type i.
|
||||
|
||||
define retrieve_var.
|
||||
read table it_numbers index &1 into lv_var.
|
||||
&2 = lv_var.
|
||||
end-of-definition.
|
||||
|
||||
define retrieve_val.
|
||||
perform eval_formula using lv_eval changing lv_result.
|
||||
if lv_result = 24.
|
||||
write / lv_eval.
|
||||
endif.
|
||||
end-of-definition.
|
||||
" Loop through all the possible number permutations.
|
||||
do.
|
||||
" Init. the operations table.
|
||||
|
||||
retrieve_var: 1 lv_var1, 2 lv_var2, 3 lv_var3, 4 lv_var4.
|
||||
do 4 times.
|
||||
case sy-index.
|
||||
when 1.
|
||||
lv_op1 = '+'.
|
||||
when 2.
|
||||
lv_op1 = '*'.
|
||||
when 3.
|
||||
lv_op1 = '-'.
|
||||
when 4.
|
||||
lv_op1 = '/'.
|
||||
endcase.
|
||||
do 4 times.
|
||||
case sy-index.
|
||||
when 1.
|
||||
lv_op2 = '+'.
|
||||
when 2.
|
||||
lv_op2 = '*'.
|
||||
when 3.
|
||||
lv_op2 = '-'.
|
||||
when 4.
|
||||
lv_op2 = '/'.
|
||||
endcase.
|
||||
do 4 times.
|
||||
case sy-index.
|
||||
when 1.
|
||||
lv_op3 = '+'.
|
||||
when 2.
|
||||
lv_op3 = '*'.
|
||||
when 3.
|
||||
lv_op3 = '-'.
|
||||
when 4.
|
||||
lv_op3 = '/'.
|
||||
endcase.
|
||||
concatenate '(' '(' lv_var1 lv_op1 lv_var2 ')' lv_op2 lv_var3 ')' lv_op3 lv_var4 into lv_eval separated by space.
|
||||
retrieve_val.
|
||||
concatenate '(' lv_var1 lv_op1 lv_var2 ')' lv_op2 '(' lv_var3 lv_op3 lv_var4 ')' into lv_eval separated by space.
|
||||
retrieve_val.
|
||||
concatenate '(' lv_var1 lv_op1 '(' lv_var2 lv_op2 lv_var3 ')' ')' lv_op3 lv_var4 into lv_eval separated by space.
|
||||
retrieve_val.
|
||||
concatenate lv_var1 lv_op1 '(' '(' lv_var2 lv_op2 lv_var3 ')' lv_op3 lv_var4 ')' into lv_eval separated by space.
|
||||
retrieve_val.
|
||||
concatenate lv_var1 lv_op1 '(' lv_var2 lv_op2 '(' lv_var3 lv_op3 lv_var4 ')' ')' into lv_eval separated by space.
|
||||
retrieve_val.
|
||||
enddo.
|
||||
enddo.
|
||||
enddo.
|
||||
|
||||
" Once we've reached the last permutation -> Exit.
|
||||
perform permute using it_numbers changing lv_flag.
|
||||
if lv_flag = 'X'.
|
||||
exit.
|
||||
endif.
|
||||
enddo.
|
||||
endform.
|
||||
|
||||
|
||||
" Permutation function - this is used to permute:
|
||||
" A = {A1...AN} -> Set of supplied variables.
|
||||
" B = {B1...BN - 1} -> Set of operators.
|
||||
" Can be used for an unbounded size set. Relies
|
||||
" on lexicographic ordering of the set.
|
||||
form permute using iv_set like lt_numbers
|
||||
changing ev_last type c.
|
||||
data: lv_len type i,
|
||||
lv_first type i,
|
||||
lv_third type i,
|
||||
lv_count type i,
|
||||
lv_temp type i,
|
||||
lv_temp_2 type i,
|
||||
lv_second type i,
|
||||
lv_changed type c,
|
||||
lv_perm type i.
|
||||
describe table iv_set lines lv_len.
|
||||
|
||||
lv_perm = lv_len - 1.
|
||||
lv_changed = ' '.
|
||||
" Loop backwards through the table, attempting to find elements which
|
||||
" can be permuted. If we find one, break out of the table and set the
|
||||
" flag indicating a switch.
|
||||
do.
|
||||
if lv_perm <= 0.
|
||||
exit.
|
||||
endif.
|
||||
" Read the elements.
|
||||
read table iv_set index lv_perm into lv_first.
|
||||
add 1 to lv_perm.
|
||||
read table iv_set index lv_perm into lv_second.
|
||||
subtract 1 from lv_perm.
|
||||
if lv_first < lv_second.
|
||||
lv_changed = 'X'.
|
||||
exit.
|
||||
endif.
|
||||
subtract 1 from lv_perm.
|
||||
enddo.
|
||||
|
||||
" Last permutation.
|
||||
if lv_changed <> 'X'.
|
||||
ev_last = 'X'.
|
||||
exit.
|
||||
endif.
|
||||
|
||||
" Swap tail decresing to get a tail increasing.
|
||||
lv_count = lv_perm + 1.
|
||||
do.
|
||||
lv_first = lv_len + lv_perm - lv_count + 1.
|
||||
if lv_count >= lv_first.
|
||||
exit.
|
||||
endif.
|
||||
|
||||
read table iv_set index lv_count into lv_temp.
|
||||
read table iv_set index lv_first into lv_temp_2.
|
||||
modify iv_set index lv_count from lv_temp_2.
|
||||
modify iv_set index lv_first from lv_temp.
|
||||
add 1 to lv_count.
|
||||
enddo.
|
||||
|
||||
lv_count = lv_len - 1.
|
||||
do.
|
||||
if lv_count <= lv_perm.
|
||||
exit.
|
||||
endif.
|
||||
|
||||
read table iv_set index lv_count into lv_first.
|
||||
read table iv_set index lv_perm into lv_second.
|
||||
read table iv_set index lv_len into lv_third.
|
||||
if ( lv_first < lv_third ) and ( lv_first > lv_second ).
|
||||
lv_len = lv_count.
|
||||
endif.
|
||||
|
||||
subtract 1 from lv_count.
|
||||
enddo.
|
||||
|
||||
read table iv_set index lv_perm into lv_temp.
|
||||
read table iv_set index lv_len into lv_temp_2.
|
||||
modify iv_set index lv_perm from lv_temp_2.
|
||||
modify iv_set index lv_len from lv_temp.
|
||||
endform.
|
||||
385
Task/24-game-Solve/ARM-Assembly/24-game-solve.arm
Normal file
385
Task/24-game-Solve/ARM-Assembly/24-game-solve.arm
Normal file
|
|
@ -0,0 +1,385 @@
|
|||
/* 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"
|
||||
98
Task/24-game-Solve/Argile/24-game-solve.argile
Normal file
98
Task/24-game-Solve/Argile/24-game-solve.argile
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
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 \
|
||||
the _24_ game, computes an expression to solve the game if possible.
|
||||
|
||||
use std, array
|
||||
|
||||
let digits be an array of 4 byte
|
||||
let operators be an array of 4 byte
|
||||
(: reordered arrays :)
|
||||
let (type of digits) rdigits
|
||||
let (type of operators) roperators
|
||||
|
||||
.: a function that given four digits <text digits> subject to
|
||||
the rules of the _24_ game, computes an expression to solve
|
||||
the game if possible. :. -> text
|
||||
if #digits != 4 {return "[error: need exactly 4 digits]"}
|
||||
operators[0] = '+' ; operators[1] = '-'
|
||||
operators[2] = '*' ; operators[3] = '/'
|
||||
for each (val int d) from 0 to 3
|
||||
if (digits[d] < '1') || (digits[d] > '9')
|
||||
return "[error: non-digit character given]"
|
||||
(super digits)[d] = digits[d]
|
||||
let expr = for each operand order stuff
|
||||
return "" if expr is nil
|
||||
expr
|
||||
|
||||
.:for each operand order stuff:. -> text
|
||||
for each (val int a) from 0 to 3
|
||||
for each (val int b) from 0 to 3
|
||||
next if (b == a)
|
||||
for each (val int c) from 0 to 3
|
||||
next if (c == b) or (c == a)
|
||||
for each (val int d) from 0 to 3
|
||||
next if (d == c) or (d == b) or (d == a)
|
||||
rdigits[0] = digits[a] ; rdigits[1] = digits[b]
|
||||
rdigits[2] = digits[c] ; rdigits[3] = digits[d]
|
||||
let found = for each operator order stuff
|
||||
return found unless found is nil
|
||||
nil
|
||||
|
||||
.:for each operator order stuff:. -> text
|
||||
for each (val int i) from 0 to 3
|
||||
for each (val int j) from 0 to 3
|
||||
for each (val int k) from 0 to 3
|
||||
roperators[0] = operators[i]
|
||||
roperators[1] = operators[j]
|
||||
roperators[2] = operators[k]
|
||||
let found = for each RPN pattern stuff
|
||||
return found if found isn't nil
|
||||
nil
|
||||
|
||||
our (raw array of text) RPN_patterns = Cdata
|
||||
"xx.x.x."
|
||||
"xx.xx.."
|
||||
"xxx..x."
|
||||
"xxx.x.."
|
||||
"xxxx..."
|
||||
our (raw array of text) formats = Cdata
|
||||
"((%c%c%c)%c%c)%c%c"
|
||||
"(%c%c%c)%c(%c%c%c)"
|
||||
"(%c%c(%c%c%c))%c%c"
|
||||
"%c%c((%c%c%c)%c%c)"
|
||||
"%c%c(%c%c(%c%c%c))"
|
||||
our (raw array of array of 3 int) rrop = Cdata
|
||||
{0;1;2}; {0;2;1}; {1;0;2}; {2;0;1}; {2;1;0}
|
||||
|
||||
.:for each RPN pattern stuff:. -> text
|
||||
let RPN_stack be an array of 4 real
|
||||
for each (val int rpn) from 0 to 4
|
||||
let (nat) sp=0, op=0, dg=0.
|
||||
let text p
|
||||
for (p = RPN_patterns[rpn]) (*p != 0) (p++)
|
||||
if *p == 'x'
|
||||
if sp >= 4 {die "RPN stack overflow\n"}
|
||||
if dg > 3 {die "RPN digits overflow\n"}
|
||||
RPN_stack[sp++] = (rdigits[dg++] - '0') as real
|
||||
if *p == '.'
|
||||
if sp < 2 {die "RPN stack underflow\n"}
|
||||
if op > 2 {die "RPN operators overflow\n"}
|
||||
sp -= 2
|
||||
let x = RPN_stack[sp]
|
||||
let y = RPN_stack[sp + 1]
|
||||
switch roperators[op++]
|
||||
case '+' {x += y}
|
||||
case '-' {x -= y}
|
||||
case '*' {x *= y}
|
||||
case '/' {x /= y}
|
||||
default {die "RPN operator unknown\n"}
|
||||
RPN_stack[sp++] = x
|
||||
if RPN_stack[0] == 24.0
|
||||
our array of 12 byte buffer (: 4 paren + 3 ops + 4 digits + null :)
|
||||
snprintf (buffer as text) (size of buffer) (formats[rpn]) \
|
||||
(rdigits[0]) (roperators[(rrop[rpn][0])]) (rdigits[1]) \
|
||||
(roperators[(rrop[rpn][1])]) (rdigits[2]) \
|
||||
(roperators[(rrop[rpn][2])]) (rdigits[3]);
|
||||
return buffer as text
|
||||
nil
|
||||
108
Task/24-game-Solve/AutoHotkey/24-game-solve.ahk
Normal file
108
Task/24-game-Solve/AutoHotkey/24-game-solve.ahk
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
#NoEnv
|
||||
InputBox, NNNN ; user input 4 digits
|
||||
NNNN := RegExReplace(NNNN, "(\d)(?=\d)", "$1,") ; separate with commas for the sort command
|
||||
sort NNNN, d`, ; sort in ascending order for the permutations to work
|
||||
StringReplace NNNN, NNNN, `,, , All ; remove comma separators after sorting
|
||||
|
||||
ops := "+-*/"
|
||||
patterns := [ "x x.x.x."
|
||||
,"x x.x x.."
|
||||
,"x x x..x."
|
||||
,"x x x.x.."
|
||||
,"x x x x..." ]
|
||||
|
||||
; build bruteforce operator list ("+++, ++-, ++* ... ///")
|
||||
a := b := c := 0
|
||||
While (++a<5){
|
||||
While (++b<5){
|
||||
While (++c<5){
|
||||
l := SubStr(ops, a, 1) . SubStr(ops, b, 1) . SubStr(ops, c, 1)
|
||||
|
||||
; build bruteforce template ("x x+x+x+, x x+x x++ ... x x x x///")
|
||||
For each, pattern in patterns
|
||||
{
|
||||
Loop 3
|
||||
StringReplace, pattern, pattern, ., % SubStr(l, A_Index, 1)
|
||||
pat .= pattern "`n"
|
||||
}
|
||||
}c := 0
|
||||
}b := 0
|
||||
}
|
||||
StringTrimRight, pat, pat, 1 ; remove trailing newline
|
||||
|
||||
|
||||
; permutate input. As the lexicographic algorithm is used, each permutation generated is unique
|
||||
While NNNN
|
||||
{
|
||||
StringSplit, N, NNNN
|
||||
; substitute numbers in for x's and evaluate
|
||||
Loop Parse, pat, `n
|
||||
{
|
||||
eval := A_LoopField ; current line
|
||||
Loop 4
|
||||
StringReplace, eval, eval, x, % N%A_Index% ; substitute number for "x"
|
||||
If Round(evalRPN(eval), 4) = 24
|
||||
final .= eval "`n"
|
||||
}
|
||||
NNNN := perm_next(NNNN) ; next lexicographic permutation of user's digits
|
||||
}
|
||||
MsgBox % final ? clipboard := final : "No solution"
|
||||
|
||||
; simple stack-based evaluation. Integers only. Whitespace is used to push a value.
|
||||
evalRPN(s){
|
||||
stack := []
|
||||
Loop Parse, s
|
||||
If A_LoopField is number
|
||||
t .= A_LoopField
|
||||
else
|
||||
{
|
||||
If t
|
||||
stack.Insert(t), t := ""
|
||||
If InStr("+-/*", l := A_LoopField)
|
||||
{
|
||||
a := stack.Remove(), b := stack.Remove()
|
||||
stack.Insert( l = "+" ? b + a
|
||||
:l = "-" ? b - a
|
||||
:l = "*" ? b * a
|
||||
:l = "/" ? b / a
|
||||
:0 )
|
||||
}
|
||||
}
|
||||
return stack.Remove()
|
||||
}
|
||||
|
||||
|
||||
|
||||
perm_Next(str){
|
||||
p := 0, sLen := StrLen(str)
|
||||
Loop % sLen
|
||||
{
|
||||
If A_Index=1
|
||||
continue
|
||||
t := SubStr(str, sLen+1-A_Index, 1)
|
||||
n := SubStr(str, sLen+2-A_Index, 1)
|
||||
If ( t < n )
|
||||
{
|
||||
p := sLen+1-A_Index, pC := SubStr(str, p, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
If !p
|
||||
return false
|
||||
Loop
|
||||
{
|
||||
t := SubStr(str, sLen+1-A_Index, 1)
|
||||
If ( t > pC )
|
||||
{
|
||||
n := sLen+1-A_Index, nC := SubStr(str, n, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
return SubStr(str, 1, p-1) . nC . Reverse(SubStr(str, p+1, n-p-1) . pC . SubStr(str, n+1))
|
||||
}
|
||||
|
||||
Reverse(s){
|
||||
Loop Parse, s
|
||||
o := A_LoopField o
|
||||
return o
|
||||
}
|
||||
56
Task/24-game-Solve/BBC-BASIC/24-game-solve.basic
Normal file
56
Task/24-game-Solve/BBC-BASIC/24-game-solve.basic
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
PROCsolve24("1234")
|
||||
PROCsolve24("6789")
|
||||
PROCsolve24("1127")
|
||||
PROCsolve24("5566")
|
||||
END
|
||||
|
||||
DEF PROCsolve24(s$)
|
||||
LOCAL F%, I%, J%, K%, L%, P%, T%, X$, o$(), p$(), t$()
|
||||
DIM o$(4), p$(24,4), t$(11)
|
||||
o$() = "", "+", "-", "*", "/"
|
||||
RESTORE
|
||||
FOR T% = 1 TO 11
|
||||
READ t$(T%)
|
||||
NEXT
|
||||
DATA "abcdefg", "(abc)defg", "ab(cde)fg", "abcd(efg)", "(abc)d(efg)", "(abcde)fg"
|
||||
DATA "ab(cdefg)", "((abc)de)fg", "(ab(cde))fg", "ab((cde)fg)", "ab(cd(efg))"
|
||||
|
||||
FOR I% = 1 TO 4
|
||||
FOR J% = 1 TO 4
|
||||
FOR K% = 1 TO 4
|
||||
FOR L% = 1 TO 4
|
||||
IF I%<>J% IF J%<>K% IF K%<>L% IF I%<>K% IF J%<>L% IF I%<>L% THEN
|
||||
P% += 1
|
||||
p$(P%,1) = MID$(s$,I%,1)
|
||||
p$(P%,2) = MID$(s$,J%,1)
|
||||
p$(P%,3) = MID$(s$,K%,1)
|
||||
p$(P%,4) = MID$(s$,L%,1)
|
||||
ENDIF
|
||||
NEXT
|
||||
NEXT
|
||||
NEXT
|
||||
NEXT
|
||||
|
||||
FOR I% = 1 TO 4
|
||||
FOR J% = 1 TO 4
|
||||
FOR K% = 1 TO 4
|
||||
FOR T% = 1 TO 11
|
||||
FOR P% = 1 TO 24
|
||||
X$ = t$(T%)
|
||||
MID$(X$, INSTR(X$,"a"), 1) = p$(P%,1)
|
||||
MID$(X$, INSTR(X$,"b"), 1) = o$(I%)
|
||||
MID$(X$, INSTR(X$,"c"), 1) = p$(P%,2)
|
||||
MID$(X$, INSTR(X$,"d"), 1) = o$(J%)
|
||||
MID$(X$, INSTR(X$,"e"), 1) = p$(P%,3)
|
||||
MID$(X$, INSTR(X$,"f"), 1) = o$(K%)
|
||||
MID$(X$, INSTR(X$,"g"), 1) = p$(P%,4)
|
||||
F% = TRUE : ON ERROR LOCAL F% = FALSE
|
||||
IF F% IF EVAL(X$) = 24 THEN PRINT X$ : EXIT FOR I%
|
||||
RESTORE ERROR
|
||||
NEXT
|
||||
NEXT
|
||||
NEXT
|
||||
NEXT
|
||||
NEXT
|
||||
IF I% > 4 PRINT "No solution found"
|
||||
ENDPROC
|
||||
90
Task/24-game-Solve/C++/24-game-solve.cpp
Normal file
90
Task/24-game-Solve/C++/24-game-solve.cpp
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
#include <iostream>
|
||||
#include <ratio>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
|
||||
typedef short int Digit; // Typedef for the digits data type.
|
||||
|
||||
constexpr Digit nDigits{4}; // Amount of digits that are taken into the game.
|
||||
constexpr Digit maximumDigit{9}; // Maximum digit that may be taken into the game.
|
||||
constexpr short int gameGoal{24}; // Desired result.
|
||||
|
||||
typedef std::array<Digit, nDigits> digitSet; // Typedef for the set of digits in the game.
|
||||
digitSet d;
|
||||
|
||||
void printTrivialOperation(std::string operation) { // Prints a commutative operation taking all the digits.
|
||||
bool printOperation(false);
|
||||
for(const Digit& number : d) {
|
||||
if(printOperation)
|
||||
std::cout << operation;
|
||||
else
|
||||
printOperation = true;
|
||||
std::cout << number;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void printOperation(std::string prefix, std::string operation1, std::string operation2, std::string operation3, std::string suffix = "") {
|
||||
std::cout << prefix << d[0] << operation1 << d[1] << operation2 << d[2] << operation3 << d[3] << suffix << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::mt19937_64 randomGenerator;
|
||||
std::uniform_int_distribution<Digit> digitDistro{1, maximumDigit};
|
||||
// Let us set up a number of trials:
|
||||
for(int trial{10}; trial; --trial) {
|
||||
for(Digit& digit : d) {
|
||||
digit = digitDistro(randomGenerator);
|
||||
std::cout << digit << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::sort(d.begin(), d.end());
|
||||
// We start with the most trivial, commutative operations:
|
||||
if(std::accumulate(d.cbegin(), d.cend(), 0) == gameGoal)
|
||||
printTrivialOperation(" + ");
|
||||
if(std::accumulate(d.cbegin(), d.cend(), 1, std::multiplies<Digit>{}) == gameGoal)
|
||||
printTrivialOperation(" * ");
|
||||
// Now let's start working on every permutation of the digits.
|
||||
do {
|
||||
// Operations with 2 symbols + and one symbol -:
|
||||
if(d[0] + d[1] + d[2] - d[3] == gameGoal) printOperation("", " + ", " + ", " - "); // If gameGoal is ever changed to a smaller value, consider adding more operations in this category.
|
||||
// Operations with 2 symbols + and one symbol *:
|
||||
if(d[0] * d[1] + d[2] + d[3] == gameGoal) printOperation("", " * ", " + ", " + ");
|
||||
if(d[0] * (d[1] + d[2]) + d[3] == gameGoal) printOperation("", " * ( ", " + ", " ) + ");
|
||||
if(d[0] * (d[1] + d[2] + d[3]) == gameGoal) printOperation("", " * ( ", " + ", " + ", " )");
|
||||
// Operations with one symbol + and 2 symbols *:
|
||||
if((d[0] * d[1] * d[2]) + d[3] == gameGoal) printOperation("( ", " * ", " * ", " ) + ");
|
||||
if(d[0] * d[1] * (d[2] + d[3]) == gameGoal) printOperation("( ", " * ", " * ( ", " + ", " )");
|
||||
if((d[0] * d[1]) + (d[2] * d[3]) == gameGoal) printOperation("( ", " * ", " ) + ( ", " * ", " )");
|
||||
// Operations with one symbol - and 2 symbols *:
|
||||
if((d[0] * d[1] * d[2]) - d[3] == gameGoal) printOperation("( ", " * ", " * ", " ) - ");
|
||||
if(d[0] * d[1] * (d[2] - d[3]) == gameGoal) printOperation("( ", " * ", " * ( ", " - ", " )");
|
||||
if((d[0] * d[1]) - (d[2] * d[3]) == gameGoal) printOperation("( ", " * ", " ) - ( ", " * ", " )");
|
||||
// Operations with one symbol +, one symbol *, and one symbol -:
|
||||
if(d[0] * d[1] + d[2] - d[3] == gameGoal) printOperation("", " * ", " + ", " - ");
|
||||
if(d[0] * (d[1] + d[2]) - d[3] == gameGoal) printOperation("", " * ( ", " + ", " ) - ");
|
||||
if(d[0] * (d[1] - d[2]) + d[3] == gameGoal) printOperation("", " * ( ", " - ", " ) + ");
|
||||
if(d[0] * (d[1] + d[2] - d[3]) == gameGoal) printOperation("", " * ( ", " + ", " - ", " )");
|
||||
if(d[0] * d[1] - (d[2] + d[3]) == gameGoal) printOperation("", " * ", " - ( ", " + ", " )");
|
||||
// Operations with one symbol *, one symbol /, one symbol +:
|
||||
if(d[0] * d[1] == (gameGoal - d[3]) * d[2]) printOperation("( ", " * ", " / ", " ) + ");
|
||||
if(((d[0] * d[1]) + d[2]) == gameGoal * d[3]) printOperation("(( ", " * ", " ) + ", " ) / ");
|
||||
if((d[0] + d[1]) * d[2] == gameGoal * d[3]) printOperation("(( ", " + ", " ) * ", " ) / ");
|
||||
if(d[0] * d[1] == gameGoal * (d[2] + d[3])) printOperation("( ", " * ", " ) / ( ", " + ", " )");
|
||||
// Operations with one symbol *, one symbol /, one symbol -:
|
||||
if(d[0] * d[1] == (gameGoal + d[3]) * d[2]) printOperation("( ", " * ", " / ", " ) - ");
|
||||
if(((d[0] * d[1]) - d[2]) == gameGoal * d[3]) printOperation("(( ", " * ", " ) - ", " ) / ");
|
||||
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[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;
|
||||
}
|
||||
315
Task/24-game-Solve/C-sharp/24-game-solve.cs
Normal file
315
Task/24-game-Solve/C-sharp/24-game-solve.cs
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
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}")}";
|
||||
}
|
||||
}
|
||||
83
Task/24-game-Solve/C/24-game-solve.c
Normal file
83
Task/24-game-Solve/C/24-game-solve.c
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#include <stdio.h>
|
||||
|
||||
typedef struct {int val, op, left, right;} Node;
|
||||
|
||||
Node nodes[10000];
|
||||
int iNodes;
|
||||
|
||||
int b;
|
||||
float eval(Node x){
|
||||
if (x.op != -1){
|
||||
float l = eval(nodes[x.left]), r = eval(nodes[x.right]);
|
||||
switch(x.op){
|
||||
case 0: return l+r;
|
||||
case 1: return l-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.;
|
||||
}
|
||||
|
||||
void show(Node x){
|
||||
if (x.op != -1){
|
||||
printf("(");
|
||||
switch(x.op){
|
||||
case 0: show(nodes[x.left]); printf(" + "); show(nodes[x.right]); break;
|
||||
case 1: show(nodes[x.left]); printf(" - "); show(nodes[x.right]); break;
|
||||
case 2: show(nodes[x.right]); printf(" - "); 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;
|
||||
case 5: show(nodes[x.right]); printf(" / "); show(nodes[x.left]); break;
|
||||
}
|
||||
printf(")");
|
||||
}
|
||||
else printf("%d", x.val);
|
||||
}
|
||||
|
||||
int float_fix(float x){ return x < 0.00001 && x > -0.00001; }
|
||||
|
||||
void solutions(int a[], int n, float t, int s){
|
||||
if (s == n){
|
||||
b = 0;
|
||||
float e = eval(nodes[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(){
|
||||
// define problem
|
||||
|
||||
int a[4] = {8, 3, 8, 3};
|
||||
float t = 24;
|
||||
|
||||
// print all solutions
|
||||
|
||||
nodes[0] = (typeof(Node)){a[0],-1,-1,-1};
|
||||
iNodes = 1;
|
||||
|
||||
solutions(a, sizeof(a)/sizeof(int), t, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
446
Task/24-game-Solve/COBOL/24-game-solve.cobol
Normal file
446
Task/24-game-Solve/COBOL/24-game-solve.cobol
Normal file
|
|
@ -0,0 +1,446 @@
|
|||
>>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.
|
||||
133
Task/24-game-Solve/Ceylon/24-game-solve.ceylon
Normal file
133
Task/24-game-Solve/Ceylon/24-game-solve.ceylon
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
25
Task/24-game-Solve/Clojure/24-game-solve.clj
Normal file
25
Task/24-game-Solve/Clojure/24-game-solve.clj
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
(ns rosettacode.24game.solve
|
||||
(:require [clojure.math.combinatorics :as c]
|
||||
[clojure.walk :as w]))
|
||||
|
||||
(def ^:private op-maps
|
||||
(map #(zipmap [:o1 :o2 :o3] %) (c/selections '(* + - /) 3)))
|
||||
|
||||
(def ^:private patterns '(
|
||||
(:o1 (:o2 :n1 :n2) (:o3 :n3 :n4))
|
||||
(:o1 :n1 (:o2 :n2 (:o3 :n3 :n4)))
|
||||
(:o1 (:o2 (:o3 :n1 :n2) :n3) :n4)))
|
||||
|
||||
(defn play24 [& digits]
|
||||
{:pre (and (every? #(not= 0 %) digits)
|
||||
(= (count digits) 4))}
|
||||
(->> (for [:let [digit-maps
|
||||
(->> digits sort c/permutations
|
||||
(map #(zipmap [:n1 :n2 :n3 :n4] %)))]
|
||||
om op-maps, dm digit-maps]
|
||||
(w/prewalk-replace dm
|
||||
(w/prewalk-replace om patterns)))
|
||||
(filter #(= (eval %) 24))
|
||||
(map println)
|
||||
doall
|
||||
count))
|
||||
87
Task/24-game-Solve/CoffeeScript/24-game-solve.coffee
Normal file
87
Task/24-game-Solve/CoffeeScript/24-game-solve.coffee
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
# This program tries to find some way to turn four digits into an arithmetic
|
||||
# expression that adds up to 24.
|
||||
#
|
||||
# Example solution for 5, 7, 8, 8:
|
||||
# (((8 + 7) * 8) / 5)
|
||||
|
||||
|
||||
solve_24_game = (digits...) ->
|
||||
# Create an array of objects for our helper functions
|
||||
arr = for digit in digits
|
||||
{
|
||||
val: digit
|
||||
expr: digit
|
||||
}
|
||||
combo4 arr...
|
||||
|
||||
combo4 = (a, b, c, d) ->
|
||||
arr = [a, b, c, d]
|
||||
# Reduce this to a three-node problem by combining two
|
||||
# nodes from the array.
|
||||
permutations = [
|
||||
[0, 1, 2, 3]
|
||||
[0, 2, 1, 3]
|
||||
[0, 3, 1, 2]
|
||||
[1, 2, 0, 3]
|
||||
[1, 3, 0, 2]
|
||||
[2, 3, 0, 1]
|
||||
]
|
||||
for permutation in permutations
|
||||
[i, j, k, m] = permutation
|
||||
for combo in combos arr[i], arr[j]
|
||||
answer = combo3 combo, arr[k], arr[m]
|
||||
return answer if answer
|
||||
null
|
||||
|
||||
combo3 = (a, b, c) ->
|
||||
arr = [a, b, c]
|
||||
permutations = [
|
||||
[0, 1, 2]
|
||||
[0, 2, 1]
|
||||
[1, 2, 0]
|
||||
]
|
||||
for permutation in permutations
|
||||
[i, j, k] = permutation
|
||||
for combo in combos arr[i], arr[j]
|
||||
answer = combo2 combo, arr[k]
|
||||
return answer if answer
|
||||
null
|
||||
|
||||
combo2 = (a, b) ->
|
||||
for combo in combos a, b
|
||||
return combo.expr if combo.val == 24
|
||||
null
|
||||
|
||||
combos = (a, b) ->
|
||||
[
|
||||
val: a.val + b.val
|
||||
expr: "(#{a.expr} + #{b.expr})"
|
||||
,
|
||||
val: a.val * b.val
|
||||
expr: "(#{a.expr} * #{b.expr})"
|
||||
,
|
||||
val: a.val - b.val
|
||||
expr: "(#{a.expr} - #{b.expr})"
|
||||
,
|
||||
val: b.val - a.val
|
||||
expr: "(#{b.expr} - #{a.expr})"
|
||||
,
|
||||
val: a.val / b.val
|
||||
expr: "(#{a.expr} / #{b.expr})"
|
||||
,
|
||||
val: b.val / a.val
|
||||
expr: "(#{b.expr} / #{a.expr})"
|
||||
,
|
||||
]
|
||||
|
||||
# test
|
||||
do ->
|
||||
rand_digit = -> 1 + Math.floor (9 * Math.random())
|
||||
|
||||
for i in [1..15]
|
||||
a = rand_digit()
|
||||
b = rand_digit()
|
||||
c = rand_digit()
|
||||
d = rand_digit()
|
||||
solution = solve_24_game a, b, c, d
|
||||
console.log "Solution for #{[a,b,c,d]}: #{solution ? 'no solution'}"
|
||||
56
Task/24-game-Solve/Common-Lisp/24-game-solve.lisp
Normal file
56
Task/24-game-Solve/Common-Lisp/24-game-solve.lisp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
(defconstant +ops+ '(* / + -))
|
||||
|
||||
(defun digits ()
|
||||
(sort (loop repeat 4 collect (1+ (random 9))) #'<))
|
||||
|
||||
(defun expr-value (expr)
|
||||
(eval expr))
|
||||
|
||||
(defun divides-by-zero-p (expr)
|
||||
(when (consp expr)
|
||||
(destructuring-bind (op &rest args) expr
|
||||
(or (divides-by-zero-p (car args))
|
||||
(and (eq op '/)
|
||||
(or (and (= 1 (length args))
|
||||
(zerop (expr-value (car args))))
|
||||
(some (lambda (arg)
|
||||
(or (divides-by-zero-p arg)
|
||||
(zerop (expr-value arg))))
|
||||
(cdr args))))))))
|
||||
|
||||
(defun solvable-p (digits &optional expr)
|
||||
(unless (divides-by-zero-p expr)
|
||||
(if digits
|
||||
(destructuring-bind (next &rest rest) digits
|
||||
(if expr
|
||||
(some (lambda (op)
|
||||
(solvable-p rest (cons op (list next expr))))
|
||||
+ops+)
|
||||
(solvable-p rest (list (car +ops+) next))))
|
||||
(when (and expr
|
||||
(eql 24 (expr-value expr)))
|
||||
(merge-exprs expr)))))
|
||||
|
||||
(defun merge-exprs (expr)
|
||||
(if (atom expr)
|
||||
expr
|
||||
(destructuring-bind (op &rest args) expr
|
||||
(if (and (member op '(* +))
|
||||
(= 1 (length args)))
|
||||
(car args)
|
||||
(cons op
|
||||
(case op
|
||||
((* +)
|
||||
(loop for arg in args
|
||||
for merged = (merge-exprs arg)
|
||||
when (and (consp merged)
|
||||
(eq op (car merged)))
|
||||
append (cdr merged)
|
||||
else collect merged))
|
||||
(t (mapcar #'merge-exprs args))))))))
|
||||
|
||||
(defun solve-24-game (digits)
|
||||
"Generate a lisp form using the operators in +ops+ and the given
|
||||
digits which evaluates to 24. The first form found is returned, or
|
||||
NIL if there is no solution."
|
||||
(solvable-p digits))
|
||||
36
Task/24-game-Solve/D/24-game-solve.d
Normal file
36
Task/24-game-Solve/D/24-game-solve.d
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import std.stdio, std.algorithm, std.range, std.conv, std.string,
|
||||
std.concurrency, permutations2, arithmetic_rational;
|
||||
|
||||
string solve(in int target, in int[] problem) {
|
||||
static struct T { Rational r; string e; }
|
||||
|
||||
Generator!T computeAllOperations(in Rational[] L) {
|
||||
return new typeof(return)({
|
||||
if (!L.empty) {
|
||||
immutable x = L[0];
|
||||
if (L.length == 1) {
|
||||
yield(T(x, x.text));
|
||||
} else {
|
||||
foreach (const o; computeAllOperations(L.dropOne)) {
|
||||
immutable y = o.r;
|
||||
auto sub = [T(x * y, "*"), T(x + y, "+"), T(x - y, "-")];
|
||||
if (y) sub ~= [T(x / y, "/")];
|
||||
foreach (const e; sub)
|
||||
yield(T(e.r, format("(%s%s%s)", x, e.e, o.e)));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
foreach (const p; problem.map!Rational.array.permutations!false)
|
||||
foreach (const sol; computeAllOperations(p))
|
||||
if (sol.r == target)
|
||||
return sol.e;
|
||||
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));
|
||||
}
|
||||
311
Task/24-game-Solve/ERRE/24-game-solve.erre
Normal file
311
Task/24-game-Solve/ERRE/24-game-solve.erre
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
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
|
||||
111
Task/24-game-Solve/EchoLisp/24-game-solve.l
Normal file
111
Task/24-game-Solve/EchoLisp/24-game-solve.l
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
;; 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))
|
||||
46
Task/24-game-Solve/Elixir/24-game-solve.elixir
Normal file
46
Task/24-game-Solve/Elixir/24-game-solve.elixir
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
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
|
||||
22
Task/24-game-Solve/Euler/24-game-solve-1.euler
Normal file
22
Task/24-game-Solve/Euler/24-game-solve-1.euler
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
>function try24 (v) ...
|
||||
$n=cols(v);
|
||||
$if n==1 and v[1]~=24 then
|
||||
$ "Solved the problem",
|
||||
$ return 1;
|
||||
$endif
|
||||
$loop 1 to n
|
||||
$ w=tail(v,2);
|
||||
$ loop 1 to n-1
|
||||
$ h=w; a=v[1]; b=w[1];
|
||||
$ w[1]=a+b; if try24(w); ""+a+"+"+b+"="+(a+b), return 1; endif;
|
||||
$ w[1]=a-b; if try24(w); ""+a+"-"+b+"="+(a-b), return 1; endif;
|
||||
$ w[1]=a*b; if try24(w); ""+a+"*"+b+"="+(a*b), return 1; endif;
|
||||
$ if not b~=0 then
|
||||
$ w[1]=a/b; if try24(w); ""+a+"/"+b+"="+(a/b), return 1; endif;
|
||||
$ endif;
|
||||
$ w=rotright(w);
|
||||
$ end;
|
||||
$ v=rotright(v);
|
||||
$end;
|
||||
$return 0;
|
||||
$endfunction
|
||||
20
Task/24-game-Solve/Euler/24-game-solve-2.euler
Normal file
20
Task/24-game-Solve/Euler/24-game-solve-2.euler
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
>try24([1,2,3,4]);
|
||||
Solved the problem
|
||||
6*4=24
|
||||
3+3=6
|
||||
1+2=3
|
||||
>try24([8,7,7,1]);
|
||||
Solved the problem
|
||||
22+2=24
|
||||
14+8=22
|
||||
7+7=14
|
||||
>try24([8,4,7,1]);
|
||||
Solved the problem
|
||||
6*4=24
|
||||
7-1=6
|
||||
8-4=4
|
||||
>try24([3,4,5,6]);
|
||||
Solved the problem
|
||||
4*6=24
|
||||
-1+5=4
|
||||
3-4=-1
|
||||
109
Task/24-game-Solve/F-Sharp/24-game-solve.fs
Normal file
109
Task/24-game-Solve/F-Sharp/24-game-solve.fs
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
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)
|
||||
let abs (x : int) = Math.Abs x
|
||||
let sign (x: int) = Math.Sign x
|
||||
let cint s = Int32.Parse(s)
|
||||
|
||||
type Rat(x : int, y : int) =
|
||||
let g = if y = 0 then 0 else gcd (abs x) (abs y)
|
||||
member this.n = if g = 0 then sign y * sign x else sign y * x / g // store a minus sign in the numerator
|
||||
member this.d =
|
||||
if y = 0 then 0 else sign y * y / g
|
||||
static member (~-) (x : Rat) = Rat(-x.n, x.d)
|
||||
static member (+) (x : Rat, y : Rat) = Rat(x.n * y.d + y.n * x.d, x.d * y.d)
|
||||
static member (-) (x : Rat, y : Rat) = x + Rat(-y.n, y.d)
|
||||
static member (*) (x : Rat, y : Rat) = Rat(x.n * y.n, x.d * y.d)
|
||||
static member (/) (x : Rat, y : Rat) = x * Rat(y.d, y.n)
|
||||
interface System.IComparable with
|
||||
member this.CompareTo o =
|
||||
match o with
|
||||
| :? Rat as that -> compare (this.n * that.d) (that.n * this.d)
|
||||
| _ -> invalidArg "o" "cannot compare values of differnet types."
|
||||
override this.Equals(o) =
|
||||
match o with
|
||||
| :? Rat as that -> this.n = that.n && this.d = that.d
|
||||
| _ -> false
|
||||
override this.ToString() =
|
||||
if this.d = 1 then this.n.ToString()
|
||||
else sprintf @"<%d,%d>" this.n this.d
|
||||
new(x : string, y : string) = if y = "" then Rat(cint x, 1) else Rat(cint x, cint y)
|
||||
|
||||
type expression =
|
||||
| Const of Rat
|
||||
| Sum of expression * expression
|
||||
| Diff of expression * expression
|
||||
| Prod of expression * expression
|
||||
| Quot of expression * expression
|
||||
|
||||
let rec eval = function
|
||||
| Const c -> c
|
||||
| Sum (f, g) -> eval f + eval g
|
||||
| Diff(f, g) -> eval f - eval g
|
||||
| Prod(f, g) -> eval f * eval g
|
||||
| Quot(f, g) -> eval f / eval g
|
||||
|
||||
let print_expr expr =
|
||||
let concat (s : seq<string>) = System.String.Concat s
|
||||
let paren p prec op_prec = if prec > op_prec then p else ""
|
||||
let rec print prec = function
|
||||
| Const c -> c.ToString()
|
||||
| Sum(f, g) ->
|
||||
concat [ (paren "(" prec 0); (print 0 f); " + "; (print 0 g); (paren ")" prec 0) ]
|
||||
| Diff(f, g) ->
|
||||
concat [ (paren "(" prec 0); (print 0 f); " - "; (print 1 g); (paren ")" prec 0) ]
|
||||
| Prod(f, g) ->
|
||||
concat [ (paren "(" prec 2); (print 2 f); " * "; (print 2 g); (paren ")" prec 2) ]
|
||||
| Quot(f, g) ->
|
||||
concat [ (paren "(" prec 2); (print 2 f); " / "; (print 3 g); (paren ")" prec 2) ]
|
||||
print 0 expr
|
||||
|
||||
let rec normal expr =
|
||||
let norm epxr =
|
||||
match expr with
|
||||
| Sum(x, y) -> if eval x <= eval y then expr else Sum(normal y, normal x)
|
||||
| Prod(x, y) -> if eval x <= eval y then expr else Prod(normal y, normal x)
|
||||
| _ -> expr
|
||||
match expr with
|
||||
| Const c -> expr
|
||||
| Sum(x, y) -> norm (Sum(normal x, normal y))
|
||||
| Prod(x, y) -> norm (Prod(normal x, normal y))
|
||||
| Diff(x, y) -> Diff(normal x, normal y)
|
||||
| Quot(x, y) -> Quot(normal x, normal y)
|
||||
|
||||
let rec insert v = function
|
||||
| [] -> [[v]]
|
||||
| x::xs as li -> (v::li) :: (List.map (fun y -> x::y) (insert v xs))
|
||||
|
||||
let permutations li =
|
||||
List.foldBack (fun x z -> List.concat (List.map (insert x) z)) li [[]]
|
||||
|
||||
let rec comp expr rest = seq {
|
||||
match rest with
|
||||
| x::xs ->
|
||||
yield! comp (Sum (expr, x)) xs;
|
||||
yield! comp (Diff(x, expr)) xs;
|
||||
yield! comp (Diff(expr, x)) xs;
|
||||
yield! comp (Prod(expr, x)) xs;
|
||||
yield! comp (Quot(x, expr)) xs;
|
||||
yield! comp (Quot(expr, x)) xs;
|
||||
| [] -> if eval expr = Rat(24,1) then yield print_expr (normal expr)
|
||||
}
|
||||
|
||||
[<EntryPoint>]
|
||||
let main argv =
|
||||
let digits = List.init 4 (fun i -> Const (Rat(argv.[i],"")))
|
||||
let solutions =
|
||||
permutations digits
|
||||
|> Seq.groupBy (sprintf "%A")
|
||||
|> Seq.map snd |> Seq.map Seq.head
|
||||
|> Seq.map (fun x -> comp (List.head x) (List.tail x))
|
||||
|> Seq.choose (fun x -> if Seq.isEmpty x then None else Some x)
|
||||
|> Seq.concat
|
||||
if Seq.isEmpty solutions then
|
||||
printfn "No solutions."
|
||||
else
|
||||
solutions
|
||||
|> Seq.groupBy id
|
||||
|> Seq.iter (fun x -> printfn "%s" (fst x))
|
||||
0
|
||||
18
Task/24-game-Solve/Factor/24-game-solve.factor
Normal file
18
Task/24-game-Solve/Factor/24-game-solve.factor
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
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
|
||||
69
Task/24-game-Solve/Fortran/24-game-solve-1.f
Normal file
69
Task/24-game-Solve/Fortran/24-game-solve-1.f
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
program solve_24
|
||||
use helpers
|
||||
implicit none
|
||||
real :: vector(4), reals(4), p, q, r, s
|
||||
integer :: numbers(4), n, i, j, k, a, b, c, d
|
||||
character, parameter :: ops(4) = (/ '+', '-', '*', '/' /)
|
||||
logical :: last
|
||||
real,parameter :: eps = epsilon(1.0)
|
||||
|
||||
do n=1,12
|
||||
call random_number(vector)
|
||||
reals = 9 * vector + 1
|
||||
numbers = int(reals)
|
||||
call Insertion_Sort(numbers)
|
||||
|
||||
permutations: do
|
||||
a = numbers(1); b = numbers(2); c = numbers(3); d = numbers(4)
|
||||
reals = real(numbers)
|
||||
p = reals(1); q = reals(2); r = reals(3); s = reals(4)
|
||||
! combinations of operators:
|
||||
do i=1,4
|
||||
do j=1,4
|
||||
do k=1,4
|
||||
if ( abs(op(op(op(p,i,q),j,r),k,s)-24.0) < eps ) then
|
||||
write (*,*) numbers, ' : ', '((',a,ops(i),b,')',ops(j),c,')',ops(k),d
|
||||
exit permutations
|
||||
else if ( abs(op(op(p,i,op(q,j,r)),k,s)-24.0) < eps ) then
|
||||
write (*,*) numbers, ' : ', '(',a,ops(i),'(',b,ops(j),c,'))',ops(k),d
|
||||
exit permutations
|
||||
else if ( abs(op(p,i,op(op(q,j,r),k,s))-24.0) < eps ) then
|
||||
write (*,*) numbers, ' : ', a,ops(i),'((',b,ops(j),c,')',ops(k),d,')'
|
||||
exit permutations
|
||||
else if ( abs(op(p,i,op(q,j,op(r,k,s)))-24.0) < eps ) then
|
||||
write (*,*) numbers, ' : ', a,ops(i),'(',b,ops(j),'(',c,ops(k),d,'))'
|
||||
exit permutations
|
||||
else if ( abs(op(op(p,i,q),j,op(r,k,s))-24.0) < eps ) then
|
||||
write (*,*) numbers, ' : ', '(',a,ops(i),b,')',ops(j),'(',c,ops(k),d,')'
|
||||
exit permutations
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
end do
|
||||
call nextpermutation(numbers,last)
|
||||
if ( last ) then
|
||||
write (*,*) numbers, ' : no solution.'
|
||||
exit permutations
|
||||
end if
|
||||
end do permutations
|
||||
|
||||
end do
|
||||
|
||||
contains
|
||||
|
||||
pure real function op(x,c,y)
|
||||
integer, intent(in) :: c
|
||||
real, intent(in) :: x,y
|
||||
select case ( ops(c) )
|
||||
case ('+')
|
||||
op = x+y
|
||||
case ('-')
|
||||
op = x-y
|
||||
case ('*')
|
||||
op = x*y
|
||||
case ('/')
|
||||
op = x/y
|
||||
end select
|
||||
end function op
|
||||
|
||||
end program solve_24
|
||||
72
Task/24-game-Solve/Fortran/24-game-solve-2.f
Normal file
72
Task/24-game-Solve/Fortran/24-game-solve-2.f
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
module helpers
|
||||
|
||||
contains
|
||||
|
||||
pure subroutine Insertion_Sort(a)
|
||||
integer, intent(inout) :: a(:)
|
||||
integer :: temp, i, j
|
||||
do i=2,size(a)
|
||||
j = i-1
|
||||
temp = a(i)
|
||||
do while ( j>=1 .and. a(j)>temp )
|
||||
a(j+1) = a(j)
|
||||
j = j - 1
|
||||
end do
|
||||
a(j+1) = temp
|
||||
end do
|
||||
end subroutine Insertion_Sort
|
||||
|
||||
subroutine nextpermutation(perm,last)
|
||||
integer, intent(inout) :: perm(:)
|
||||
logical, intent(out) :: last
|
||||
integer :: k,l
|
||||
k = largest1()
|
||||
last = k == 0
|
||||
if ( .not. last ) then
|
||||
l = largest2(k)
|
||||
call swap(l,k)
|
||||
call reverse(k)
|
||||
end if
|
||||
contains
|
||||
pure integer function largest1()
|
||||
integer :: k, max
|
||||
max = 0
|
||||
do k=1,size(perm)-1
|
||||
if ( perm(k) < perm(k+1) ) then
|
||||
max = k
|
||||
end if
|
||||
end do
|
||||
largest1 = max
|
||||
end function largest1
|
||||
|
||||
pure integer function largest2(k)
|
||||
integer, intent(in) :: k
|
||||
integer :: l, max
|
||||
max = k+1
|
||||
do l=k+2,size(perm)
|
||||
if ( perm(k) < perm(l) ) then
|
||||
max = l
|
||||
end if
|
||||
end do
|
||||
largest2 = max
|
||||
end function largest2
|
||||
|
||||
subroutine swap(l,k)
|
||||
integer, intent(in) :: k,l
|
||||
integer :: temp
|
||||
temp = perm(k)
|
||||
perm(k) = perm(l)
|
||||
perm(l) = temp
|
||||
end subroutine swap
|
||||
|
||||
subroutine reverse(k)
|
||||
integer, intent(in) :: k
|
||||
integer :: i
|
||||
do i=1,(size(perm)-k)/2
|
||||
call swap(k+i,size(perm)+1-i)
|
||||
end do
|
||||
end subroutine reverse
|
||||
|
||||
end subroutine nextpermutation
|
||||
|
||||
end module helpers
|
||||
84
Task/24-game-Solve/GAP/24-game-solve.gap
Normal file
84
Task/24-game-Solve/GAP/24-game-solve.gap
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# Solution in '''RPN'''
|
||||
check := function(x, y, z)
|
||||
local r, c, s, i, j, k, a, b, p;
|
||||
i := 0;
|
||||
j := 0;
|
||||
k := 0;
|
||||
s := [ ];
|
||||
r := "";
|
||||
for c in z do
|
||||
if c = 'x' then
|
||||
i := i + 1;
|
||||
k := k + 1;
|
||||
s[k] := x[i];
|
||||
Append(r, String(x[i]));
|
||||
else
|
||||
j := j + 1;
|
||||
b := s[k];
|
||||
k := k - 1;
|
||||
a := s[k];
|
||||
p := y[j];
|
||||
r[Size(r) + 1] := p;
|
||||
if p = '+' then
|
||||
a := a + b;
|
||||
elif p = '-' then
|
||||
a := a - b;
|
||||
elif p = '*' then
|
||||
a := a * b;
|
||||
elif p = '/' then
|
||||
if b = 0 then
|
||||
continue;
|
||||
else
|
||||
a := a / b;
|
||||
fi;
|
||||
else
|
||||
return fail;
|
||||
fi;
|
||||
s[k] := a;
|
||||
fi;
|
||||
od;
|
||||
if s[1] = 24 then
|
||||
return r;
|
||||
else
|
||||
return fail;
|
||||
fi;
|
||||
end;
|
||||
|
||||
Player24 := function(digits)
|
||||
local u, v, w, x, y, z, r;
|
||||
u := PermutationsList(digits);
|
||||
v := Tuples("+-*/", 3);
|
||||
w := ["xx*x*x*", "xx*xx**", "xxx**x*", "xxx*x**", "xxxx***"];
|
||||
for x in u do
|
||||
for y in v do
|
||||
for z in w do
|
||||
r := check(x, y, z);
|
||||
if r <> fail then
|
||||
return r;
|
||||
fi;
|
||||
od;
|
||||
od;
|
||||
od;
|
||||
return fail;
|
||||
end;
|
||||
|
||||
Player24([1,2,7,7]);
|
||||
# "77*1-2/"
|
||||
Player24([9,8,7,6]);
|
||||
# "68*97-/"
|
||||
Player24([1,1,7,7]);
|
||||
# fail
|
||||
|
||||
# Solutions with only one distinct digit are found only for 3, 4, 5, 6:
|
||||
Player24([3,3,3,3]);
|
||||
# "33*3*3-"
|
||||
Player24([4,4,4,4]);
|
||||
# "44*4+4+"
|
||||
Player24([5,5,5,5]);
|
||||
# "55*55/-"
|
||||
Player24([6,6,6,6]);
|
||||
# "66*66+-"
|
||||
|
||||
# A tricky one:
|
||||
Player24([3,3,8,8]);
|
||||
"8383/-/"
|
||||
171
Task/24-game-Solve/Go/24-game-solve.go
Normal file
171
Task/24-game-Solve/Go/24-game-solve.go
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
op_num = iota
|
||||
op_add
|
||||
op_sub
|
||||
op_mul
|
||||
op_div
|
||||
)
|
||||
|
||||
type frac struct {
|
||||
num, denom int
|
||||
}
|
||||
|
||||
// Expression: can either be a single number, or a result of binary
|
||||
// operation from left and right node
|
||||
type Expr struct {
|
||||
op int
|
||||
left, right *Expr
|
||||
value frac
|
||||
}
|
||||
|
||||
var n_cards = 4
|
||||
var goal = 24
|
||||
var digit_range = 9
|
||||
|
||||
func (x *Expr) String() string {
|
||||
if x.op == op_num {
|
||||
return fmt.Sprintf("%d", x.value.num)
|
||||
}
|
||||
|
||||
var bl1, br1, bl2, br2, opstr string
|
||||
switch {
|
||||
case x.left.op == op_num:
|
||||
case x.left.op >= x.op:
|
||||
case x.left.op == op_add && x.op == op_sub:
|
||||
bl1, br1 = "", ""
|
||||
default:
|
||||
bl1, br1 = "(", ")"
|
||||
}
|
||||
|
||||
if x.right.op == op_num || x.op < x.right.op {
|
||||
bl2, br2 = "", ""
|
||||
} else {
|
||||
bl2, br2 = "(", ")"
|
||||
}
|
||||
|
||||
switch {
|
||||
case x.op == op_add:
|
||||
opstr = " + "
|
||||
case x.op == op_sub:
|
||||
opstr = " - "
|
||||
case x.op == op_mul:
|
||||
opstr = " * "
|
||||
case x.op == op_div:
|
||||
opstr = " / "
|
||||
}
|
||||
|
||||
return bl1 + x.left.String() + br1 + opstr +
|
||||
bl2 + x.right.String() + br2
|
||||
}
|
||||
|
||||
func expr_eval(x *Expr) (f frac) {
|
||||
if x.op == op_num {
|
||||
return x.value
|
||||
}
|
||||
|
||||
l, r := expr_eval(x.left), expr_eval(x.right)
|
||||
|
||||
switch x.op {
|
||||
case op_add:
|
||||
f.num = l.num*r.denom + l.denom*r.num
|
||||
f.denom = l.denom * r.denom
|
||||
return
|
||||
|
||||
case op_sub:
|
||||
f.num = l.num*r.denom - l.denom*r.num
|
||||
f.denom = l.denom * r.denom
|
||||
return
|
||||
|
||||
case op_mul:
|
||||
f.num = l.num * r.num
|
||||
f.denom = l.denom * r.denom
|
||||
return
|
||||
|
||||
case op_div:
|
||||
f.num = l.num * r.denom
|
||||
f.denom = l.denom * r.num
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func solve(ex_in []*Expr) bool {
|
||||
// only one expression left, meaning all numbers are arranged into
|
||||
// a binary tree, so evaluate and see if we get 24
|
||||
if len(ex_in) == 1 {
|
||||
f := expr_eval(ex_in[0])
|
||||
if f.denom != 0 && f.num == f.denom*goal {
|
||||
fmt.Println(ex_in[0].String())
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var node Expr
|
||||
ex := make([]*Expr, len(ex_in)-1)
|
||||
|
||||
// try to combine a pair of expressions into one, thus reduce
|
||||
// the list length by 1, and recurse down
|
||||
for i := range ex {
|
||||
copy(ex[i:len(ex)], ex_in[i+1:len(ex_in)])
|
||||
|
||||
ex[i] = &node
|
||||
for j := i + 1; j < len(ex_in); j++ {
|
||||
node.left = ex_in[i]
|
||||
node.right = ex_in[j]
|
||||
|
||||
// try all 4 operators
|
||||
for o := op_add; o <= op_div; o++ {
|
||||
node.op = o
|
||||
if solve(ex) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// also - and / are not commutative, so swap arguments
|
||||
node.left = ex_in[j]
|
||||
node.right = ex_in[i]
|
||||
|
||||
node.op = op_sub
|
||||
if solve(ex) {
|
||||
return true
|
||||
}
|
||||
|
||||
node.op = op_div
|
||||
if solve(ex) {
|
||||
return true
|
||||
}
|
||||
|
||||
if j < len(ex) {
|
||||
ex[j] = ex_in[j]
|
||||
}
|
||||
}
|
||||
ex[i] = ex_in[i]
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func main() {
|
||||
cards := make([]*Expr, n_cards)
|
||||
rand.Seed(time.Now().Unix())
|
||||
|
||||
for k := 0; k < 10; k++ {
|
||||
for i := 0; i < n_cards; i++ {
|
||||
cards[i] = &Expr{op_num, nil, nil,
|
||||
frac{rand.Intn(digit_range-1) + 1, 1}}
|
||||
fmt.Printf(" %d", cards[i].value.num)
|
||||
}
|
||||
fmt.Print(": ")
|
||||
if !solve(cards) {
|
||||
fmt.Println("No solution")
|
||||
}
|
||||
}
|
||||
}
|
||||
110
Task/24-game-Solve/Gosu/24-game-solve.gosu
Normal file
110
Task/24-game-Solve/Gosu/24-game-solve.gosu
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
uses java.lang.Integer
|
||||
uses java.lang.Double
|
||||
uses java.lang.System
|
||||
uses java.util.ArrayList
|
||||
uses java.util.LinkedList
|
||||
uses java.util.List
|
||||
uses java.util.Scanner
|
||||
uses java.util.Stack
|
||||
|
||||
function permutations<T>( lst : List<T> ) : List<List<T>> {
|
||||
if( lst.size() == 0 ) return {}
|
||||
if( lst.size() == 1 ) return { lst }
|
||||
|
||||
var pivot = lst.get(lst.size()-1)
|
||||
|
||||
var sublist = new ArrayList<T>( lst )
|
||||
sublist.remove( sublist.size() - 1 )
|
||||
|
||||
var subPerms = permutations( sublist )
|
||||
|
||||
var ret = new ArrayList<List<T>>()
|
||||
for( x in subPerms ) {
|
||||
for( e in x index i ) {
|
||||
var next = new LinkedList<T>( x )
|
||||
next.add( i, pivot )
|
||||
ret.add( next )
|
||||
}
|
||||
x.add( pivot )
|
||||
ret.add( x )
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
function readVals() : List<Integer> {
|
||||
var line = new java.io.BufferedReader( new java.io.InputStreamReader( System.in ) ).readLine()
|
||||
var scan = new Scanner( line )
|
||||
|
||||
var ret = new ArrayList<Integer>()
|
||||
for( i in 0..3 ) {
|
||||
var next = scan.nextInt()
|
||||
if( 0 >= next || next >= 10 ) {
|
||||
print( "Invalid entry: ${next}" )
|
||||
return null
|
||||
}
|
||||
ret.add( next )
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
function getOp( i : int ) : char[] {
|
||||
var ret = new char[3]
|
||||
var ops = { '+', '-', '*', '/' }
|
||||
ret[0] = ops[i / 16]
|
||||
ret[1] = ops[(i / 4) % 4 ]
|
||||
ret[2] = ops[i % 4 ]
|
||||
return ret
|
||||
}
|
||||
|
||||
function isSoln( nums : List<Integer>, ops : char[] ) : boolean {
|
||||
var stk = new Stack<Double>()
|
||||
for( n in nums ) {
|
||||
stk.push( n )
|
||||
}
|
||||
|
||||
for( c in ops ) {
|
||||
var r = stk.pop().doubleValue()
|
||||
var l = stk.pop().doubleValue()
|
||||
if( c == '+' ) {
|
||||
stk.push( l + r )
|
||||
} else if( c == '-' ) {
|
||||
stk.push( l - r )
|
||||
} else if( c == '*' ) {
|
||||
stk.push( l * r )
|
||||
} else if( c == '/' ) {
|
||||
// Avoid division by 0
|
||||
if( r == 0.0 ) {
|
||||
return false
|
||||
}
|
||||
stk.push( l / r )
|
||||
}
|
||||
}
|
||||
|
||||
return java.lang.Math.abs( stk.pop().doubleValue() - 24.0 ) < 0.001
|
||||
}
|
||||
|
||||
function printSoln( nums : List<Integer>, ops : char[] ) {
|
||||
// RPN: a b c d + - *
|
||||
// Infix (a * (b - (c + d)))
|
||||
print( "Found soln: (${nums.get(0)} ${ops[0]} (${nums.get(1)} ${ops[1]} (${nums.get(2)} ${ops[2]} ${nums.get(3)})))" )
|
||||
}
|
||||
|
||||
System.out.print( "#> " )
|
||||
var vals = readVals()
|
||||
|
||||
var opPerms = 0..63
|
||||
var solnFound = false
|
||||
|
||||
for( i in permutations( vals ) ) {
|
||||
for( j in opPerms ) {
|
||||
var opList = getOp( j )
|
||||
if( isSoln( i, opList ) ) {
|
||||
printSoln( i, opList )
|
||||
solnFound = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( ! solnFound ) {
|
||||
print( "No solution!" )
|
||||
}
|
||||
50
Task/24-game-Solve/Haskell/24-game-solve-1.hs
Normal file
50
Task/24-game-Solve/Haskell/24-game-solve-1.hs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import Data.List
|
||||
import Data.Ratio
|
||||
import Control.Monad
|
||||
import System.Environment (getArgs)
|
||||
|
||||
data Expr = Constant Rational |
|
||||
Expr :+ Expr | Expr :- Expr |
|
||||
Expr :* Expr | Expr :/ Expr
|
||||
deriving (Eq)
|
||||
|
||||
ops = [(:+), (:-), (:*), (:/)]
|
||||
|
||||
instance Show Expr where
|
||||
show (Constant x) = show $ numerator x
|
||||
-- In this program, we need only print integers.
|
||||
show (a :+ b) = strexp "+" a b
|
||||
show (a :- b) = strexp "-" a b
|
||||
show (a :* b) = strexp "*" a b
|
||||
show (a :/ b) = strexp "/" a b
|
||||
|
||||
strexp :: String -> Expr -> Expr -> String
|
||||
strexp op a b = "(" ++ show a ++ " " ++ op ++ " " ++ show b ++ ")"
|
||||
|
||||
templates :: [[Expr] -> Expr]
|
||||
templates = do
|
||||
op1 <- ops
|
||||
op2 <- ops
|
||||
op3 <- ops
|
||||
[\[a, b, c, d] -> op1 a $ op2 b $ op3 c d,
|
||||
\[a, b, c, d] -> op1 (op2 a b) $ op3 c d,
|
||||
\[a, b, c, d] -> op1 a $ op2 (op3 b c) d,
|
||||
\[a, b, c, d] -> op1 (op2 a $ op3 b c) d,
|
||||
\[a, b, c, d] -> op1 (op2 (op3 a b) c) d]
|
||||
|
||||
eval :: Expr -> Maybe Rational
|
||||
eval (Constant c) = Just c
|
||||
eval (a :+ b) = liftM2 (+) (eval a) (eval b)
|
||||
eval (a :- b) = liftM2 (-) (eval a) (eval b)
|
||||
eval (a :* b) = liftM2 (*) (eval a) (eval b)
|
||||
eval (a :/ b) = do
|
||||
denom <- eval b
|
||||
guard $ denom /= 0
|
||||
liftM (/ denom) $ eval a
|
||||
|
||||
solve :: Rational -> [Rational] -> [Expr]
|
||||
solve target r4 = filter (maybe False (== target) . eval) $
|
||||
liftM2 ($) templates $
|
||||
nub $ permutations $ map Constant r4
|
||||
|
||||
main = getArgs >>= mapM_ print . solve 24 . map (toEnum . read)
|
||||
42
Task/24-game-Solve/Haskell/24-game-solve-2.hs
Normal file
42
Task/24-game-Solve/Haskell/24-game-solve-2.hs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import Control.Applicative
|
||||
import Data.List
|
||||
import Text.PrettyPrint
|
||||
|
||||
|
||||
data Expr = C Int | Op String Expr Expr
|
||||
|
||||
toDoc (C x ) = int x
|
||||
toDoc (Op op x y) = parens $ toDoc x <+> text op <+> toDoc y
|
||||
|
||||
ops :: [(String, Int -> Int -> Int)]
|
||||
ops = [("+",(+)), ("-",(-)), ("*",(*)), ("/",div)]
|
||||
|
||||
|
||||
solve :: Int -> [Int] -> [Expr]
|
||||
solve res = filter ((Just res ==) . eval) . genAst
|
||||
where
|
||||
genAst [x] = [C x]
|
||||
genAst xs = do
|
||||
(ys,zs) <- split xs
|
||||
let f (Op op _ _) = op `notElem` ["+","*"] || ys <= zs
|
||||
filter f $ Op <$> map fst ops <*> genAst ys <*> genAst zs
|
||||
|
||||
eval (C x ) = Just x
|
||||
eval (Op "/" _ y) | Just 0 <- eval y = Nothing
|
||||
eval (Op op x y) = lookup op ops <*> eval x <*> eval y
|
||||
|
||||
|
||||
select :: Int -> [Int] -> [[Int]]
|
||||
select 0 _ = [[]]
|
||||
select n xs = [x:zs | k <- [0..length xs - n]
|
||||
, let (x:ys) = drop k xs
|
||||
, zs <- select (n - 1) ys
|
||||
]
|
||||
|
||||
split :: [Int] -> [([Int],[Int])]
|
||||
split xs = [(ys, xs \\ ys) | n <- [1..length xs - 1]
|
||||
, ys <- nub . sort $ select n xs
|
||||
]
|
||||
|
||||
|
||||
main = mapM_ (putStrLn . render . toDoc) $ solve 24 [2,3,8,9]
|
||||
76
Task/24-game-Solve/Icon/24-game-solve.icon
Normal file
76
Task/24-game-Solve/Icon/24-game-solve.icon
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
invocable all
|
||||
link strings # for csort, deletec, permutes
|
||||
|
||||
procedure main()
|
||||
static eL
|
||||
initial {
|
||||
eoP := [] # set-up expression and operator permutation patterns
|
||||
every ( e := !["a@b#c$d", "a@(b#c)$d", "a@b#(c$d)", "a@(b#c$d)", "a@(b#(c$d))"] ) &
|
||||
( o := !(opers := "+-*/") || !opers || !opers ) do
|
||||
put( eoP, map(e,"@#$",o) ) # expr+oper perms
|
||||
|
||||
eL := [] # all cases
|
||||
every ( e := !eoP ) & ( p := permutes("wxyz") ) do
|
||||
put(eL, map(e,"abcd",p))
|
||||
|
||||
}
|
||||
|
||||
write("This will attempt to find solutions to 24 for sets of numbers by\n",
|
||||
"combining 4 single digits between 1 and 9 to make 24 using only + - * / and ( ).\n",
|
||||
"All operations have equal precedence and are evaluated left to right.\n",
|
||||
"Enter 'use n1 n2 n3 n4' or just hit enter (to use a random set),",
|
||||
"'first'/'all' shows the first or all solutions, 'quit' to end.\n\n")
|
||||
|
||||
repeat {
|
||||
e := trim(read()) | fail
|
||||
e ? case tab(find(" ")|0) of {
|
||||
"q"|"quit" : break
|
||||
"u"|"use" : e := tab(0)
|
||||
"f"|"first": first := 1 & next
|
||||
"a"|"all" : first := &null & next
|
||||
"" : e := " " ||(1+?8) || " " || (1+?8) ||" " || (1+?8) || " " || (1+?8)
|
||||
}
|
||||
|
||||
writes("Attempting to solve 24 for",e)
|
||||
|
||||
e := deletec(e,' \t') # no whitespace
|
||||
if e ? ( tab(many('123456789')), pos(5), pos(0) ) then
|
||||
write(":")
|
||||
else write(" - invalid, only the digits '1..9' are allowed.") & next
|
||||
|
||||
eS := set()
|
||||
every ex := map(!eL,"wxyz",e) do {
|
||||
if member(eS,ex) then next # skip duplicates of final expression
|
||||
insert(eS,ex)
|
||||
if ex ? (ans := eval(E()), pos(0)) then # parse and evaluate
|
||||
if ans = 24 then {
|
||||
write("Success ",image(ex)," evaluates to 24.")
|
||||
if \first then break
|
||||
}
|
||||
}
|
||||
}
|
||||
write("Quiting.")
|
||||
end
|
||||
|
||||
procedure eval(X) #: return the evaluated AST
|
||||
if type(X) == "list" then {
|
||||
x := eval(get(X))
|
||||
while o := get(X) do
|
||||
if y := get(X) then
|
||||
x := o( real(x), (o ~== "/" | fail, eval(y) ))
|
||||
else write("Malformed expression.") & fail
|
||||
}
|
||||
return \x | X
|
||||
end
|
||||
|
||||
procedure E() #: expression
|
||||
put(lex := [],T())
|
||||
while put(lex,tab(any('+-*/'))) do
|
||||
put(lex,T())
|
||||
suspend if *lex = 1 then lex[1] else lex # strip useless []
|
||||
end
|
||||
|
||||
procedure T() #: Term
|
||||
suspend 2(="(", E(), =")") | # parenthesized subexpression, or ...
|
||||
tab(any(&digits)) # just a value
|
||||
end
|
||||
9
Task/24-game-Solve/J/24-game-solve-1.j
Normal file
9
Task/24-game-Solve/J/24-game-solve-1.j
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
perm=: (A.&i.~ !) 4
|
||||
ops=: ' ',.'+-*%' {~ >,{i.each 4 4 4
|
||||
cmask=: 1 + 0j1 * i.@{:@$@[ e. ]
|
||||
left=: [ #!.'('~"1 cmask
|
||||
right=: [ #!.')'~"1 cmask
|
||||
paren=: 2 :'[: left&m right&n'
|
||||
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
|
||||
15
Task/24-game-Solve/J/24-game-solve-2.j
Normal file
15
Task/24-game-Solve/J/24-game-solve-2.j
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
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 ' '
|
||||
)
|
||||
264
Task/24-game-Solve/Java/24-game-solve.java
Normal file
264
Task/24-game-Solve/Java/24-game-solve.java
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
import java.util.*;
|
||||
|
||||
public class Game24Player {
|
||||
final String[] patterns = {"nnonnoo", "nnonono", "nnnoono", "nnnonoo",
|
||||
"nnnnooo"};
|
||||
final String ops = "+-*/^";
|
||||
|
||||
String solution;
|
||||
List<Integer> digits;
|
||||
|
||||
public static void main(String[] args) {
|
||||
new Game24Player().play();
|
||||
}
|
||||
|
||||
void play() {
|
||||
digits = getSolvableDigits();
|
||||
|
||||
Scanner in = new Scanner(System.in);
|
||||
while (true) {
|
||||
System.out.print("Make 24 using these digits: ");
|
||||
System.out.println(digits);
|
||||
System.out.println("(Enter 'q' to quit, 's' for a solution)");
|
||||
System.out.print("> ");
|
||||
|
||||
String line = in.nextLine();
|
||||
if (line.equalsIgnoreCase("q")) {
|
||||
System.out.println("\nThanks for playing");
|
||||
return;
|
||||
}
|
||||
|
||||
if (line.equalsIgnoreCase("s")) {
|
||||
System.out.println(solution);
|
||||
digits = getSolvableDigits();
|
||||
continue;
|
||||
}
|
||||
|
||||
char[] entry = line.replaceAll("[^*+-/)(\\d]", "").toCharArray();
|
||||
|
||||
try {
|
||||
validate(entry);
|
||||
|
||||
if (evaluate(infixToPostfix(entry))) {
|
||||
System.out.println("\nCorrect! Want to try another? ");
|
||||
digits = getSolvableDigits();
|
||||
} else {
|
||||
System.out.println("\nNot correct.");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
System.out.printf("%n%s Try again.%n", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void validate(char[] input) throws Exception {
|
||||
int total1 = 0, parens = 0, opsCount = 0;
|
||||
|
||||
for (char c : input) {
|
||||
if (Character.isDigit(c))
|
||||
total1 += 1 << (c - '0') * 4;
|
||||
else if (c == '(')
|
||||
parens++;
|
||||
else if (c == ')')
|
||||
parens--;
|
||||
else if (ops.indexOf(c) != -1)
|
||||
opsCount++;
|
||||
if (parens < 0)
|
||||
throw new Exception("Parentheses mismatch.");
|
||||
}
|
||||
|
||||
if (parens != 0)
|
||||
throw new Exception("Parentheses mismatch.");
|
||||
|
||||
if (opsCount != 3)
|
||||
throw new Exception("Wrong number of operators.");
|
||||
|
||||
int total2 = 0;
|
||||
for (int d : digits)
|
||||
total2 += 1 << d * 4;
|
||||
|
||||
if (total1 != total2)
|
||||
throw new Exception("Not the same digits.");
|
||||
}
|
||||
|
||||
boolean evaluate(char[] line) throws Exception {
|
||||
Stack<Float> s = new Stack<>();
|
||||
try {
|
||||
for (char c : line) {
|
||||
if ('0' <= c && c <= '9')
|
||||
s.push((float) c - '0');
|
||||
else
|
||||
s.push(applyOperator(s.pop(), s.pop(), c));
|
||||
}
|
||||
} catch (EmptyStackException e) {
|
||||
throw new Exception("Invalid entry.");
|
||||
}
|
||||
return (Math.abs(24 - s.peek()) < 0.001F);
|
||||
}
|
||||
|
||||
float applyOperator(float a, float b, char c) {
|
||||
switch (c) {
|
||||
case '+':
|
||||
return a + b;
|
||||
case '-':
|
||||
return b - a;
|
||||
case '*':
|
||||
return a * b;
|
||||
case '/':
|
||||
return b / a;
|
||||
default:
|
||||
return Float.NaN;
|
||||
}
|
||||
}
|
||||
|
||||
List<Integer> randomDigits() {
|
||||
Random r = new Random();
|
||||
List<Integer> result = new ArrayList<>(4);
|
||||
for (int i = 0; i < 4; i++)
|
||||
result.add(r.nextInt(9) + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
List<Integer> getSolvableDigits() {
|
||||
List<Integer> result;
|
||||
do {
|
||||
result = randomDigits();
|
||||
} while (!isSolvable(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
boolean isSolvable(List<Integer> digits) {
|
||||
Set<List<Integer>> dPerms = new HashSet<>(4 * 3 * 2);
|
||||
permute(digits, dPerms, 0);
|
||||
|
||||
int total = 4 * 4 * 4;
|
||||
List<List<Integer>> oPerms = new ArrayList<>(total);
|
||||
permuteOperators(oPerms, 4, total);
|
||||
|
||||
StringBuilder sb = new StringBuilder(4 + 3);
|
||||
|
||||
for (String pattern : patterns) {
|
||||
char[] patternChars = pattern.toCharArray();
|
||||
|
||||
for (List<Integer> dig : dPerms) {
|
||||
for (List<Integer> opr : oPerms) {
|
||||
|
||||
int i = 0, j = 0;
|
||||
for (char c : patternChars) {
|
||||
if (c == 'n')
|
||||
sb.append(dig.get(i++));
|
||||
else
|
||||
sb.append(ops.charAt(opr.get(j++)));
|
||||
}
|
||||
|
||||
String candidate = sb.toString();
|
||||
try {
|
||||
if (evaluate(candidate.toCharArray())) {
|
||||
solution = postfixToInfix(candidate);
|
||||
return true;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
sb.setLength(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
String postfixToInfix(String postfix) {
|
||||
class Expression {
|
||||
String op, ex;
|
||||
int prec = 3;
|
||||
|
||||
Expression(String e) {
|
||||
ex = e;
|
||||
}
|
||||
|
||||
Expression(String e1, String e2, String o) {
|
||||
ex = String.format("%s %s %s", e1, o, e2);
|
||||
op = o;
|
||||
prec = ops.indexOf(o) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
Stack<Expression> expr = new Stack<>();
|
||||
|
||||
for (char c : postfix.toCharArray()) {
|
||||
int idx = ops.indexOf(c);
|
||||
if (idx != -1) {
|
||||
|
||||
Expression r = expr.pop();
|
||||
Expression l = expr.pop();
|
||||
|
||||
int opPrec = idx / 2;
|
||||
|
||||
if (l.prec < opPrec)
|
||||
l.ex = '(' + l.ex + ')';
|
||||
|
||||
if (r.prec <= opPrec)
|
||||
r.ex = '(' + r.ex + ')';
|
||||
|
||||
expr.push(new Expression(l.ex, r.ex, "" + c));
|
||||
} else {
|
||||
expr.push(new Expression("" + c));
|
||||
}
|
||||
}
|
||||
return expr.peek().ex;
|
||||
}
|
||||
|
||||
char[] infixToPostfix(char[] infix) throws Exception {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Stack<Integer> s = new Stack<>();
|
||||
try {
|
||||
for (char c : infix) {
|
||||
int idx = ops.indexOf(c);
|
||||
if (idx != -1) {
|
||||
if (s.isEmpty())
|
||||
s.push(idx);
|
||||
else {
|
||||
while (!s.isEmpty()) {
|
||||
int prec2 = s.peek() / 2;
|
||||
int prec1 = idx / 2;
|
||||
if (prec2 >= prec1)
|
||||
sb.append(ops.charAt(s.pop()));
|
||||
else
|
||||
break;
|
||||
}
|
||||
s.push(idx);
|
||||
}
|
||||
} else if (c == '(') {
|
||||
s.push(-2);
|
||||
} else if (c == ')') {
|
||||
while (s.peek() != -2)
|
||||
sb.append(ops.charAt(s.pop()));
|
||||
s.pop();
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
while (!s.isEmpty())
|
||||
sb.append(ops.charAt(s.pop()));
|
||||
|
||||
} catch (EmptyStackException e) {
|
||||
throw new Exception("Invalid entry.");
|
||||
}
|
||||
return sb.toString().toCharArray();
|
||||
}
|
||||
|
||||
void permute(List<Integer> lst, Set<List<Integer>> res, int k) {
|
||||
for (int i = k; i < lst.size(); i++) {
|
||||
Collections.swap(lst, i, k);
|
||||
permute(lst, res, k + 1);
|
||||
Collections.swap(lst, k, i);
|
||||
}
|
||||
if (k == lst.size())
|
||||
res.add(new ArrayList<>(lst));
|
||||
}
|
||||
|
||||
void permuteOperators(List<List<Integer>> res, int n, int total) {
|
||||
for (int i = 0, npow = n * n; i < total; i++)
|
||||
res.add(Arrays.asList((i / npow), (i % npow) / n, i % n));
|
||||
}
|
||||
}
|
||||
104
Task/24-game-Solve/JavaScript/24-game-solve.js
Normal file
104
Task/24-game-Solve/JavaScript/24-game-solve.js
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
var ar=[],order=[0,1,2],op=[],val=[];
|
||||
var NOVAL=9999,oper="+-*/",out;
|
||||
|
||||
function rnd(n){return Math.floor(Math.random()*n)}
|
||||
|
||||
function say(s){
|
||||
try{document.write(s+"<br>")}
|
||||
catch(e){WScript.Echo(s)}
|
||||
}
|
||||
|
||||
function getvalue(x,dir){
|
||||
var r=NOVAL;
|
||||
if(dir>0)++x;
|
||||
while(1){
|
||||
if(val[x]!=NOVAL){
|
||||
r=val[x];
|
||||
val[x]=NOVAL;
|
||||
break;
|
||||
}
|
||||
x+=dir;
|
||||
}
|
||||
return r*1;
|
||||
}
|
||||
|
||||
function calc(){
|
||||
var c=0,l,r,x;
|
||||
val=ar.join('/').split('/');
|
||||
while(c<3){
|
||||
x=order[c];
|
||||
l=getvalue(x,-1);
|
||||
r=getvalue(x,1);
|
||||
switch(op[x]){
|
||||
case 0:val[x]=l+r;break;
|
||||
case 1:val[x]=l-r;break;
|
||||
case 2:val[x]=l*r;break;
|
||||
case 3:
|
||||
if(!r||l%r)return 0;
|
||||
val[x]=l/r;
|
||||
}
|
||||
++c;
|
||||
}
|
||||
return getvalue(-1,1);
|
||||
}
|
||||
|
||||
function shuffle(s,n){
|
||||
var x=n,p=eval(s),r,t;
|
||||
while(x--){
|
||||
r=rnd(n);
|
||||
t=p[x];
|
||||
p[x]=p[r];
|
||||
p[r]=t;
|
||||
}
|
||||
}
|
||||
|
||||
function parenth(n){
|
||||
while(n>0)--n,out+='(';
|
||||
while(n<0)++n,out+=')';
|
||||
}
|
||||
|
||||
function getpriority(x){
|
||||
for(var z=3;z--;)if(order[z]==x)return 3-z;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function showsolution(){
|
||||
var x=0,p=0,lp=0,v=0;
|
||||
while(x<4){
|
||||
if(x<3){
|
||||
lp=p;
|
||||
p=getpriority(x);
|
||||
v=p-lp;
|
||||
if(v>0)parenth(v);
|
||||
}
|
||||
out+=ar[x];
|
||||
if(x<3){
|
||||
if(v<0)parenth(v);
|
||||
out+=oper.charAt(op[x]);
|
||||
}
|
||||
++x;
|
||||
}
|
||||
parenth(-p);
|
||||
say(out);
|
||||
}
|
||||
|
||||
function solve24(s){
|
||||
var z=4,r;
|
||||
while(z--)ar[z]=s.charCodeAt(z)-48;
|
||||
out="";
|
||||
for(z=100000;z--;){
|
||||
r=rnd(256);
|
||||
op[0]=r&3;
|
||||
op[1]=(r>>2)&3;
|
||||
op[2]=(r>>4)&3;
|
||||
shuffle("ar",4);
|
||||
shuffle("order",3);
|
||||
if(calc()!=24)continue;
|
||||
showsolution();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
solve24("1234");
|
||||
solve24("6789");
|
||||
solve24("1127");
|
||||
38
Task/24-game-Solve/Jq/24-game-solve-1.jq
Normal file
38
Task/24-game-Solve/Jq/24-game-solve-1.jq
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# 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;
|
||||
23
Task/24-game-Solve/Jq/24-game-solve-2.jq
Normal file
23
Task/24-game-Solve/Jq/24-game-solve-2.jq
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# 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("");
|
||||
21
Task/24-game-Solve/Jq/24-game-solve-3.jq
Normal file
21
Task/24-game-Solve/Jq/24-game-solve-3.jq
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
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."
|
||||
16
Task/24-game-Solve/Jq/24-game-solve-4.jq
Normal file
16
Task/24-game-Solve/Jq/24-game-solve-4.jq
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
$ 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.
|
||||
19
Task/24-game-Solve/Julia/24-game-solve.julia
Normal file
19
Task/24-game-Solve/Julia/24-game-solve.julia
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
function solve24(nums)
|
||||
length(nums) != 4 && error("Input must be a 4-element Array")
|
||||
syms = [+,-,*,/]
|
||||
for x in syms, y in syms, z in syms
|
||||
for i = 1:24
|
||||
a,b,c,d = nthperm(nums,i)
|
||||
if round(x(y(a,b),z(c,d)),5) == 24
|
||||
return "($a$y$b)$x($c$z$d)"
|
||||
elseif round(x(a,y(b,z(c,d))),5) == 24
|
||||
return "$a$x($b$y($c$z$d))"
|
||||
elseif round(x(y(z(c,d),b),a),5) == 24
|
||||
return "(($c$z$d)$y$b)$x$a"
|
||||
elseif round(x(y(b,z(c,d)),a),5) == 24
|
||||
return "($b$y($c$z$d))$x$a"
|
||||
end
|
||||
end
|
||||
end
|
||||
return "0"
|
||||
end
|
||||
99
Task/24-game-Solve/Kotlin/24-game-solve.kotlin
Normal file
99
Task/24-game-Solve/Kotlin/24-game-solve.kotlin
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
// version 1.1.3
|
||||
|
||||
import java.util.Random
|
||||
|
||||
const val N_CARDS = 4
|
||||
const val SOLVE_GOAL = 24
|
||||
const val MAX_DIGIT = 9
|
||||
|
||||
class Frac(val num: Int, val den: Int)
|
||||
|
||||
enum class OpType { NUM, ADD, SUB, MUL, DIV }
|
||||
|
||||
class Expr(
|
||||
var op: OpType = OpType.NUM,
|
||||
var left: Expr? = null,
|
||||
var right: Expr? = null,
|
||||
var value: Int = 0
|
||||
)
|
||||
|
||||
fun showExpr(e: Expr?, prec: OpType, isRight: Boolean) {
|
||||
if (e == null) return
|
||||
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("(")
|
||||
showExpr(e.left, e.op, false)
|
||||
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")
|
||||
}
|
||||
}
|
||||
123
Task/24-game-Solve/Liberty-BASIC/24-game-solve.basic
Normal file
123
Task/24-game-Solve/Liberty-BASIC/24-game-solve.basic
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
dim d(4)
|
||||
input "Enter 4 digits: "; a$
|
||||
nD=0
|
||||
for i =1 to len(a$)
|
||||
c$=mid$(a$,i,1)
|
||||
if instr("123456789",c$) then
|
||||
nD=nD+1
|
||||
d(nD)=val(c$)
|
||||
end if
|
||||
next
|
||||
'for i = 1 to 4
|
||||
' print d(i);
|
||||
'next
|
||||
|
||||
'precompute permutations. Dumb way.
|
||||
nPerm = 1*2*3*4
|
||||
dim perm(nPerm, 4)
|
||||
n = 0
|
||||
for i = 1 to 4
|
||||
for j = 1 to 4
|
||||
for k = 1 to 4
|
||||
for l = 1 to 4
|
||||
'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
|
||||
'
|
||||
' perm(n,1)=i
|
||||
' perm(n,2)=j
|
||||
' perm(n,3)=k
|
||||
' perm(n,4)=l
|
||||
'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
|
||||
next
|
||||
next
|
||||
next
|
||||
next
|
||||
'check if permutations look OK. They are
|
||||
'for i =1 to n
|
||||
' print i,
|
||||
' for j =1 to 4: print perm(i,j);:next
|
||||
' print
|
||||
'next
|
||||
|
||||
'possible brackets
|
||||
NBrackets = 11
|
||||
dim Brakets$(NBrackets)
|
||||
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
|
||||
read Tmpl$: Brakets$(i) = Tmpl$
|
||||
next
|
||||
|
||||
'operations: full search
|
||||
count = 0
|
||||
Ops$="+ - * /"
|
||||
dim Op$(3)
|
||||
For op1=1 to 4
|
||||
Op$(1)=word$(Ops$,op1)
|
||||
For op2=1 to 4
|
||||
Op$(2)=word$(Ops$,op2)
|
||||
For op3=1 to 4
|
||||
Op$(3)=word$(Ops$,op3)
|
||||
'print "*"
|
||||
'substitute all brackets
|
||||
for t = 1 to NBrackets
|
||||
Tmpl$=Brakets$(t)
|
||||
'print , Tmpl$
|
||||
'now, substitute all digits: permutations.
|
||||
for p = 1 to nPerm
|
||||
res$= ""
|
||||
nOp=0
|
||||
nD=0
|
||||
for i = 1 to len(Tmpl$)
|
||||
c$ = mid$(Tmpl$, i, 1)
|
||||
select case c$
|
||||
case "#" 'operations
|
||||
nOp = nOp+1
|
||||
res$ = res$+Op$(nOp)
|
||||
case "4" 'digits
|
||||
nD = nOp+1
|
||||
res$ = res$; perm(p,nD)
|
||||
case else 'brackets goes here
|
||||
res$ = res$+ c$
|
||||
end select
|
||||
next
|
||||
'print,, res$
|
||||
'eval here
|
||||
if evalWithErrCheck(res$) = 24 then
|
||||
print "24 = ";res$
|
||||
end 'comment it out if you want to see all versions
|
||||
end if
|
||||
count = count + 1
|
||||
next
|
||||
next
|
||||
Next
|
||||
Next
|
||||
next
|
||||
|
||||
print "If you see this, probably task cannot be solved with these digits"
|
||||
'print count
|
||||
end
|
||||
|
||||
function evalWithErrCheck(expr$)
|
||||
on error goto [handler]
|
||||
evalWithErrCheck=eval(expr$)
|
||||
exit function
|
||||
[handler]
|
||||
end function
|
||||
74
Task/24-game-Solve/Lua/24-game-solve.lua
Normal file
74
Task/24-game-Solve/Lua/24-game-solve.lua
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
local SIZE = #arg[1]
|
||||
local GOAL = tonumber(arg[2]) or 24
|
||||
|
||||
local input = {}
|
||||
for v in arg[1]:gmatch("%d") do
|
||||
table.insert(input, v)
|
||||
end
|
||||
assert(#input == SIZE, 'Invalid input')
|
||||
|
||||
local operations = {'+', '-', '*', '/'}
|
||||
|
||||
local function BinaryTrees(vert)
|
||||
if vert == 0 then
|
||||
return {false}
|
||||
else
|
||||
local buf = {}
|
||||
for leften = 0, vert - 1 do
|
||||
local righten = vert - leften - 1
|
||||
for _, left in pairs(BinaryTrees(leften)) do
|
||||
for _, right in pairs(BinaryTrees(righten)) do
|
||||
table.insert(buf, {left, right})
|
||||
end
|
||||
end
|
||||
end
|
||||
return buf
|
||||
end
|
||||
end
|
||||
local trees = BinaryTrees(SIZE-1)
|
||||
local c, opc, oper, str
|
||||
local max = math.pow(#operations, SIZE-1)
|
||||
local function op(a,b)
|
||||
opc = opc + 1
|
||||
local i = math.floor(oper/math.pow(#operations, opc-1))%#operations+1
|
||||
return '('.. a .. operations[i] .. b ..')'
|
||||
end
|
||||
|
||||
local function EvalTree(tree)
|
||||
if tree == false then
|
||||
c = c + 1
|
||||
return input[c-1]
|
||||
else
|
||||
return op(EvalTree(tree[1]), EvalTree(tree[2]))
|
||||
end
|
||||
end
|
||||
|
||||
local function printResult()
|
||||
for _, v in ipairs(trees) do
|
||||
for i = 0, max do
|
||||
c, opc, oper = 1, 0, i
|
||||
str = EvalTree(v)
|
||||
loadstring('res='..str)()
|
||||
if(res == GOAL) then print(str, '=', res) end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local uniq = {}
|
||||
local function permgen (a, n)
|
||||
if n == 0 then
|
||||
local str = table.concat(a)
|
||||
if not uniq[str] then
|
||||
printResult()
|
||||
uniq[str] = true
|
||||
end
|
||||
else
|
||||
for i = 1, n do
|
||||
a[n], a[i] = a[i], a[n]
|
||||
permgen(a, n - 1)
|
||||
a[n], a[i] = a[i], a[n]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
permgen(input, SIZE)
|
||||
16
Task/24-game-Solve/Mathematica/24-game-solve-1.math
Normal file
16
Task/24-game-Solve/Mathematica/24-game-solve-1.math
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
treeR[n_] := Table[o[trees[a], trees[n - a]], {a, 1, n - 1}]
|
||||
treeR[1] := n
|
||||
tree[n_] :=
|
||||
Flatten[treeR[n] //. {o[a_List, b_] :> (o[#, b] & /@ a),
|
||||
o[a_, b_List] :> (o[a, #] & /@ b)}]
|
||||
game24play[val_List] :=
|
||||
Union[StringReplace[StringTake[ToString[#, InputForm], {10, -2}],
|
||||
"-1*" ~~ n_ :> "-" <> n] & /@ (HoldForm /@
|
||||
Select[Union@
|
||||
Flatten[Outer[# /. {o[q_Integer] :> #2[[q]],
|
||||
n[q_] :> #3[[q]]} &,
|
||||
Block[{O = 1, N = 1}, # /. {o :> o[O++], n :> n[N++]}] & /@
|
||||
tree[4], Tuples[{Plus, Subtract, Times, Divide}, 3],
|
||||
Permutations[Array[v, 4]], 1]],
|
||||
Quiet[(# /. v[q_] :> val[[q]]) == 24] &] /.
|
||||
Table[v[q] -> val[[q]], {q, 4}])]
|
||||
1
Task/24-game-Solve/Mathematica/24-game-solve-2.math
Normal file
1
Task/24-game-Solve/Mathematica/24-game-solve-2.math
Normal file
|
|
@ -0,0 +1 @@
|
|||
game24play[RandomInteger[{1, 9}, 4]]
|
||||
35
Task/24-game-Solve/Mathematica/24-game-solve-3.math
Normal file
35
Task/24-game-Solve/Mathematica/24-game-solve-3.math
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
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]]
|
||||
56
Task/24-game-Solve/Nim/24-game-solve.nim
Normal file
56
Task/24-game-Solve/Nim/24-game-solve.nim
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
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()
|
||||
70
Task/24-game-Solve/OCaml/24-game-solve.ocaml
Normal file
70
Task/24-game-Solve/OCaml/24-game-solve.ocaml
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
type expression =
|
||||
| Const of float
|
||||
| Sum of expression * expression (* e1 + e2 *)
|
||||
| Diff of expression * expression (* e1 - e2 *)
|
||||
| Prod of expression * expression (* e1 * e2 *)
|
||||
| Quot of expression * expression (* e1 / e2 *)
|
||||
|
||||
let rec eval = function
|
||||
| Const c -> c
|
||||
| Sum (f, g) -> eval f +. eval g
|
||||
| Diff(f, g) -> eval f -. eval g
|
||||
| Prod(f, g) -> eval f *. eval g
|
||||
| Quot(f, g) -> eval f /. eval g
|
||||
|
||||
let print_expr expr =
|
||||
let open_paren prec op_prec =
|
||||
if prec > op_prec then print_string "(" in
|
||||
let close_paren prec op_prec =
|
||||
if prec > op_prec then print_string ")" in
|
||||
let rec print prec = function (* prec is the current precedence *)
|
||||
| Const c -> Printf.printf "%g" c
|
||||
| Sum(f, g) ->
|
||||
open_paren prec 0;
|
||||
print 0 f; print_string " + "; print 0 g;
|
||||
close_paren prec 0
|
||||
| Diff(f, g) ->
|
||||
open_paren prec 0;
|
||||
print 0 f; print_string " - "; print 1 g;
|
||||
close_paren prec 0
|
||||
| Prod(f, g) ->
|
||||
open_paren prec 2;
|
||||
print 2 f; print_string " * "; print 2 g;
|
||||
close_paren prec 2
|
||||
| Quot(f, g) ->
|
||||
open_paren prec 2;
|
||||
print 2 f; print_string " / "; print 3 g;
|
||||
close_paren prec 2
|
||||
in
|
||||
print 0 expr
|
||||
|
||||
let rec insert v = function
|
||||
| [] -> [[v]]
|
||||
| x::xs as li -> (v::li) :: (List.map (fun y -> x::y) (insert v xs))
|
||||
|
||||
let permutations li =
|
||||
List.fold_right (fun x z -> List.concat (List.map (insert x) z)) li [[]]
|
||||
|
||||
let rec comp expr = function
|
||||
| x::xs ->
|
||||
comp (Sum (expr, x)) xs;
|
||||
comp (Diff(expr, x)) xs;
|
||||
comp (Prod(expr, x)) xs;
|
||||
comp (Quot(expr, x)) xs;
|
||||
| [] ->
|
||||
if (eval expr) = 24.0
|
||||
then (print_expr expr; print_newline())
|
||||
;;
|
||||
|
||||
let () =
|
||||
Random.self_init();
|
||||
let digits = Array.init 4 (fun _ -> 1 + Random.int 9) in
|
||||
print_string "Input digits: ";
|
||||
Array.iter (Printf.printf " %d") digits; print_newline();
|
||||
let digits = Array.to_list(Array.map float_of_int digits) in
|
||||
let digits = List.map (fun v -> Const v) digits in
|
||||
let all = permutations digits in
|
||||
List.iter (function
|
||||
| x::xs -> comp x xs
|
||||
| [] -> assert false
|
||||
) all
|
||||
54
Task/24-game-Solve/Perl/24-game-solve.pl
Normal file
54
Task/24-game-Solve/Perl/24-game-solve.pl
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# 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..$#_;
|
||||
while ( $code->(@_[@idx]) ) {
|
||||
my $p = $#idx;
|
||||
--$p while $idx[$p-1] > $idx[$p];
|
||||
my $q = $p or return;
|
||||
push @idx, reverse splice @idx, $p;
|
||||
++$q while $idx[$p-1] > $idx[$q];
|
||||
@idx[$p-1,$q]=@idx[$q,$p-1];
|
||||
}
|
||||
}
|
||||
|
||||
@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))',
|
||||
);
|
||||
|
||||
# generate all possible combinations of operators
|
||||
@op = qw( + - * / );
|
||||
@operators = map{ $a=$_; map{ $b=$_; map{ "$a $b $_" }@op }@op }@op;
|
||||
|
||||
while(1)
|
||||
{
|
||||
print "Enter four integers or 'q' to exit: ";
|
||||
chomp($ent = <>);
|
||||
last if $ent eq 'q';
|
||||
|
||||
|
||||
if($ent !~ /^[1-9] [1-9] [1-9] [1-9]$/){ print "invalid input\n"; next }
|
||||
|
||||
@n = split / /,$ent;
|
||||
permute { push @numbers,join ' ',@_ }@n;
|
||||
|
||||
for $format (@formats)
|
||||
{
|
||||
for(@numbers)
|
||||
{
|
||||
@n = split;
|
||||
for(@operators)
|
||||
{
|
||||
@o = split;
|
||||
$str = sprintf $format,$n[0],$o[0],$n[1],$o[1],$n[2],$o[2],$n[3];
|
||||
$r = eval($str);
|
||||
print "$str\n" if $r == 24;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
117
Task/24-game-Solve/Phix/24-game-solve.phix
Normal file
117
Task/24-game-Solve/Phix/24-game-solve.phix
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
(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 <(map)1>, 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>
|
||||
<!--
|
||||
19
Task/24-game-Solve/Picat/24-game-solve-1.picat
Normal file
19
Task/24-game-Solve/Picat/24-game-solve-1.picat
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
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 =>
|
||||
println(Exp).
|
||||
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]).
|
||||
44
Task/24-game-Solve/Picat/24-game-solve-2.picat
Normal file
44
Task/24-game-Solve/Picat/24-game-solve-2.picat
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import util.
|
||||
|
||||
main =>
|
||||
Target=24,
|
||||
Nums = [5,6,7,8],
|
||||
|
||||
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.
|
||||
solve_num(Nums, Target,Expr) =>
|
||||
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)",
|
||||
"A X (B Y 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().
|
||||
|
||||
ignore(_E) => fail. % ignore zero_divisor errors
|
||||
|
||||
% Replace all occurrences in S with From -> To.
|
||||
replace_all(S,From,To) = Res =>
|
||||
R = S,
|
||||
foreach({F,T} in zip(From,To))
|
||||
R := replace(R, F,T.to_string())
|
||||
end,
|
||||
Res = R.
|
||||
46
Task/24-game-Solve/Picat/24-game-solve-3.picat
Normal file
46
Task/24-game-Solve/Picat/24-game-solve-3.picat
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import util.
|
||||
|
||||
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().
|
||||
18
Task/24-game-Solve/PicoLisp/24-game-solve.l
Normal file
18
Task/24-game-Solve/PicoLisp/24-game-solve.l
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
(be play24 (@Lst @Expr) # Define Pilog rule
|
||||
(permute @Lst (@A @B @C @D))
|
||||
(member @Op1 (+ - * /))
|
||||
(member @Op2 (+ - * /))
|
||||
(member @Op3 (+ - * /))
|
||||
(or
|
||||
((equal @Expr (@Op1 (@Op2 @A @B) (@Op3 @C @D))))
|
||||
((equal @Expr (@Op1 @A (@Op2 @B (@Op3 @C @D))))) )
|
||||
(^ @ (= 24 (catch '("Div/0") (eval (-> @Expr))))) )
|
||||
|
||||
(de play24 (A B C D) # Define PicoLisp function
|
||||
(pilog
|
||||
(quote
|
||||
@L (list A B C D)
|
||||
(play24 @L @X) )
|
||||
(println @X) ) )
|
||||
|
||||
(play24 5 6 7 8) # Call 'play24' function
|
||||
35
Task/24-game-Solve/ProDOS/24-game-solve.dos
Normal file
35
Task/24-game-Solve/ProDOS/24-game-solve.dos
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
editvar /modify -random- = <10
|
||||
:a
|
||||
editvar /newvar /withothervar /value=-random- /title=1
|
||||
editvar /newvar /withothervar /value=-random- /title=2
|
||||
editvar /newvar /withothervar /value=-random- /title=3
|
||||
editvar /newvar /withothervar /value=-random- /title=4
|
||||
printline These are your four digits: -1- -2- -3- -4-
|
||||
printline Use an algorithm to make the number 24.
|
||||
editvar /newvar /value=a /userinput=1 /title=Algorithm:
|
||||
do -a-
|
||||
if -a- /hasvalue 24 printline Your algorithm worked! & goto :b (
|
||||
) else printline Your algorithm did not work.
|
||||
editvar /newvar /value=b /userinput=1 /title=Do you want to see how you could have done it?
|
||||
if -b- /hasvalue y goto :c else goto :b
|
||||
:b
|
||||
editvar /newvar /value=c /userinput=1 /title=Do you want to play again?
|
||||
if -c- /hasvalue y goto :a else exitcurrentprogram
|
||||
:c
|
||||
editvar /newvar /value=do -1- + -2- + -3- + -4- /title=c & do -c- >d & if -d- /hasvalue 24 goto :solve
|
||||
editvar /newvar /value=do -1- - -2- + -3- + -4- /title=c & do -c- >d & if -d- /hasvalue 24 goto :solve
|
||||
editvar /newvar /value=do -1- / -2- + -3- + -4- /title=c & do -c- >d & if -d- /hasvalue 24 goto :solve
|
||||
editvar /newvar /value=do -1- * -2- + -3- + -4- /title=c & do -c- >d & if -d- /hasvalue 24 goto :solve
|
||||
editvar /newvar /value=do -1- + -2- - -3- + -4- /title=c & do -c- >d & if -d- /hasvalue 24 goto :solve
|
||||
editvar /newvar /value=do -1- + -2- / -3- + -4- /title=c & do -c- >d & if -d- /hasvalue 24 goto :solve
|
||||
editvar /newvar /value=do -1- + -2- * -3- + -4- /title=c & do -c- >d & if -d- /hasvalue 24 goto :solve
|
||||
editvar /newvar /value=do -1- + -2- + -3- - -4- /title=c & do -c- >d & if -d- /hasvalue 24 goto :solve
|
||||
editvar /newvar /value=do -1- + -2- + -3- / -4- /title=c & do -c- >d & if -d- /hasvalue 24 goto :solve
|
||||
editvar /newvar /value=do -1- + -2- + -3- * -4- /title=c & do -c- >d & if -d- /hasvalue 24 goto :solve
|
||||
editvar /newvar /value=do -1- - -2- - -3- - -4- /title=c & do -c- >d & if -d- /hasvalue 24 goto :solve
|
||||
editvar /newvar /value=do -1- / -2- / -3- / -4- /title=c & do -c- >d & if -d- /hasvalue 24 goto :solve
|
||||
editvar /newvar /value=do -1- * -2- * -3- * -4- /title=c & do -c- >d & if -d- /hasvalue 24 goto :solve
|
||||
:solve
|
||||
printline you could have done it by doing -c-
|
||||
stoptask
|
||||
goto :b
|
||||
91
Task/24-game-Solve/Prolog/24-game-solve-1.pro
Normal file
91
Task/24-game-Solve/Prolog/24-game-solve-1.pro
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
play24(Len, Range, Goal) :-
|
||||
game(Len, Range, Goal, L, S),
|
||||
maplist(my_write, L),
|
||||
format(': ~w~n', [S]).
|
||||
|
||||
game(Len, Range, Value, L, S) :-
|
||||
length(L, Len),
|
||||
maplist(choose(Range), L),
|
||||
compute(L, Value, [], S).
|
||||
|
||||
|
||||
choose(Range, V) :-
|
||||
V is random(Range) + 1.
|
||||
|
||||
|
||||
write_tree([M], [M]).
|
||||
|
||||
write_tree([+, M, N], S) :-
|
||||
write_tree(M, MS),
|
||||
write_tree(N, NS),
|
||||
append(MS, [+ | NS], S).
|
||||
|
||||
write_tree([-, M, N], S) :-
|
||||
write_tree(M, MS),
|
||||
write_tree(N, NS),
|
||||
( is_add(N) -> append(MS, [-, '(' | NS], Temp), append(Temp, ')', S)
|
||||
; append(MS, [- | NS], S)).
|
||||
|
||||
|
||||
write_tree([Op, M, N], S) :-
|
||||
member(Op, [*, /]),
|
||||
write_tree(M, MS),
|
||||
write_tree(N, NS),
|
||||
( is_add(M) -> append(['(' | MS], [')'], TempM)
|
||||
; TempM = MS),
|
||||
( is_add(N) -> append(['(' | NS], [')'], TempN)
|
||||
; TempN = NS),
|
||||
append(TempM, [Op | TempN], S).
|
||||
|
||||
is_add([Op, _, _]) :-
|
||||
member(Op, [+, -]).
|
||||
|
||||
compute([Value], Value, [[_R-S1]], S) :-
|
||||
write_tree(S1, S2),
|
||||
with_output_to(atom(S), maplist(write, S2)).
|
||||
|
||||
compute(L, Value, CS, S) :-
|
||||
select(M, L, L1),
|
||||
select(N, L1, L2),
|
||||
next_value(M, N, R, CS, Expr),
|
||||
compute([R|L2], Value, Expr, S).
|
||||
|
||||
next_value(M, N, R, CS,[[R - [+, M1, N1]] | CS2]) :-
|
||||
R is M+N,
|
||||
( member([M-ExprM], CS) -> select([M-ExprM], CS, CS1), M1 = ExprM
|
||||
; M1 = [M], CS1 = CS
|
||||
),
|
||||
( member([N-ExprN], CS1) -> select([N-ExprN], CS1, CS2), N1 = ExprN
|
||||
; N1 = [N], CS2 = CS1
|
||||
).
|
||||
|
||||
next_value(M, N, R, CS,[[R - [-, M1, N1]] | CS2]) :-
|
||||
R is M-N,
|
||||
( member([M-ExprM], CS) -> select([M-ExprM], CS, CS1), M1 = ExprM
|
||||
; M1 = [M], CS1 = CS
|
||||
),
|
||||
( member([N-ExprN], CS1) -> select([N-ExprN], CS1, CS2), N1 = ExprN
|
||||
; N1 = [N], CS2 = CS1
|
||||
).
|
||||
|
||||
next_value(M, N, R, CS,[[R - [*, M1, N1]] | CS2]) :-
|
||||
R is M*N,
|
||||
( member([M-ExprM], CS) -> select([M-ExprM], CS, CS1), M1 = ExprM
|
||||
; M1 = [M], CS1 = CS
|
||||
),
|
||||
( member([N-ExprN], CS1) -> select([N-ExprN], CS1, CS2), N1 = ExprN
|
||||
; N1 = [N], CS2 = CS1
|
||||
).
|
||||
|
||||
next_value(M, N, R, CS,[[R - [/, M1, N1]] | CS2]) :-
|
||||
N \= 0,
|
||||
R is rdiv(M,N),
|
||||
( member([M-ExprM], CS) -> select([M-ExprM], CS, CS1), M1 = ExprM
|
||||
; M1 = [M], CS1 = CS
|
||||
),
|
||||
( member([N-ExprN], CS1) -> select([N-ExprN], CS1, CS2), N1 = ExprN
|
||||
; N1 = [N], CS2 = CS1
|
||||
).
|
||||
|
||||
my_write(V) :-
|
||||
format('~w ', [V]).
|
||||
22
Task/24-game-Solve/Prolog/24-game-solve-2.pro
Normal file
22
Task/24-game-Solve/Prolog/24-game-solve-2.pro
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
:- initialization(main).
|
||||
|
||||
solve(N,Xs,Ast) :-
|
||||
Err = evaluation_error(zero_divisor)
|
||||
, gen_ast(Xs,Ast), catch(Ast =:= N, error(Err,_), fail)
|
||||
.
|
||||
|
||||
gen_ast([N],N) :- between(1,9,N).
|
||||
gen_ast(Xs,Ast) :-
|
||||
Ys = [_|_], Zs = [_|_], split(Xs,Ys,Zs)
|
||||
, ( member(Op, [(+),(*)]), Ys @=< Zs ; member(Op, [(-),(//)]) )
|
||||
, gen_ast(Ys,A), gen_ast(Zs,B), Ast =.. [Op,A,B]
|
||||
.
|
||||
|
||||
split(Xs,Ys,Zs) :- sublist(Ys,Xs), select_all(Ys,Xs,Zs).
|
||||
% where
|
||||
select_all([],Xs,Xs).
|
||||
select_all([Y|Ys],Xs,Zs) :- select(Y,Xs,X1), !, select_all(Ys,X1,Zs).
|
||||
|
||||
|
||||
test(T) :- solve(24, [2,3,8,9], T).
|
||||
main :- forall(test(T), (write(T), nl)), halt.
|
||||
44
Task/24-game-Solve/Python/24-game-solve-1.py
Normal file
44
Task/24-game-Solve/Python/24-game-solve-1.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# -*- 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")
|
||||
359
Task/24-game-Solve/Python/24-game-solve-2.py
Normal file
359
Task/24-game-Solve/Python/24-game-solve-2.py
Normal file
|
|
@ -0,0 +1,359 @@
|
|||
''' 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()
|
||||
39
Task/24-game-Solve/Python/24-game-solve.py
Normal file
39
Task/24-game-Solve/Python/24-game-solve.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# -*- 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)}")
|
||||
64
Task/24-game-Solve/Quackery/24-game-solve.quackery
Normal file
64
Task/24-game-Solve/Quackery/24-game-solve.quackery
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
[ ' [ 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 --> )
|
||||
34
Task/24-game-Solve/R/24-game-solve-1.r
Normal file
34
Task/24-game-Solve/R/24-game-solve-1.r
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
library(gtools)
|
||||
|
||||
solve24 <- function(vals=c(8, 4, 2, 1),
|
||||
goal=24,
|
||||
ops=c("+", "-", "*", "/")) {
|
||||
|
||||
val.perms <- as.data.frame(t(
|
||||
permutations(length(vals), length(vals))))
|
||||
|
||||
nop <- length(vals)-1
|
||||
op.perms <- as.data.frame(t(
|
||||
do.call(expand.grid,
|
||||
replicate(nop, list(ops)))))
|
||||
|
||||
ord.perms <- as.data.frame(t(
|
||||
do.call(expand.grid,
|
||||
replicate(n <- nop, 1:((n <<- n-1)+1)))))
|
||||
|
||||
for (val.perm in val.perms)
|
||||
for (op.perm in op.perms)
|
||||
for (ord.perm in ord.perms)
|
||||
{
|
||||
expr <- as.list(vals[val.perm])
|
||||
for (i in 1:nop) {
|
||||
expr[[ ord.perm[i] ]] <- call(as.character(op.perm[i]),
|
||||
expr[[ ord.perm[i] ]],
|
||||
expr[[ ord.perm[i]+1 ]])
|
||||
expr <- expr[ -(ord.perm[i]+1) ]
|
||||
}
|
||||
if (identical(eval(expr[[1]]), goal)) return(expr[[1]])
|
||||
}
|
||||
|
||||
return(NA)
|
||||
}
|
||||
12
Task/24-game-Solve/R/24-game-solve-2.r
Normal file
12
Task/24-game-Solve/R/24-game-solve-2.r
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
> solve24()
|
||||
8 * (4 - 2 + 1)
|
||||
> solve24(c(6,7,9,5))
|
||||
6 + (7 - 5) * 9
|
||||
> solve24(c(8,8,8,8))
|
||||
[1] NA
|
||||
> solve24(goal=49) #different goal value
|
||||
8 * (4 + 2) + 1
|
||||
> solve24(goal=52) #no solution
|
||||
[1] NA
|
||||
> solve24(ops=c('-', '/')) #restricted set of operators
|
||||
(8 - 2)/(1/4)
|
||||
263
Task/24-game-Solve/REXX/24-game-solve.rexx
Normal file
263
Task/24-game-Solve/REXX/24-game-solve.rexx
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
/*REXX program helps the user find solutions to the game of 24. */
|
||||
/* start-of-help
|
||||
┌───────────────────────────────────────────────────────────────────────┐
|
||||
│ Argument is either of three forms: (blank) │~
|
||||
│ ssss │~
|
||||
│ ssss,tot │~
|
||||
│ ssss-ffff │~
|
||||
│ ssss-ffff,tot │~
|
||||
│ -ssss │~
|
||||
│ +ssss │~
|
||||
│ │~
|
||||
│ where SSSS and/or FFFF must be exactly four numerals (digits) │~
|
||||
│ comprised soley of the numerals (digits) 1 ──> 9 (no zeroes). │~
|
||||
│ │~
|
||||
│ SSSS is the start, │~
|
||||
│ FFFF is the start. │~
|
||||
│ │~
|
||||
│ │~
|
||||
│ If ssss has a leading plus (+) sign, it is used as the number, and │~
|
||||
│ the user is prompted to find a solution. │~
|
||||
│ │~
|
||||
│ If ssss has a leading minus (-) sign, a solution is looked for and │~
|
||||
│ the user is told there is a solution (but no solutions are shown). │~
|
||||
│ │~
|
||||
│ If no argument is specified, this program finds a four digits (no │~
|
||||
│ zeroes) which has at least one solution, and shows the digits to │~
|
||||
│ the user, requesting that they enter a solution. │~
|
||||
│ │~
|
||||
│ If tot is entered, it is the desired answer. The default is 24. │~
|
||||
│ │~
|
||||
│ 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)=='+' then rrrr=start /*use what's specified. */
|
||||
show= 1 /*enable SOLVE to show solutions. */
|
||||
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) /*any illegal characters? */
|
||||
if _v\==0 then do; call ger 'invalid character:' substr(y, _v, 1); iterate; end
|
||||
if y='' then do; call validate y; iterate; end
|
||||
|
||||
do j=1 for length(y)-1 while \abuttals /*check for two digits adjacent. */
|
||||
if \datatype(substr(y,j,1), 'W') then iterate
|
||||
if datatype(substr(y,j+1,1),'W') then do
|
||||
call ger 'invalid use of digit abuttal' substr(y,j,2)
|
||||
iterate guesses
|
||||
end
|
||||
end /*j*/
|
||||
|
||||
yd= countchars(y, digs) /*count of legal digits 123456789 */
|
||||
if yd<4 then do; call ger 'not enough digits entered.'; iterate guesses; end
|
||||
if yd>4 then do; call ger 'too many digits entered.' ; iterate guesses; end
|
||||
|
||||
do j=1 for length(groupsym) by 2
|
||||
if countchars(y,substr(groupsym,j ,1))\==,
|
||||
countchars(y,substr(groupsym,j+1,1)) then do
|
||||
call ger 'mismatched' substr(groupsym,j,2)
|
||||
iterate guesses
|
||||
end
|
||||
end /*j*/
|
||||
|
||||
do k=1 for 2 /*check for ** and // */
|
||||
_= copies( substr( opers, k, 1), 2)
|
||||
if pos(_, y)\==0 then do; call ger 'illegal operator:' _; iterate guesses; end
|
||||
end /*k*/
|
||||
|
||||
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 /*gggg*/
|
||||
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*/
|
||||
_= a.j
|
||||
do k=j+1 to L
|
||||
if a.k<_ then do; a.j= a.k; a.k= _; _= a.k; end
|
||||
end /*k*/
|
||||
end /*j*/
|
||||
v= a.1
|
||||
do m=2 to L; v= v || a.m /*build a string of digs from A.m */
|
||||
end /*m*/
|
||||
return v
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
validate: parse arg y; errCode= 0; _v= verify(y, digs)
|
||||
select
|
||||
when y=='' then call ger 'no digits entered.'
|
||||
when length(y)<4 then call ger 'not enough digits entered, must be 4'
|
||||
when length(y)>4 then call ger 'too many digits entered, must be 4'
|
||||
when pos(0,y)\==0 then call ger "can't use the digit 0 (zero)"
|
||||
when _v\==0 then call ger 'illegal character:' substr(y,_v,1)
|
||||
otherwise nop
|
||||
end /*select*/
|
||||
return \errCode
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
div: procedure; parse arg q; if q=0 then q=1e9; return q /*tests if dividing by zero.*/
|
||||
ger: say= '***error*** for argument:' y; say arg(1); errCode= 1; return 0
|
||||
p: return word( arg(1), 1)
|
||||
s: if arg(1)==1 then return arg(3); return word( arg(2) 's', 1)
|
||||
16
Task/24-game-Solve/Racket/24-game-solve-1.rkt
Normal file
16
Task/24-game-Solve/Racket/24-game-solve-1.rkt
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
(define (in-variants n1 o1 n2 o2 n3 o3 n4)
|
||||
(let ([o1n (object-name o1)]
|
||||
[o2n (object-name o2)]
|
||||
[o3n (object-name o3)])
|
||||
(with-handlers ((exn:fail:contract:divide-by-zero? (λ (_) empty-sequence)))
|
||||
(in-parallel
|
||||
(list (o1 (o2 (o3 n1 n2) n3) n4)
|
||||
(o1 (o2 n1 (o3 n2 n3)) n4)
|
||||
(o1 (o2 n1 n2) (o3 n3 n4))
|
||||
(o1 n1 (o2 (o3 n2 n3) n4))
|
||||
(o1 n1 (o2 n2 (o3 n3 n4))))
|
||||
(list `(((,n1 ,o3n ,n2) ,o2n ,n3) ,o1n ,n4)
|
||||
`((,n1 ,o2n (,n2 ,o3n ,n3)) ,o1n ,n4)
|
||||
`((,n1 ,o2n ,n2) ,o1n (,n3 ,o3n ,n4))
|
||||
`(,n1 ,o1n ((,n2 ,o3n ,n3) ,o2n ,n4))
|
||||
`(,n1 ,o1n (,n2 ,o2n (,n3 ,o3n ,n4))))))))
|
||||
15
Task/24-game-Solve/Racket/24-game-solve-2.rkt
Normal file
15
Task/24-game-Solve/Racket/24-game-solve-2.rkt
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
(define (find-solutions numbers (goal 24))
|
||||
(define in-operations (list + - * /))
|
||||
(remove-duplicates
|
||||
(for*/list ([n1 numbers]
|
||||
[n2 (remove-from numbers n1)]
|
||||
[n3 (remove-from numbers n1 n2)]
|
||||
[n4 (remove-from numbers n1 n2 n3)]
|
||||
[o1 in-operations]
|
||||
[o2 in-operations]
|
||||
[o3 in-operations]
|
||||
[(res expr) (in-variants n1 o1 n2 o2 n3 o3 n4)]
|
||||
#:when (= res goal))
|
||||
expr)))
|
||||
|
||||
(define (remove-from numbers . n) (foldr remq numbers n))
|
||||
37
Task/24-game-Solve/Raku/24-game-solve-1.raku
Normal file
37
Task/24-game-Solve/Raku/24-game-solve-1.raku
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
90
Task/24-game-Solve/Raku/24-game-solve-2.raku
Normal file
90
Task/24-game-Solve/Raku/24-game-solve-2.raku
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
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
|
||||
========================================================================
|
||||
}
|
||||
41
Task/24-game-Solve/Ruby/24-game-solve.rb
Normal file
41
Task/24-game-Solve/Ruby/24-game-solve.rb
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
class TwentyFourGame
|
||||
EXPRESSIONS = [
|
||||
'((%dr %s %dr) %s %dr) %s %dr',
|
||||
'(%dr %s (%dr %s %dr)) %s %dr',
|
||||
'(%dr %s %dr) %s (%dr %s %dr)',
|
||||
'%dr %s ((%dr %s %dr) %s %dr)',
|
||||
'%dr %s (%dr %s (%dr %s %dr))',
|
||||
]
|
||||
|
||||
OPERATORS = [:+, :-, :*, :/].repeated_permutation(3).to_a
|
||||
|
||||
def self.solve(digits)
|
||||
solutions = []
|
||||
perms = digits.permutation.to_a.uniq
|
||||
perms.product(OPERATORS, EXPRESSIONS) do |(a,b,c,d), (op1,op2,op3), expr|
|
||||
# evaluate using rational arithmetic
|
||||
text = expr % [a, op1, b, op2, c, op3, d]
|
||||
value = eval(text) rescue next # catch division by zero
|
||||
solutions << text.delete("r") if value == 24
|
||||
end
|
||||
solutions
|
||||
end
|
||||
end
|
||||
|
||||
# validate user input
|
||||
digits = ARGV.map do |arg|
|
||||
begin
|
||||
Integer(arg)
|
||||
rescue ArgumentError
|
||||
raise "error: not an integer: '#{arg}'"
|
||||
end
|
||||
end
|
||||
digits.size == 4 or raise "error: need 4 digits, only have #{digits.size}"
|
||||
|
||||
solutions = TwentyFourGame.solve(digits)
|
||||
if solutions.empty?
|
||||
puts "no solutions"
|
||||
else
|
||||
puts "found #{solutions.size} solutions, including #{solutions.first}"
|
||||
puts solutions.sort
|
||||
end
|
||||
165
Task/24-game-Solve/Rust/24-game-solve.rust
Normal file
165
Task/24-game-Solve/Rust/24-game-solve.rust
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
#[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]]]
|
||||
}
|
||||
25
Task/24-game-Solve/Scala/24-game-solve.scala
Normal file
25
Task/24-game-Solve/Scala/24-game-solve.scala
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
def permute(l: List[Double]): List[List[Double]] = l match {
|
||||
case Nil => List(Nil)
|
||||
case x :: xs =>
|
||||
for {
|
||||
ys <- permute(xs)
|
||||
position <- 0 to ys.length
|
||||
(left, right) = ys splitAt position
|
||||
} yield left ::: (x :: right)
|
||||
}
|
||||
|
||||
def computeAllOperations(l: List[Double]): List[(Double,String)] = l match {
|
||||
case Nil => Nil
|
||||
case x :: Nil => List((x, "%1.0f" format x))
|
||||
case x :: xs =>
|
||||
for {
|
||||
(y, ops) <- computeAllOperations(xs)
|
||||
(z, op) <-
|
||||
if (y == 0)
|
||||
List((x*y, "*"), (x+y, "+"), (x-y, "-"))
|
||||
else
|
||||
List((x*y, "*"), (x/y, "/"), (x+y, "+"), (x-y, "-"))
|
||||
} yield (z, "(%1.0f%s%s)" format (x,op,ops))
|
||||
}
|
||||
|
||||
def hasSolution(l: List[Double]) = permute(l) flatMap computeAllOperations filter (_._1 == 24) map (_._2)
|
||||
46
Task/24-game-Solve/Scheme/24-game-solve-1.ss
Normal file
46
Task/24-game-Solve/Scheme/24-game-solve-1.ss
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#!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))))
|
||||
13
Task/24-game-Solve/Scheme/24-game-solve-2.ss
Normal file
13
Task/24-game-Solve/Scheme/24-game-solve-2.ss
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
> (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)
|
||||
()
|
||||
33
Task/24-game-Solve/Sidef/24-game-solve-1.sidef
Normal file
33
Task/24-game-Solve/Sidef/24-game-solve-1.sidef
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
58
Task/24-game-Solve/Sidef/24-game-solve-2.sidef
Normal file
58
Task/24-game-Solve/Sidef/24-game-solve-2.sidef
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
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...))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
297
Task/24-game-Solve/Simula/24-game-solve.simula
Normal file
297
Task/24-game-Solve/Simula/24-game-solve.simula
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
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.
|
||||
172
Task/24-game-Solve/Swift/24-game-solve.swift
Normal file
172
Task/24-game-Solve/Swift/24-game-solve.swift
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
import Darwin
|
||||
import Foundation
|
||||
|
||||
var solution = ""
|
||||
|
||||
println("24 Game")
|
||||
println("Generating 4 digits...")
|
||||
|
||||
func randomDigits() -> [Int] {
|
||||
var result = [Int]()
|
||||
for i in 0 ..< 4 {
|
||||
result.append(Int(arc4random_uniform(9)+1))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Choose 4 digits
|
||||
let digits = randomDigits()
|
||||
|
||||
print("Make 24 using these digits : ")
|
||||
|
||||
for digit in digits {
|
||||
print("\(digit) ")
|
||||
}
|
||||
println()
|
||||
|
||||
// get input from operator
|
||||
var input = NSString(data:NSFileHandle.fileHandleWithStandardInput().availableData, encoding:NSUTF8StringEncoding)!
|
||||
|
||||
var enteredDigits = [Double]()
|
||||
|
||||
var enteredOperations = [Character]()
|
||||
|
||||
let inputString = input as String
|
||||
|
||||
// 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 = 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)
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
|
||||
for dig in dPerms {
|
||||
for opr in oPerms {
|
||||
var expression = ""
|
||||
|
||||
if evaluate(dig, opr) {
|
||||
for digit in dig {
|
||||
expression += "\(digit)"
|
||||
}
|
||||
|
||||
for oper in opr {
|
||||
expression += oper
|
||||
}
|
||||
|
||||
solution = beautify(expression)
|
||||
result = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func permute(inout lst: [Double], inout res: [[Double]], k: Int) -> Void {
|
||||
for i in k ..< lst.count {
|
||||
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 = ["+", "-", "*", "/"]
|
||||
let npow = n * n
|
||||
for i in 0 ..< total {
|
||||
res.append([posOperations[(i / npow)], posOperations[((i % npow) / n)], posOperations[(i % n)]])
|
||||
}
|
||||
}
|
||||
|
||||
func beautify(infix: String) -> String {
|
||||
let newString = infix as NSString
|
||||
|
||||
var 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!")
|
||||
}
|
||||
62
Task/24-game-Solve/Tcl/24-game-solve.tcl
Normal file
62
Task/24-game-Solve/Tcl/24-game-solve.tcl
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
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
|
||||
set permutations [struct::list map [struct::list permutations {a b c d}] \
|
||||
{apply {v {lassign $v a b c d; list A $a B $b C $c D $d}}}]
|
||||
# The permitted operations
|
||||
set operations {+ - * /}
|
||||
|
||||
# Given a list of four integers (precondition not checked!)
|
||||
# return a list of solutions to the 24 game using those four integers.
|
||||
proc find24GameSolutions {values} {
|
||||
global operations patterns permutations
|
||||
set found {}
|
||||
# For each possible structure with numbers at the leaves...
|
||||
foreach pattern $patterns {
|
||||
foreach permutation $permutations {
|
||||
set p [string map [subst {
|
||||
a [lindex $values 0].0
|
||||
b [lindex $values 1].0
|
||||
c [lindex $values 2].0
|
||||
d [lindex $values 3].0
|
||||
}] [string map $permutation $pattern]]
|
||||
|
||||
# For each possible structure with operators at the branches...
|
||||
foreach x $operations {
|
||||
foreach y $operations {
|
||||
foreach z $operations {
|
||||
set e [string map [subst {x $x y $y z $z}] $p]
|
||||
|
||||
# Try to evaluate (div-zero is an issue!) and add it to
|
||||
# the result if it is 24
|
||||
catch {
|
||||
if {[expr $e] == 24.0} {
|
||||
lappend found [string map {.0 {}} $e]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $found
|
||||
}
|
||||
|
||||
# Wrap the solution finder into a player
|
||||
proc print24GameSolutionFor {values} {
|
||||
set found [lsort -unique [find24GameSolutions $values]]
|
||||
if {![llength $found]} {
|
||||
puts "No solution possible"
|
||||
} else {
|
||||
puts "Total [llength $found] solutions (may include logical duplicates)"
|
||||
puts "First solution: [lindex $found 0]"
|
||||
}
|
||||
}
|
||||
print24GameSolutionFor $argv
|
||||
11
Task/24-game-Solve/Ursala/24-game-solve-1.ursala
Normal file
11
Task/24-game-Solve/Ursala/24-game-solve-1.ursala
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#import std
|
||||
#import nat
|
||||
#import rat
|
||||
|
||||
tree_shapes = "n". (@vLPiYo //eql iota "n")*~ (rep"n" ~&iiiK0NlrNCCVSPTs) {0^:<>}
|
||||
with_leaves = ^|DrlDrlK34SPSL/permutations ~&
|
||||
with_roots = ^DrlDrlK35dlPvVoPSPSL\~&r @lrhvdNCBvLPTo2DlS @hiNCSPtCx ~&K0=>
|
||||
value = *^ ~&v?\(@d ~&\1) ^|H\~&hthPX '+-*/'-$<sum,difference,product,quotient>
|
||||
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"
|
||||
3
Task/24-game-Solve/Ursala/24-game-solve-2.ursala
Normal file
3
Task/24-game-Solve/Ursala/24-game-solve-2.ursala
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#show+
|
||||
|
||||
test_games = mat` * pad` *K7 pad0 game24* <<2,3,8,9>,<5,7,4,1>,<5,6,7,8>>
|
||||
95
Task/24-game-Solve/Wren/24-game-solve.wren
Normal file
95
Task/24-game-Solve/Wren/24-game-solve.wren
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
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")
|
||||
}
|
||||
179
Task/24-game-Solve/Yabasic/24-game-solve.basic
Normal file
179
Task/24-game-Solve/Yabasic/24-game-solve.basic
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
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
|
||||
26
Task/24-game-Solve/Zkl/24-game-solve-1.zkl
Normal file
26
Task/24-game-Solve/Zkl/24-game-solve-1.zkl
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
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))")
|
||||
.pump(List,T("replace","d","%d"),T("replace",".","%s"));
|
||||
|
||||
fcn f2s(digits,ops,f){
|
||||
fts[f.name[1].toInt()].fmt(digits.zip(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) }]];
|
||||
}
|
||||
3
Task/24-game-Solve/Zkl/24-game-solve-2.zkl
Normal file
3
Task/24-game-Solve/Zkl/24-game-solve-2.zkl
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
solutions:=u(game24Solver(ask(0,"digits: ")));
|
||||
println(solutions.len()," solutions:");
|
||||
solutions.apply2(Console.println);
|
||||
Loading…
Add table
Add a link
Reference in a new issue