This commit is contained in:
Ingy döt Net 2013-04-10 21:29:02 -07:00
parent 764da6cbbb
commit db842d013d
19005 changed files with 197040 additions and 7 deletions

View file

@ -0,0 +1,23 @@
USING: bit-arrays formatting fry kernel math math.ranges
sequences ;
IN: rosetta.doors
CONSTANT: number-of-doors 100
: multiples ( n -- range )
0 number-of-doors rot <range> ;
: toggle-multiples ( n doors -- )
[ multiples ] dip '[ _ [ not ] change-nth ] each ;
: toggle-all-multiples ( doors -- )
[ number-of-doors [1,b] ] dip '[ _ toggle-multiples ] each ;
: print-doors ( doors -- )
[
swap "open" "closed" ? "Door %d is %s\n" printf
] each-index ;
: main ( -- )
number-of-doors 1 + <bit-array>
[ toggle-all-multiples ] [ print-doors ] bi ;

View file

@ -0,0 +1,11 @@
doors = arrayBuffer( 101, false )
for pass in [ 0 : doors.len() ]
for door in [ 0 : doors.len() : pass+1 ]
doors[ door ] = not doors[ door ]
end
end
for door in [ 1 : doors.len() ] // Show Output
> "Door ", $door, " is: ", ( doors[ door ] ) ? "open" : "closed"
end

View file

@ -0,0 +1 @@
for door in [ 1 : 101 ]: > "Door ", $door, " is: ", fract( door ** 0.5 ) ? "closed" : "open"

View file

@ -0,0 +1,5 @@
states := (1..100).toList
100.times |i| {
states = states.map |state| { state % (i+1) == 0 ? -state : +state }
}
echo("Open doors are " + states.findAll { it < 0 }.map { -it })

View file

@ -0,0 +1 @@
echo("Open doors are " + (1..100).toList.findAll { it.toFloat.pow(0.5f).toInt.pow(2) == it})

View file

@ -0,0 +1,18 @@
doors := function(n)
local a,j,s;
a := [ ];
for j in [1 .. n] do
a[j] := 0;
od;
for s in [1 .. n] do
j := s;
while j <= n do
a[j] := 1 - a[j];
j := j + s;
od;
od;
return Filtered([1 .. n], j -> a[j] = 1);
end;
doors(100);
# [ 1, 4, 9, 16, 25, 36, 49, 64, 81, 100 ]

View file

@ -0,0 +1,28 @@
var doors,a,i;
//Sets up the array for all of the doors.
for (i=1;i<=100;i+=1)
{
doors[i]=0;
}
//This first for loop goes through and passes the interval down to the next for loop.
for (i=1;i<=100;i+=1)
{
//This for loop opens or closes the doors and uses the interval(if interval is 2 it only uses every other etc..)
for (a=0;a<=100;a+=i;)
{
//Opens or closes a door.
doors[a]=!doors[a];
}
}
open_doors='';
//This for loop goes through the array and checks for open doors.
//If the door is open it adds it to the string then displays the string.
for (i=1;i<=100;i+=1)
{
if doors[i]=1
{
open_doors+="Door Number "+string(i)+" is open#";
}
}
show_message(open_doors);
game_end();

View file

@ -0,0 +1,4 @@
100:c;[{0}c*]:d;
c,{.c,>\)%{.d<\.d=1^\)d>++:d;}/}/
[c,{)"door "\+" is"+}%d{{"open"}{"closed"}if}%]zip
{" "*puts}/

View file

@ -0,0 +1,3 @@
100,{)}%
{:d.sqrt 2?=
{"open"}{"close"}if"door "d+" is "+\+puts}/

View file

@ -0,0 +1,4 @@
[{"close"}100*]:d;
10,{)2?(.d<\["open"]\)d>++:d;}/
[100,{)"door "\+" is"+}%d]zip
{" "*puts}/

View file

@ -0,0 +1,16 @@
uses java.util.Arrays
var doors = new boolean[100]
Arrays.fill( doors, false )
for( pass in 1..100 ) {
var counter = pass-1
while( counter < 100 ) {
doors[counter] = !doors[counter]
counter += pass
}
}
for( door in doors index i ) {
print( "door ${i+1} is ${door ? 'open' : 'closed'}" )
}

View file

@ -0,0 +1,12 @@
var door = 1
var delta = 0
for( i in 1..100 ) {
if( i == door ) {
print( "door ${i} is open" )
delta++
door += 2*delta + 1
} else {
print( "door ${i} is closed" )
}
}

View file

@ -0,0 +1,9 @@
doors = [false] * 100
(0..99).each {
it.step(100, it + 1) {
doors[it] ^= true
}
}
(0..99).each {
println("Door #${it + 1} is ${doors[it] ? 'open' : 'closed'}.")
}

View file

@ -0,0 +1,3 @@
(1..100).each {
println("Door #${it} is ${Math.sqrt(it).with{it==(int)it} ? 'open' : 'closed'}.")
}

View file

@ -0,0 +1,5 @@
doors = ['closed'] * 100
(1..10).each { doors[it**2 - 1] = 'open' }
(0..99).each {
println("Door #${it + 1} is ${doors[it]}.")
}

View file

@ -0,0 +1,18 @@
class RosettaDemo
{
static public function main()
{
findOpenLockers(100);
}
static function findOpenLockers(n : Int)
{
var i = 1;
while((i*i) <= n)
{
Sys.print(i*i + "\n");
i++;
}
}
}

View file

@ -0,0 +1,9 @@
REAL :: n=100, open=1, door(n)
door = 1 - open ! = closed
DO i = 1, n
DO j = i, n, i
door(j) = open - door(j)
ENDDO
ENDDO
DLG(Text=door, TItle=SUM(door)//" doors open")

View file

@ -0,0 +1,5 @@
door = 1 - open ! = closed
DO i = 1, n^0.5
door(i*i) = open
ENDDO
DLG(Text=door, TItle=SUM(door)//" doors open")

View file

@ -0,0 +1,7 @@
procedure main()
door := table(0) # default value of entries is 0
every pass := 1 to 100 do
every door[i := pass to 100 by pass] := 1 - door[i]
every write("Door ", i := 1 to 100, " is ", if door[i] = 1 then "open" else "closed")
end

View file

@ -0,0 +1,3 @@
procedure main()
every write("Door ", i := 1 to 100, " is ", if integer(sqrt(i)) = sqrt(i) then "open" else "closed")
end

View file

@ -0,0 +1,5 @@
procedure main(args)
dMap := table("closed")
every dMap[(1 to sqrt(100))^2] := "open"
every write("Door ",i := 1 to 100," is ",dMap[i])
end

View file

@ -0,0 +1,29 @@
Hallway is a room.
A toggle door is a kind of thing.
A toggle door can be open or closed. It is usually closed.
A toggle door has a number called the door number.
Understand the door number property as referring to a toggle door.
Rule for printing the name of a toggle door: say "door #[door number]".
There are 100 toggle doors.
When play begins (this is the initialize doors rule):
let the next door number be 1;
repeat with D running through toggle doors:
now the door number of D is the next door number;
increment the next door number.
To toggle (D - open toggle door): now D is closed.
To toggle (D - closed toggle door): now D is open.
When play begins (this is the solve puzzle rule):
let the door list be the list of toggle doors;
let the door count be the number of entries in the door list;
repeat with iteration running from 1 to 100:
let N be the iteration;
while N is less than the door count:
toggle entry N in the door list;
increase N by the iteration;
say "Doors left open: [list of open toggle doors].";
end the story.

View file

@ -0,0 +1,22 @@
MAIN
DEFINE
i, pass SMALLINT,
doors ARRAY[100] OF SMALLINT
FOR i = 1 TO 100
LET doors[i] = FALSE
END FOR
FOR pass = 1 TO 100
FOR i = pass TO 100 STEP pass
LET doors[i] = NOT doors[i]
END FOR
END FOR
FOR i = 1 TO 100
IF doors[i]
THEN DISPLAY i USING "Door <<& is open"
ELSE DISPLAY i USING "Door <<& is closed"
END IF
END FOR
END MAIN

View file

@ -0,0 +1,6 @@
doors := List clone
for(i,1,100, doors append(false))
for(i,1,100,
for(x,i,100, i, doors atPut(x - 1, doors at(x - 1) not))
)
doors foreach(i, x, if(x, "Door #{i + 1} is open" interpolate println))

View file

@ -0,0 +1,21 @@
NDoors = Origin mimic
NDoors Toggle = Origin mimic do(
initialize = method(toggled?, @toggled? = toggled?)
toggle! = method(@toggled? = !toggled?. self)
)
NDoors Doors = Origin mimic do(
initialize = method(n,
@n = n
@doors = {} addKeysAndValues(1..n, (1..n) map(_, NDoors Toggle mimic(false)))
)
numsToToggle = method(n, for(x <- (1..@n), (x % n) zero?, x))
toggleThese = method(nums, nums each(x, @doors[x] = @doors at(x) toggle))
show = method(@doors filter:dict(value toggled?) keys sort println)
)
; Test code
x = NDoors Doors mimic(100)
(1..100) each(n, x toggleThese(x numsToToggle(n)))
x show

View file

@ -0,0 +1,4 @@
~:/ (100 $ - {. 1:)"0 >:i.100
1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ...
~:/ 0=|/~ >:i.100 NB. alternative
1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ...

View file

@ -0,0 +1,4 @@
(e. *:) 1+i.100
1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ...
1 (<:*:i.10)} 100$0 NB. alternative
1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ...

View file

@ -0,0 +1,4 @@
'these doors are open' ; >: I. (>:i.100) e. *: i.11
┌────────────────────┬───────────────────────────┐
│these doors are open│1 4 9 16 25 36 49 64 81 100│
└────────────────────┴───────────────────────────┘

View file

@ -0,0 +1,5 @@
doors = falses(100)
for a = 1:100, b in a:a:100
doors[b] = !doors[b]
end
for a = 1:100 println("Door $a is " * (doors[a] ? "open" : "close") ) end

View file

@ -0,0 +1 @@
for i = 1:10 println("Door $(i^2) is open") end

View file

@ -0,0 +1 @@
`closed `open ![ ; 2 ] @ #:' 1 _ = ,/ &:' 0 = t !\:/: t : ! 101

View file

@ -0,0 +1 @@
( 1 + ! 10 ) ^ 2

View file

@ -0,0 +1 @@
{ ( 1 + ! _ x ^ % 2 ) ^ 2 } 100

View file

@ -0,0 +1,27 @@
HAI 1.3
I HAS A doors ITZ A BUKKIT
IM IN YR hallway UPPIN YR door TIL BOTH SAEM door AN 100
doors HAS A SRS door ITZ FAIL BTW, INISHULIZE ALL TEH DOORZ AS CLOZD
IM OUTTA YR hallway
IM IN YR hallway UPPIN YR pass TIL BOTH SAEM pass AN 100
I HAS A door ITZ pass
IM IN YR passer
doors'Z SRS door R NOT doors'Z SRS door
door R SUM OF door AN SUM OF pass AN 1
DIFFRINT door AN SMALLR OF door AN 99, O RLY?
YA RLY, GTFO
OIC
IM OUTTA YR passer
IM OUTTA YR hallway
IM IN YR printer UPPIN YR door TIL BOTH SAEM door AN 100
VISIBLE "Door #" SUM OF door AN 1 " is "!
doors'Z SRS door, O RLY?
YA RLY, VISIBLE "open."
NO WAI, VISIBLE "closed."
OIC
IM OUTTA YR printer
KTHXBYE

View file

@ -0,0 +1,30 @@
to doors
;Problem 100 Doors
;Lhogho
for "p [1 100]
[
make :p "false
]
for "a [1 100 1]
[
for "b [:a 100 :a]
[
if :b < 101
[
make :b not thing :b
]
]
]
for "c [1 100]
[
if thing :c
[
(print "door :c "is "open)
]
]
end
doors

View file

@ -0,0 +1,10 @@
dim doors(100)
for pass = 1 to 100
for door = pass to 100 step pass
doors(door) = not(doors(door))
next door
next pass
print "open doors ";
for door = 1 to 100
if doors(door) then print door;" ";
next door

View file

@ -0,0 +1,14 @@
to doors
;Problem 100 Doors
;FMSLogo
;lrcvs 2010
make "door (vector 100 1)
for [p 1 100][setitem :p :door 0]
for [a 1 100 1][for [b :a 100 :a][make "x item :b :door
ifelse :x = 0 [setitem :b :door 1][setitem :b :door 0] ] ]
for [c 1 100][make "y item :c :door
ifelse :y = 0 [pr (list :c "Close)] [pr (list :c "Open)] ]
end

View file

@ -0,0 +1,10 @@
define(`_set', `define(`$1[$2]', `$3')')dnl
define(`_get', `defn(`$1[$2]')')dnl
define(`for',`ifelse($#,0,``$0'',`ifelse(eval($2<=$3),1,
`pushdef(`$1',$2)$5`'popdef(`$1')$0(`$1',eval($2+$4),$3,$4,`$5')')')')dnl
define(`opposite',`_set(`door',$1,ifelse(_get(`door',$1),`closed',`open',`closed'))')dnl
define(`upper',`100')dnl
for(`x',`1',upper,`1',`_set(`door',x,`closed')')dnl
for(`x',`1',upper,`1',`for(`y',x,upper,x,`opposite(y)')')dnl
for(`x',`1',upper,`1',`door x is _get(`door',x)
')dnl

View file

@ -0,0 +1,14 @@
doorsOpen = for i in 1 to 100 collect false
for pass in 1 to 100 do
(
for door in pass to 100 by pass do
(
doorsOpen[door] = not doorsOpen[door]
)
)
for i in 1 to doorsOpen.count do
(
format ("Door % is open?: %\n") i doorsOpen[i]
)

View file

@ -0,0 +1,5 @@
for i in 1 to 100 do
(
root = pow i 0.5
format ("Door % is open?: %\n") i (root == (root as integer))
)

View file

@ -0,0 +1,63 @@
.data
doors: .space 100
num_str: .asciiz "Number "
comma_gap: .asciiz " is "
newline: .asciiz "\n"
.text
main:
# Clear all the cells to zero
li $t1, 100
la $t2, doors
clear_loop:
sb $0, ($t2)
add $t2, $t2, 1
sub $t1, $t1, 1
bnez $t1, clear_loop
# Now start the loops
li $t0, 1 # This will the the step size
li $t4, 1 # just an arbitrary 1
loop1:
move $t1, $t0 # Counter
la $t2, doors # Current pointer
add $t2, $t2, $t0
addi $t2, $t2, -1
loop2:
lb $t3, ($t2)
sub $t3, $t4, $t3
sb $t3, ($t2)
add $t1, $t1, $t0
add $t2, $t2, $t0
ble $t1, 100, loop2
addi $t0, $t0, 1
ble $t0, 100, loop1
# Now display everything
la $t0, doors
li $t1, 1
loop3:
li $v0, 4
la $a0, num_str
syscall
li $v0, 1
move $a0, $t1
syscall
li $v0, 4
la $a0, comma_gap
syscall
li $v0, 1
lb $a0, ($t0)
syscall
li $v0, 4,
la $a0, newline
syscall
addi $t0, $t0, 1
addi $t1, $t1, 1
bne $t1, 101 loop3

View file

@ -0,0 +1,41 @@
MCSKIP "WITH" NL
"" 100 doors
MCINS %.
MCSKIP MT,<>
"" Doors represented by P1-P100, 0 is closed
MCPVAR 100
"" Set P variables to 0
MCDEF ZEROPS WITHS NL AS <MCSET T1=1
%L1.MCSET PT1=0
MCSET T1=T1+1
MCGO L1 UNLESS T1 EN 101
>
ZEROPS
"" Generate door state
MCDEF STATE WITHS () AS <MCSET T1=%A1.
MCGO L1 UNLESS T1 EN 0
closed<>MCGO L0
%L1.open>
"" Main macro - no arguments
"" T1 is pass number
"" T2 is door number
MCDEF DOORS WITHS NL
AS <MCSET T1=1
"" pass loop
%L1.MCGO L4 IF T1 GR 100
"" door loop
MCSET T2=T1
%L2.MCGO L3 IF T2 GR 100
MCSET PT2=1-PT2
MCSET T2=T2+T1
MCGO L2
%L3.MCSET T1=T1+1
MCGO L1
%L4."" now output the result
MCSET T1=1
%L5.door %T1. is STATE(%PT1.)
MCSET T1=T1+1
MCGO L5 UNLESS T1 GR 100
>
"" Do it
DOORS

View file

@ -0,0 +1,14 @@
is_open = make(100);
for pass in [1..100]
for door in [pass..100]
if (door % pass)
continue;
endif
is_open[door] = !is_open[door];
endfor
endfor
"output the result";
for door in [1..100]
player:tell("door #", door, " is ", (is_open[door] ? "open" : "closed"), ".");
endfor

View file

@ -0,0 +1,18 @@
doors new door,pass
For door=1:1:100 Set door(door)=0
For pass=1:1:100 For door=pass:pass:100 Set door(door)='door(door)
For door=1:1:100 If door(door) Write !,"Door",$j(door,4)," is open"
Write !,"All other doors are closed."
Quit
Do doors
Door 1 is open
Door 4 is open
Door 9 is open
Door 16 is open
Door 25 is open
Door 36 is open
Door 49 is open
Door 64 is open
Door 81 is open
Door 100 is open
All other doors are closed.

View file

@ -0,0 +1,16 @@
NDoors := proc( N :: posint )
# Initialise, using 0 to represent "closed"
local doors := Array( 1 .. N, 'datatype' = 'integer'[ 1 ] );
# Now do N passes
for local pass from 1 to N do
for local door from pass by pass while door <= N do
doors[ door ] := 1 - doors[ door ]
end do
end do;
# Output
for door from 1 to N do
printf( "Door %d is %s.\n", door, `if`( doors[ door ] = 0, "closed", "open" ) )
end do;
# Since this is a printing routine, return nothing.
NULL
end proc:

View file

@ -0,0 +1 @@
> NDoors( 100 );

View file

@ -0,0 +1,2 @@
> seq( i^2, i = 1 .. isqrt( 100 ) );
1, 4, 9, 16, 25, 36, 49, 64, 81, 100

View file

@ -0,0 +1,2 @@
> [seq]( 1 .. 10 )^~2;
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

View file

@ -0,0 +1,3 @@
f[n_] = "Closed";
Do[Do[If[f[n] == "Closed", f[n] = "Open", f[n] = "Closed"], {n, k, 100, k}], {k, 1, 100}];
Table[f[n], {n, 1, 100}]

View file

@ -0,0 +1 @@
Do[Print["door ",i," is ",If[IntegerQ[Sqrt[i]],"open","closed"]],{i,100}]

View file

@ -0,0 +1,3 @@
n=100;
a=Range[1,Sqrt[n]]^2
Do[Print["door ",i," is ",If[MemberQ[a,i],"open","closed"]],{i,100}]

View file

@ -0,0 +1,12 @@
n=100
nn=1
a=0
For[i=1,i<=n,i++,
If[i==nn,
Print["door ",i," is open"];
a++;
nn+=2a+1;
,
Print["door ",i," is closed"];
];
]

View file

@ -0,0 +1 @@
Pick[Range[100], Xor@@@Array[Divisible[#1,#2]&, {100,100}]]

View file

@ -0,0 +1 @@
Range[Sqrt[100]]^2

View file

@ -0,0 +1,10 @@
doors(n) := block([v: makelist(i, i, 1, n)],
for i from 2 thru n do
for j from i step i while j <= n do v[j]: -v[j],
sublist(v, ?plusp))$
doors(100);
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
/* Note: ?plusp is a Lisp function. Maxima has nonnegintegerp, which is equivalent,
but it needs load(linearalgebra)$ first. */

View file

@ -0,0 +1,33 @@
:- module doors.
:- interface.
:- import_module array, io, int.
:- type door ---> open ; closed.
:- type doors == array(door).
:- func toggle(door) = door.
:- pred walk(int::in, doors::in, doors::out) is semidet.
:- pred walks(int::in, int::in, doors::in, doors::out) is det.
:- pred main(io::di, io::uo) is det.
:- implementation.
toggle(open) = closed.
toggle(closed) = open.
walk(N, !D) :- walk(N, N, !D).
:- pred walk(int::in, int::in, doors::in, doors::out) is semidet.
walk(At, By, !D) :-
semidet_lookup(!.D, At - 1, Door),
slow_set(!.D, At - 1, toggle(Door), !:D),
( walk(At + By, By, !D) -> true ; true ).
walks(N, End, !D) :-
( N =< End, walk(N, !D) -> walks(N + 1, End, !D) ; true ).
main(!IO) :-
io.write(Doors1, !IO), io.nl(!IO),
array.init(100, closed, Doors0),
walks(1, 100, Doors0, Doors1).

View file

@ -0,0 +1,11 @@
boolean doors[];
for i = 1 upto 100: doors[i] := false; endfor
for i = 1 upto 100:
for j = 1 step i until 100:
doors[j] := not doors[j];
endfor
endfor
for i = 1 upto 100:
message decimal(i) & " " & if doors[i]: "open" else: "close" fi;
endfor
end

View file

@ -0,0 +1,44 @@
import java.util.ArrayList
class Door
:state
def initialize
@state=false
end
def closed?; !@state; end
def open?; @state; end
def close; @state=false; end
def open; @state=true; end
def toggle
if closed?
open
else
close
end
end
def toString; Boolean.toString(@state); end
end
doors=ArrayList.new
1.upto(100) do
doors.add(Door.new)
end
1.upto(100) do |multiplier|
index = 0
doors.each do |door|
Door(door).toggle if (index+1)%multiplier == 0
index += 1
end
end
i = 0
doors.each do |door|
puts "Door #{i+1} is #{door}."
i+=1
end

View file

@ -0,0 +1,36 @@
MODULE Doors;
IMPORT InOut;
TYPE State = (Closed, Open);
TYPE List = ARRAY [1 .. 100] OF State;
VAR
Doors: List;
I, J: CARDINAL;
BEGIN
FOR I := 1 TO 100 DO
FOR J := 1 TO 100 DO
IF J MOD I = 0 THEN
IF Doors[J] = Closed THEN
Doors[J] := Open
ELSE
Doors[J] := Closed
END
END
END
END;
FOR I := 1 TO 100 DO
InOut.WriteCard(I, 3);
InOut.WriteString(' is ');
IF Doors[I] = Closed THEN
InOut.WriteString('Closed.')
ELSE
InOut.WriteString('Open.')
END;
InOut.WriteLn
END
END Doors.

View file

@ -0,0 +1,26 @@
MODULE DoorsOpt;
IMPORT InOut;
TYPE State = (Closed, Open);
TYPE List = ARRAY [1 .. 100] OF State;
VAR
Doors: List;
I: CARDINAL;
BEGIN
FOR I := 1 TO 10 DO
Doors[I*I] := Open
END;
FOR I := 1 TO 100 DO
InOut.WriteCard(I, 3);
InOut.WriteString(' is ');
IF Doors[I] = Closed THEN
InOut.WriteString('Closed.')
ELSE
InOut.WriteString('Open.')
END;
InOut.WriteLn
END
END DoorsOpt.

View file

@ -0,0 +1,31 @@
MODULE Doors EXPORTS Main;
IMPORT IO, Fmt;
TYPE State = {Closed, Open};
TYPE List = ARRAY [1..100] OF State;
VAR doors := List{State.Closed, ..};
BEGIN
FOR i := 1 TO 100 DO
FOR j := FIRST(doors) TO LAST(doors) DO
IF j MOD i = 0 THEN
IF doors[j] = State.Closed THEN
doors[j] := State.Open;
ELSE
doors[j] := State.Closed;
END;
END;
END;
END;
FOR i := FIRST(doors) TO LAST(doors) DO
IO.Put(Fmt.Int(i) & " is ");
IF doors[i] = State.Closed THEN
IO.Put("Closed.\n");
ELSE
IO.Put("Open.\n");
END;
END;
END Doors.

View file

@ -0,0 +1,23 @@
MODULE DoorsOpt EXPORTS Main;
IMPORT IO, Fmt;
TYPE State = {Closed, Open};
TYPE List = ARRAY [1..100] OF State;
VAR doors := List{State.Closed, ..};
BEGIN
FOR i := 1 TO 10 DO
doors[i * i] := State.Open;
END;
FOR i := FIRST(doors) TO LAST(doors) DO
IO.Put(Fmt.Int(i) & " is ");
IF doors[i] = State.Closed THEN
IO.Put("Closed.\n");
ELSE
IO.Put("Open.\n");
END;
END;
END DoorsOpt.

View file

@ -0,0 +1,6 @@
Write a function that given four digits subject to the rules of the [[24 game]], computes an expression to solve the game if possible.
Show examples of solutions generated by the function
C.F: [[Arithmetic Evaluator]]

View 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.

View 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

View 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
}

View 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

View file

@ -0,0 +1,141 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define n_cards 4
#define solve_goal 24
#define max_digit 9
typedef struct { int num, denom; } frac_t, *frac;
typedef enum { C_NUM = 0, C_ADD, C_SUB, C_MUL, C_DIV, } op_type;
typedef struct expr_t *expr;
typedef struct expr_t {
op_type op;
expr left, right;
int value;
} expr_t;
void show_expr(expr e, op_type prec, int is_right)
{
const char * op;
switch(e->op) {
case C_NUM: printf("%d", e->value);
return;
case C_ADD: op = " + "; break;
case C_SUB: op = " - "; break;
case C_MUL: op = " x "; break;
case C_DIV: op = " / "; break;
}
if ((e->op == prec && is_right) || e->op < prec) printf("(");
show_expr(e->left, e->op, 0);
printf("%s", op);
show_expr(e->right, e->op, 1);
if ((e->op == prec && is_right) || e->op < prec) printf(")");
}
void eval_expr(expr e, frac f)
{
frac_t left, right;
if (e->op == C_NUM) {
f->num = e->value;
f->denom = 1;
return;
}
eval_expr(e->left, &left);
eval_expr(e->right, &right);
switch (e->op) {
case C_ADD:
f->num = left.num * right.denom + left.denom * right.num;
f->denom = left.denom * right.denom;
return;
case C_SUB:
f->num = left.num * right.denom - left.denom * right.num;
f->denom = left.denom * right.denom;
return;
case C_MUL:
f->num = left.num * right.num;
f->denom = left.denom * right.denom;
return;
case C_DIV:
f->num = left.num * right.denom;
f->denom = left.denom * right.num;
return;
default:
fprintf(stderr, "Unknown op: %d\n", e->op);
return;
}
}
int solve(expr ex_in[], int len)
{
int i, j;
expr_t node;
expr ex[n_cards];
frac_t final;
if (len == 1) {
eval_expr(ex_in[0], &final);
if (final.num == final.denom * solve_goal && final.denom) {
show_expr(ex_in[0], 0, 0);
return 1;
}
return 0;
}
for (i = 0; i < len - 1; i++) {
for (j = i + 1; j < len; j++)
ex[j - 1] = ex_in[j];
ex[i] = &node;
for (j = i + 1; j < len; j++) {
node.left = ex_in[i];
node.right = ex_in[j];
for (node.op = C_ADD; node.op <= C_DIV; node.op++)
if (solve(ex, len - 1))
return 1;
node.left = ex_in[j];
node.right = ex_in[i];
node.op = C_SUB;
if (solve(ex, len - 1)) return 1;
node.op = C_DIV;
if (solve(ex, len - 1)) return 1;
ex[j] = ex_in[j];
}
ex[i] = ex_in[i];
}
return 0;
}
int solve24(int n[])
{
int i;
expr_t ex[n_cards];
expr e[n_cards];
for (i = 0; i < n_cards; i++) {
e[i] = ex + i;
ex[i].op = C_NUM;
ex[i].left = ex[i].right = 0;
ex[i].value = n[i];
}
return solve(e, n_cards);
}
int main()
{
int i, j, n[] = { 3, 3, 8, 8, 9 };
srand(time(0));
for (j = 0; j < 10; j++) {
for (i = 0; i < n_cards; i++) {
n[i] = 1 + (double) rand() * max_digit / RAND_MAX;
printf(" %d", n[i]);
}
printf(": ");
printf(solve24(n) ? "\n" : "No solution\n");
}
return 0;
}

View file

@ -0,0 +1,30 @@
(use 'clojure.contrib.combinatorics)
(defn nested-replace [l m]
(cond
(= l '()) '()
(m (first l)) (concat (list (m (first l))) (nested-replace (rest l) m))
(seq? (first l)) (concat (list (nested-replace (first l) m)) (nested-replace (rest l) m))
true (concat (list (first l)) (nested-replace (rest l) m))))
(defn format-solution [sol]
(cond
(number? sol) sol
(seq? sol)
(list (format-solution (second sol)) (first sol) (format-solution (nth sol 2)))))
(defn play24 [& digits] (count (map #(-> % format-solution println)
(let [operator-map-list (map (fn [a] {:op1 (nth a 0) :op2 (nth a 1) :op3 (nth a 2)})
(selections '(* + - /) 3))
digits-map-list
(map (fn [a] {:num1 (nth a 0) :num2 (nth a 1) :num3 (nth a 2) :num4 (nth a 3)})
(permutations digits))
patterns-list (list
'(:op1 (:op2 :num1 :num2) (:op3 :num3 :num4))
'(:op1 :num1 (:op2 :num2 (:op3 :num3 :num4))))
;other patterns can be added here, e.g. '(:op1 (:op2 (:op3 :num1 :num2) :num3) :num4)
op-subbed (reduce concat '()
(map (fn [a] (map #(nested-replace a % ) operator-map-list)) patterns-list))
full-subbed (reduce concat '()
(map (fn [a] (map #(nested-replace % a) op-subbed)) digits-map-list))]
(filter #(= (try (eval %) (catch Exception e nil)) 24) full-subbed)))))

View 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'}"

View file

@ -0,0 +1,16 @@
> coffee 24_game.coffee
Solution for 8,3,1,8: ((1 + 8) * (8 / 3))
Solution for 6,9,5,7: (6 - ((5 - 7) * 9))
Solution for 4,2,1,1: no solution
Solution for 3,5,1,3: (((3 + 5) * 1) * 3)
Solution for 6,4,1,7: ((7 - (4 - 1)) * 6)
Solution for 8,1,3,1: (((8 + 1) - 1) * 3)
Solution for 6,1,3,3: (((6 + 1) * 3) + 3)
Solution for 7,1,5,6: (((7 - 1) * 5) - 6)
Solution for 4,2,3,1: ((3 + 1) * (4 + 2))
Solution for 8,8,5,8: ((5 * 8) - (8 + 8))
Solution for 3,8,4,1: ((1 - (3 - 8)) * 4)
Solution for 6,4,3,8: ((8 - (6 / 3)) * 4)
Solution for 2,1,8,7: (((2 * 8) + 1) + 7)
Solution for 5,2,7,5: ((2 * 7) + (5 + 5))
Solution for 2,4,8,9: ((9 - (2 + 4)) * 8)

View 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))

View file

@ -0,0 +1,47 @@
import std.stdio, std.algorithm, std.range, std.typecons, std.conv,
std.string, permutations2, arithmetic_rational;
string solve(in int target, in int[] problem) {
static struct ComputeAllOperations {
//static struct T { Rational r; string e; }
alias T = Tuple!(Rational,"r", string,"e");
Rational[] L;
int opApply(in int delegate(ref T) dg) {
int result;
if (!L.empty) {
auto x = L[0];
auto xs = L[1 .. $];
if (L.length == 1) {
T aux = T(x, text(x));
result = dg(aux);
} else {
OUTER: foreach (o; ComputeAllOperations(xs)) {
auto y = o.r;
auto sub = [T(x * y, "*"), T(x + y, "+"), T(x - y, "-")];
if (y) sub ~= [T(x/y, "/")];
foreach (e; sub) {
auto aux = T(e.r, format("(%s%s%s)", x, e.e, o.e));
result = dg(aux); if (result) break OUTER;
}
}
}
}
return result;
}
}
foreach (p; problem.map!Rational.array.permutations)
foreach (sol; ComputeAllOperations(p))
if (sol.r == target)
return sol.e;
return "No solution";
}
void main() {
foreach (prob; [[6, 7, 9, 5], [3, 3, 8, 8], [1, 1, 1, 1]])
writeln(prob, ": ", solve(24, prob));
}

View 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

View 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

View 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

View 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

View 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/-/"

View 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 {
case x.op == op_add:
f.num = l.num*r.denom + l.denom*r.num
f.denom = l.denom * r.denom
return
case x.op == op_sub:
f.num = l.num*r.denom - l.denom*r.num
f.denom = l.denom * r.denom
return
case x.op == op_mul:
f.num = l.num * r.num
f.denom = l.denom * r.denom
return
case x.op == 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")
}
}
}

View 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!" )
}

View 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)

View 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

View 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

View 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");

View 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

View 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)

View 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}])]

View file

@ -0,0 +1 @@
game24play[RandomInteger[{1, 9}, 4]]

View file

@ -0,0 +1,54 @@
# Fischer-Krause ordered permutation generator
# http://faq.perl.org/perlfaq4.html#How_do_I_permute_N_e
sub permute (&@) {
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;
}
}
}
}

View 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

View 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]).

View file

@ -0,0 +1,159 @@
'''
The 24 Game Player
Given any four digits in the range 1 to 9, which may have repetitions,
Using just the +, -, *, and / operators; and the possible use of
brackets, (), show how to make an answer of 24.
An answer of "q" will quit the game.
An answer of "!" will generate a new set of four digits.
An answer of "!!" will ask you for a new set of four digits.
An answer of "?" will compute an expression for the current digits.
Otherwise you are repeatedly asked for an expression until it evaluates to 24
Note: you cannot form multiple digit numbers from the supplied digits,
so an answer of 12+12 when given 1, 2, 2, and 1 would not be allowed.
'''
from __future__ import division, print_function
from itertools import permutations, combinations, product, \
chain
from pprint import pprint as pp
from fractions import Fraction as F
import random, ast, re
import sys
if sys.version_info[0] < 3:
input = raw_input
from itertools import izip_longest as zip_longest
else:
from itertools import zip_longest
def choose4():
'four random digits >0 as characters'
return [str(random.randint(1,9)) for i in range(4)]
def ask4():
'get four random digits >0 from the player'
digits = ''
while len(digits) != 4 or not all(d in '123456789' for d in digits):
digits = input('Enter the digits to solve for: ')
digits = ''.join(digits.strip().split())
return list(digits)
def welcome(digits):
print (__doc__)
print ("Your four digits: " + ' '.join(digits))
def check(answer, digits):
allowed = set('() +-*/\t'+''.join(digits))
ok = all(ch in allowed for ch in answer) and \
all(digits.count(dig) == answer.count(dig) for dig in set(digits)) \
and not re.search('\d\d', answer)
if ok:
try:
ast.parse(answer)
except:
ok = False
return ok
def solve(digits):
"""\
>>> for digits in '3246 4788 1111 123456 1127 3838'.split():
solve(list(digits))
Solution found: 2 + 3 * 6 + 4
'2 + 3 * 6 + 4'
Solution found: ( 4 + 7 - 8 ) * 8
'( 4 + 7 - 8 ) * 8'
No solution found for: 1 1 1 1
'!'
Solution found: 1 + 2 + 3 * ( 4 + 5 ) - 6
'1 + 2 + 3 * ( 4 + 5 ) - 6'
Solution found: ( 1 + 2 ) * ( 1 + 7 )
'( 1 + 2 ) * ( 1 + 7 )'
Solution found: 8 / ( 3 - 8 / 3 )
'8 / ( 3 - 8 / 3 )'
>>> """
digilen = len(digits)
# length of an exp without brackets
exprlen = 2 * digilen - 1
# permute all the digits
digiperm = sorted(set(permutations(digits)))
# All the possible operator combinations
opcomb = list(product('+-*/', repeat=digilen-1))
# All the bracket insertion points:
brackets = ( [()] + [(x,y)
for x in range(0, exprlen, 2)
for y in range(x+4, exprlen+2, 2)
if (x,y) != (0,exprlen+1)]
+ [(0, 3+1, 4+2, 7+3)] ) # double brackets case
for d in digiperm:
for ops in opcomb:
if '/' in ops:
d2 = [('F(%s)' % i) for i in d] # Use Fractions for accuracy
else:
d2 = d
ex = list(chain.from_iterable(zip_longest(d2, ops, fillvalue='')))
for b in brackets:
exp = ex[::]
for insertpoint, bracket in zip(b, '()'*(len(b)//2)):
exp.insert(insertpoint, bracket)
txt = ''.join(exp)
try:
num = eval(txt)
except ZeroDivisionError:
continue
if num == 24:
if '/' in ops:
exp = [ (term if not term.startswith('F(') else term[2])
for term in exp ]
ans = ' '.join(exp).rstrip()
print ("Solution found:",ans)
return ans
print ("No solution found for:", ' '.join(digits))
return '!'
def main():
digits = choose4()
welcome(digits)
trial = 0
answer = ''
chk = ans = False
while not (chk and ans == 24):
trial +=1
answer = input("Expression %i: " % trial)
chk = check(answer, digits)
if answer == '?':
solve(digits)
answer = '!'
if answer.lower() == 'q':
break
if answer == '!':
digits = choose4()
trial = 0
print ("\nNew digits:", ' '.join(digits))
continue
if answer == '!!':
digits = ask4()
trial = 0
print ("\nNew digits:", ' '.join(digits))
continue
if not chk:
print ("The input '%s' was wonky!" % answer)
else:
if '/' in answer:
# Use Fractions for accuracy in divisions
answer = ''.join( (('F(%s)' % char) if char in '123456789' else char)
for char in answer )
ans = eval(answer)
print (" = ", ans)
if ans == 24:
print ("Thats right!")
print ("Thank you and goodbye")
main()

View 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)
}

View 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)

View file

@ -0,0 +1,99 @@
/*REXX program to help the user find solutions to the game of 24. */
/* ┌──────────────────────────────────────────────────────────────────┐
Argument is either of two forms: ssss ==or== ssss-ffff
where one or both strings must be exactly four numerals (digits)
comprised soley of the numerals (digits) 1 > 9 (no zeroes).
In SSSS-FFFF SSSS is the start,
FFFF is the start.
*/
parse arg orig /*get the guess from the argument. */
parse var orig start '-' finish /*get the start and finish (maybe). */
start=space(start,0) /*remove any blanks from the START. */
finish=space(finish,0) /*remove any blanks from the FINISH. */
finish=word(finish start,1) /*if no FINISH specified, use START.*/
digs=123456789 /*numerals (digits) that can be used. */
call validate start
call validate finish
opers='+-*/' /*define the legal arithmetic operators*/
ops=length(opers) /* ... and the count of them (length). */
do j=1 for ops /*define a version for fast execution. */
o.j=substr(opers,j,1)
end /*j*/
finds=0 /*number of found solutions (so far). */
x.=0 /*a method to hold unique expressions. */
indent=left('',30) /*used to indent display of solutions. */
/*alternative: indent=copies(' ',30) */
Lpar='(' /*a string to make REXX code prettier. */
Rpar=')' /*ditto. */
do g=start to finish /*process a (possible) range of values.*/
if pos(0,g)\==0 then iterate /*ignore values with zero in them. */
do _=1 for 4 /*define versions for faster execution.*/
g._=substr(g,_,1)
end /*_*/
do i=1 for ops /*insert an operator after 1st number. */
do j=1 for ops /*insert an operator after 2nd number. */
do k=1 for ops /*insert an operator after 2nd number. */
do m=0 to 3; L.= /*assume no left parenthesis so far. */
do n=m+1 to 4 /*match left paren with a right paren. */
L.m=Lpar /*define a left paren, m=0 means ignore*/
R.="" /*un-define all right parenthesis. */
if m==1 & n==2 then L.="" /*special case: (n)+ ... */
else if m\==0 then R.n=Rpar /*no (, no )*/
e= L.1 g.1 o.i L.2 g.2 o.j L.3 g.3 R.3 o.k g.4 R.4
e=space(e,0) /*remove all blanks from the expression*/
/*(below) change expression: */
/* /(yyy) ===> /div(yyy) */
/*Enables to check for division by zero*/
origE=e /*keep old version for the display. */
if pos('/(',e)\==0 then e=changestr('/(',e,"/div(")
/*The above could be replaced by: */
/* e=changestr('/(',e,"/div(") */
/*INTERPRET stresses REXX's groin, so */
/* try to avoid repeated heavy lifting.*/
if x.e then iterate /*was the expression already used? */
x.e=1 /*mark this expression as unique. */
/*have REXX do the heavy lifting (ugh).*/
interpret 'x=' e /*... strain... */
x=x/1 /*remove trailing decimal points(maybe)*/
if x\==24 then iterate /*Not correct? Try again. */
finds=finds+1 /*bump number of found solutions. */
_=translate(origE, '][', ")(") /*show [], not (). */
say indent 'a solution:' _ /*display a solution. */
end /*n*/
end /*m*/
end /*k*/
end /*j*/
end /*i*/
end /*g*/
sols=finds
if sols==0 then sols='No' /*make the sentence not so geek-like. */
say; say sols 'unique solution's(finds) "found for" orig /*pluralize.*/
exit
/*───────────────────────────DIV subroutine─────────────────────────────*/
div: procedure; parse arg q /*tests if dividing by 0 (zero). */
if q=0 then q=1e9 /*if dividing by zero, change divisor. */
return q /*changing Q invalidates the expression*/
/*───────────────────────────GER subroutine─────────────────────────────*/
ger: say; say '*** error! ***'; if _\=='' then say 'guess=' _
say arg(1); say; exit 13
/*───────────────────────────S subroutine───────────────────────────────*/
s: if arg(1)==1 then return ''; return 's' /*simple pluralizer.*/
/*───────────────────────────validate subroutine────────────────────────*/
validate: parse arg y; errCode=0; _v=verify(y,digs)
select
when y=='' then call ger 'no digits entered.'
when length(y)<4 then call ger 'not enough digits entered, must be 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

View file

@ -0,0 +1,57 @@
require 'rational'
class TwentyFourGamePlayer
EXPRESSIONS = [
'((%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))',
]
OPERATORS = [:+, :-, :*, :/]
@@objective = Rational(24,1)
def initialize(digits)
@digits = digits
@solutions = []
solve
end
attr_reader :digits, :solutions
def solve
digits.permutation.to_a.uniq.each do |a,b,c,d|
OPERATORS.each do |op1|
OPERATORS.each do |op2|
OPERATORS.each do |op3|
EXPRESSIONS.each do |expr|
# evaluate using rational arithmetic
test = expr.gsub('%d', 'Rational(%d,1)') % [a, op1, b, op2, c, op3, d]
value = eval(test) rescue -1 # catch division by zero
if value == @@objective
@solutions << expr % [a, op1, b, op2, c, op3, d]
end
end;end;end;end
end
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}"
player = TwentyFourGamePlayer.new(digits)
if player.solutions.empty?
puts "no solutions"
else
puts "found #{player.solutions.size} solutions, including #{player.solutions.first}"
puts player.solutions.sort.join("\n")
end

View 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)

View 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

View file

@ -0,0 +1,71 @@
load compiler
function genRandomNumbers( amount )
rtn = []
for i in [ 0 : amount ]: rtn += random( 1, 9 )
return( rtn )
end
function getAnswer( exp )
ic = ICompiler()
ic.compileAll(exp)
return( ic.result )
end
function validInput( str )
for i in [ 0 : str.len() ]
if str[i] notin ' ()[]0123456789-+/*'
> 'INVALID Character = ', str[i]
return( false )
end
end
return( true )
end
printl('
The 24 Game
Given any four digits in the range 1 to 9, which may have repetitions,
Using just the +, -, *, and / operators; and the possible use of
brackets, (), show how to make an answer of 24.
An answer of "q" will quit the game.
An answer of "!" will generate a new set of four digits.
Otherwise you are repeatedly asked for an expression until it evaluates to 24
Note: you cannot form multiple digit numbers from the supplied digits,
so an answer of 12+12 when given 1, 2, 2, and 1 would not be allowed.
')
num = genRandomNumbers( 4 )
while( true )
>> "Here are the numbers to choose from: "
map({ a => print(a, " ") }, num)
>
exp = input()
switch exp
case "q", "Q"
exit()
case "!"
> 'Generating new numbers list'
num = genRandomNumbers( 4 )
default
if not validInput( exp ): continue
answer = getAnswer( exp )
if answer == 24
> "By George you GOT IT! Your expression equals 24"
else
> "Ahh Sorry, So Sorry your answer of ", answer, " does not equal 24."
end
end
end

View file

@ -0,0 +1,92 @@
# Solution in '''RPN'''
Play24 := function()
local input, digits, line, c, chars, stack, stackptr, cur, p, q, ok, a, b, run;
input := InputTextUser();
run := true;
while run do
digits := List([1 .. 4], n -> Random(1, 9));
while true do
Display(digits);
line := ReadLine(input);
line := Chomp(line);
if line = "end" then
run := false;
break;
elif line = "next" then
break;
else
ok := true;
stack := [ ];
stackptr := 0;
chars := "123456789+-*/ ";
cur := ShallowCopy(digits);
for c in line do
if c = ' ' then
continue;
fi;
p := Position(chars, c);
if p = fail then
ok := false;
break;
fi;
if p < 10 then
q := Position(cur, p);
if q = fail then
ok := false;
break;
fi;
Unbind(cur[q]);
stackptr := stackptr + 1;
stack[stackptr] := p;
else
if stackptr < 2 then
ok := false;
break;
fi;
b := stack[stackptr];
a := stack[stackptr - 1];
stackptr := stackptr - 1;
if c = '+' then
a := a + b;
elif c = '-' then
a := a - b;
elif c = '*' then
a := a * b;
elif c = '/' then
if b = 0 then
ok := false;
break;
fi;
a := a / b;
else
ok := false;
break;
fi;
stack[stackptr] := a;
fi;
od;
if ok and stackptr = 1 and Size(cur) = 0 then
if stack[1] = 24 then
Print("Good !\n");
break;
else
Print("Bad value: ", stack[1], "\n");
continue;
fi;
fi;
Print("Invalid expression\n");
fi;
od;
od;
CloseStream(input);
end;
# example session
# type "end" to quit the game, "next" to try another list of digits
gap> Play24();
[ 7, 6, 8, 5 ]
86*75-/
Good !
[ 5, 9, 2, 7 ]
end
gap>

Some files were not shown because too many files have changed in this diff Show more