Add tasks for all the new languages

This commit is contained in:
Tina Müller 2016-12-05 23:44:36 +01:00
parent 9dc3c2bb62
commit bba7bfd280
13208 changed files with 134745 additions and 0 deletions

View file

@ -0,0 +1,109 @@
\ Generate four random digits and display to the user
\ then get an expression from the user using +, -, / and * and the digits
\ the result must equal 24
\ http://8th-dev.com/24game.html
\ Only the words in namespace 'game' are available to the player:
ns: game
: + n:+ ;
: - n:- ;
: * n:* ;
: / n:/ ;
ns: G
var random-digits
var user-input
: one-digit \ a -- a
rand n:abs 9 n:mod n:1+ a:push ;
: gen-digits \ - a
[] clone nip \ the clone nip is not needed in versions past 1.0.2...
' one-digit 4 times
' n:cmp a:sort
random-digits ! ;
: prompt-user
cr "The digits are: " . random-digits @ . cr ;
: goodbye
cr "Thanks for playing!\n" . cr 0 die ;
: get-input
70 null con:accept dup user-input !
null? if drop goodbye then ;
: compare-digits
true swap
(
\ inputed-array index
dup >r
a:@
random-digits @ r> a:@ nip
n:= not if
break
swap drop false swap
then
) 0 3 loop drop ;
/^\D*(\d)\D+(\d)\D+(\d)\D+(\d)\D*$/ var, digits-regex
: all-digits?
user-input @ digits-regex @ r:match
null? if drop false else
5 = not if
false
else
\ convert the captured digits in the regex into a sorted array:
digits-regex @
( r:@ >n swap ) 1 4 loop drop
4 a:close ' n:cmp a:sort
compare-digits
then
then ;
: does-eval?
0 user-input @ eval 24 n:=
dup not if
cr "Sorry, that expression is wrong" . cr
then ;
: check-input
reset
all-digits? if
does-eval? if
cr "Excellent! Your expression: \"" .
user-input @ .
"\" worked!" . cr
then
else
cr "You did not use the digits properly, try again." . cr
then ;
: intro quote |
Welcome to the '24 game'!
You will be shown four digits each time. Using only the + - * and / operators
and all the digits (and only the digits), produce the number '24'
Enter your result in 8th syntax, e.g.: 4 4 + 2 1 + *
To quit the game, just hit enter by itself. Enjoy!
| . ;
: start
\ don't allow anything but the desired words
ns:game only
intro
repeat
gen-digits
prompt-user
get-input
check-input
again ;
start

View file

@ -0,0 +1,221 @@
import ceylon.random {
DefaultRandom
}
class Rational(shared Integer numerator, shared Integer denominator = 1) satisfies Numeric<Rational> {
assert(denominator != 0);
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``";
}
interface Expression {
shared formal Rational evaluate();
}
class NumberExpression(Rational number) satisfies Expression {
evaluate() => number;
string => number.string;
}
class OperatorExpression(Expression left, Character operator, Expression right) satisfies Expression {
shared actual Rational evaluate() {
switch(operator)
case('*') {
return left.evaluate() * right.evaluate();
}
case('/') {
return left.evaluate() / right.evaluate();
}
case('-') {
return left.evaluate() - right.evaluate();
}
case('+') {
return left.evaluate() + right.evaluate();
}
else {
throw Exception("unknown operator ``operator``");
}
}
string => "(``left.string`` ``operator.string`` ``right.string``)";
}
"A simplified top down operator precedence parser. There aren't any right
binding operators so we don't have to worry about that."
class PrattParser(String input) {
value tokens = input.replace(" ", "");
variable value index = -1;
shared Expression expression(Integer precedence = 0) {
value token = advance();
variable value left = parseUnary(token);
while(precedence < getPrecedence(peek())) {
value nextToken = advance();
left = parseBinary(left, nextToken);
}
return left;
}
Integer getPrecedence(Character op) =>
switch(op)
case('*' | '/') 2
case('+' | '-') 1
else 0;
Character advance(Character? expected = null) {
index++;
value token = tokens[index] else ' ';
if(exists expected, token != expected) {
throw Exception("unknown character ``token``");
}
return token;
}
Character peek() => tokens[index + 1] else ' ';
Expression parseBinary(Expression left, Character operator) =>
let(right = expression(getPrecedence(operator)))
OperatorExpression(left, operator, right);
Expression parseUnary(Character token) {
if(token.digit) {
assert(exists int = parseInteger(token.string));
return NumberExpression(Rational(int));
} else if(token == '(') {
value exp = expression();
advance(')');
return exp;
} else {
throw Exception("unknown character ``token``");
}
}
}
"Run the module `twentyfourgame`."
shared void run() {
value random = DefaultRandom();
function random4Numbers() =>
random.elements(1..9).take(4).sequence();
function isValidGuess(String input, {Integer*} allowedNumbers) {
value allowedOperators = set {*"()+-/*"};
value extractedNumbers = input
.split((Character ch) => ch in allowedOperators || ch.whitespace)
.map((String element) => parseInteger(element))
.coalesced;
if(extractedNumbers.any((Integer element) => element > 9)) {
print("number too big!");
return false;
}
if(extractedNumbers.any((Integer element) => element < 1)) {
print("number too small!");
return false;
}
if(extractedNumbers.sort(byIncreasing(Integer.magnitude)) != allowedNumbers.sort(byIncreasing(Integer.magnitude))) {
print("use all the numbers, please!");
return false;
}
if(!input.every((Character element) => element in allowedOperators || element.digit || element.whitespace)) {
print("only digits and mathematical operators, please");
return false;
}
variable value lefts = 0;
for(c in input) {
if(c == '(') {
lefts++;
} else if(c == ')') {
lefts--;
if(lefts < 0) {
break;
}
}
}
if(lefts != 0) {
print("unbalanced brackets!");
return false;
}
return true;
}
function evaluate(String input) =>
let(parser = PrattParser(input),
exp = parser.expression())
exp.evaluate();
print("Welcome to The 24 Game.
Create a mathematical equation with four random
numbers that evaluates to 24.
You must use all the numbers once and only once,
but in any order.
Also, only + - / * and parentheses are allowed.
For example: (1 + 2 + 3) * 4
Also: enter n for new numbers and q to quit.
-----------------------------------------------");
while(true) {
value chosenNumbers = random4Numbers();
void pleaseTryAgain() => print("Sorry, please try again. (Your numbers are ``chosenNumbers``)");
print("Your numbers are ``chosenNumbers``. Please turn them into 24.");
while(true) {
value line = process.readLine()?.trimmed;
if(exists line) {
if(line.uppercased == "Q") {
print("bye!");
return;
}
if(line.uppercased == "N") {
break;
}
if(isValidGuess(line, chosenNumbers)) {
try {
value result = evaluate(line);
print("= ``result``");
if(result.integer == 24) {
print("You did it!");
break;
} else {
pleaseTryAgain();
}
} catch(Exception e) {
print(e.message);
pleaseTryAgain();
}
} else {
pleaseTryAgain();
}
}
}
}
}

View file

@ -0,0 +1,31 @@
(string-delimiter "")
;; check that nums are in expr, and only once
(define (is-valid? expr sorted: nums)
(when (equal? 'q expr) (error "24-game" "Thx for playing"))
(unless (and
(list? expr)
(equal? nums (list-sort < (filter number? (flatten expr)))))
(writeln "🎃 Please use" nums)
#f))
;; 4 random digits
(define (gen24)
(->> (append (range 1 10)(range 1 10)) shuffle (take 4) (list-sort < )))
(define (is-24? num)
(unless (= 24 num)
(writeln "😧 Sorry - Result = " num)
#f))
(define (check-24 expr)
(if (and
(is-valid? expr nums)
(is-24? (js-eval (string expr)))) ;; use js evaluator
"🍀 🌸 Congrats - (play24) for another one."
(input-expr check-24 (string nums))))
(define nums null)
(define (play24)
(set! nums (gen24))
(writeln "24-game - Can you combine" nums "to get 24 ❓ (q to exit)")
(input-expr check-24 (string-append (string nums) " -> 24 ❓")))

View file

@ -0,0 +1,70 @@
[
if(sys_listunboundmethods !>> 'randoms') => {
define randoms()::array => {
local(out = array)
loop(4) => { #out->insert(math_random(9,1)) }
return #out
}
}
if(sys_listunboundmethods !>> 'checkvalid') => {
define checkvalid(str::string, nums::array)::boolean => {
local(chk = array('*','/','+','-','(',')',' '), chknums = array, lastintpos = -1, poscounter = 0)
loop(9) => { #chk->insert(loop_count) }
with s in #str->values do => {
#poscounter++
#chk !>> #s && #chk !>> integer(#s) ? return false
integer(#s) > 0 && #lastintpos + 1 >= #poscounter ? return false
integer(#s) > 0 ? #chknums->insert(integer(#s))
integer(#s) > 0 ? #lastintpos = #poscounter
}
#chknums->size != 4 ? return false
#nums->sort
#chknums->sort
loop(4) => { #nums->get(loop_count) != #chknums(loop_count) ? return false }
return true
}
}
if(sys_listunboundmethods !>> 'executeexpr') => {
define executeexpr(expr::string)::integer => {
local(keep = string)
with i in #expr->values do => {
if(array('*','/','+','-','(',')') >> #i) => {
#keep->append(#i)
else
integer(#i) > 0 ? #keep->append(decimal(#i))
}
}
return integer(sourcefile('['+#keep+']','24game',true,true)->invoke)
}
}
local(numbers = array, exprsafe = true, exprcorrect = false, exprresult = 0)
if(web_request->param('nums')->asString->size) => {
with n in web_request->param('nums')->asString->split(',') do => { #numbers->insert(integer(#n->trim&)) }
}
#numbers->size != 4 ? #numbers = randoms()
if(web_request->param('nums')->asString->size) => {
#exprsafe = checkvalid(web_request->param('expr')->asString,#numbers)
if(#exprsafe) => {
#exprresult = executeexpr(web_request->param('expr')->asString)
#exprresult == 24 ? #exprcorrect = true
}
}
]<h1>24 Game</h1>
<p><b>Rules:</b><br>
Enter an expression that evaluates to 24</p>
<ul>
<li>Only multiplication, division, addition, and subtraction operators/functions are allowed.</li>
<li>Brackets are allowed.</li>
<li>Forming multiple digit numbers from the supplied digits is disallowed. (So an answer of 12+12 when given 1, 2, 2, and 1 is wrong).</li>
<li>The order of the digits when given does not have to be preserved.</li>
</ul>
<h2>Numbers</h2>
<p>[#numbers->join(', ')] (<a href="?">Reload</a>)</p>
[!#exprsafe ? '<p>Please provide a valid expression</p>']
<form><input type="hidden" value="[#numbers->join(',')]" name="nums"><input type="text" name="expr" value="[web_request->param('expr')->asString]"><input type="submit" name="submit" value="submit"></form>
[if(#exprsafe)]
<p>Result: <b>[#exprresult]</b> [#exprcorrect ? 'is CORRECT!' | 'is incorrect']</p>
[/if]

View file

@ -0,0 +1,5 @@
on mouseUp
put empty into fld "EvalField"
put empty into fld "AnswerField"
put random(9) & comma & random(9) & comma & random(9) & comma & random(9) into fld "YourNumbersField"
end mouseUp

View file

@ -0,0 +1,30 @@
on keyDown k
local ops, nums, allowedKeys, numsCopy, expr
put "+,-,/,*,(,)" into ops
put the text of fld "YourNumbersField" into nums
put the text of fld "EvalField" into expr
if matchText(expr & k,"\d\d") then
answer "You can't enter 2 digits together"
exit keyDown
end if
repeat with n = 1 to the number of chars of expr
if offset(char n of expr, nums) > 0 then
delete char offset(char n of expr, nums) of nums
end if
end repeat
put ops & comma & nums into allowedKeys
if k is among the items of allowedKeys then
put k after expr
delete char offset(k, nums) of nums
replace comma with empty in nums
try
put the value of merge("[[expr]]") into fld "AnswerField"
if the value of fld "AnswerField" is 24 and nums is empty then
answer "You win!"
end if
end try
pass keyDown
else
exit keyDown
end if
end keyDown

View file

@ -0,0 +1,40 @@
import math, strutils, algorithm, sequtils
randomize()
template newSeqWith(len: int, init: expr): expr =
var result {.gensym.} = newSeq[type(init)](len)
for i in 0 .. <len:
result[i] = init
result
var
problem = newSeqWith(4, random(1..9))
stack = newSeq[float]()
digits = newSeq[int]()
echo "Make 24 with the digits: ", problem
template op(c): stmt =
let a = stack.pop
stack.add c(stack.pop, a)
for c in stdin.readLine:
case c
of '1'..'9':
digits.add c.ord - '0'.ord
stack.add float(c.ord - '0'.ord)
of '+': op `+`
of '*': op `*`
of '-': op `-`
of '/': op `/`
of Whitespace: discard
else: raise ValueError.newException "Wrong char: " & c
sort digits, cmp[int]
sort problem, cmp[int]
if digits.deduplicate != problem.deduplicate:
raise ValueError.newException "Not using the given digits."
if stack.len != 1:
raise ValueError.newException "Wrong expression."
echo "Result: ", stack[0]
echo if abs(stack[0] - 24) < 0.001: "Good job!" else: "Try again."

View file

@ -0,0 +1,19 @@
: 24game
| l expr w n i |
ListBuffer init(4, #[ 9 rand ]) ->l
System.Out "Digits : " << l << " --> RPN Expression for 24 : " << drop
System.Console askln ->expr
expr words forEach: w [
w "+" == ifTrue: [ + continue ]
w "-" == ifTrue: [ - continue ]
w "*" == ifTrue: [ * continue ]
w "/" == ifTrue: [ asFloat / continue ]
w asInteger dup ->n ifNull: [ System.Out "Word " << w << " not allowed " << cr break ]
l indexOf(n) dup ->i ifNull: [ System.Out "Integer " << n << " is wrong " << cr break ]
n l put(i, null)
]
l conform(#isNull) ifFalse: [ "Sorry, all numbers must be used..." println return ]
24 == ifTrue: [ "You won !" ] else: [ "You loose..." ] println ;

View file

@ -0,0 +1,177 @@
-- Note this uses simple/strict left association, so for example:
-- 1+2*1*8 is ((1+2)*1)*8 not 1+((2*1)*8) [or 1+(2*(1*8))], and
-- 7-(2*2)*8 is (7-(2*2))*8 not 7-((2*2)*8)
-- Does not allow unary minus on the first digit.
-- Uses solve24() from the next task, when it can.
-- (you may want to comment out the last 2 lines/uncomment the if 0, in that file)
--
--include 24_game_solve.exw
--with trace
forward function eval(string equation, sequence unused, integer idx=1)
-- (the above definition is entirely optional, but good coding style)
constant errorcodes = {"digit expected", -- 1
"')' expected", -- 2
"digit already used", -- 3
"digit not offered", -- 4
"operand expected"} -- 5
function card(integer idx) -- (for error handling)
if idx=1 then return "1st" end if
if idx=2 then return "2nd" end if
-- (assumes expression is less than 21 characters)
return sprintf("%dth",idx)
end function
function errorchar(sequence equation, integer idx)
if idx>length(equation) then return "" end if
return sprintf("(%s)",equation[idx])
end function
sequence rset = repeat(0,4)
procedure new_rset()
for i=1 to length(rset) do
rset[i] = rand(9)
end for
end procedure
function get_operand(string equation, integer idx, sequence unused)
integer ch, k,
error = 1 -- "digit expected"
atom res
if idx<=length(equation) then
ch = equation[idx]
if ch='(' then
{error,res,unused,idx} = eval(equation,unused,idx+1)
if error=0
and idx<=length(equation) then
ch = equation[idx]
if ch=')' then
return {0,res,unused,idx+1}
end if
end if
if error=0 then
error = 2 -- "')' expected"
end if
elsif ch>='0' and ch<='9' then
res = ch-'0'
k = find(res,unused)
if k!=0 then
unused[k..k] = {}
return {0,res,unused,idx+1}
end if
if find(res,rset) then
error = 3 -- "digit already used"
else
error = 4 -- "digit not offered"
end if
end if
end if
return {error,0,unused,idx}
end function
function get_operator(string equation, integer idx)
integer ch, error = 5 -- "operand expected"
if idx<=length(equation) then
ch = equation[idx]
if find(ch,"+-/*") then
return {0,ch,idx+1}
end if
end if
return {error,0,idx}
end function
function eval(string equation, sequence unused, integer idx=1)
atom lhs, rhs
integer ch, error
{error,lhs,unused,idx} = get_operand(equation,idx,unused)
if error=0 then
while 1 do
{error,ch,idx} = get_operator(equation,idx)
if error!=0 then exit end if
{error,rhs,unused,idx} = get_operand(equation,idx,unused)
if error!=0 then exit end if
if ch='+' then lhs += rhs
elsif ch='-' then lhs -= rhs
elsif ch='/' then lhs /= rhs
elsif ch='*' then lhs *= rhs
else ?9/0 -- (should not happen)
end if
if idx>length(equation) then
return {0,lhs,unused,idx}
end if
ch = equation[idx]
if ch=')' then
return {0,lhs,unused,idx}
end if
end while
end if
return {error,0,unused,idx}
end function
function strip(string equation)
for i=length(equation) to 1 by -1 do
if find(equation[i]," \t\r\n") then
equation[i..i] = ""
end if
end for
return equation
end function
function strip0(atom a) -- (for error handling)
string res = sprintf("%f",a)
integer ch
for i=length(res) to 2 by -1 do
ch = res[i]
if ch='.' then return res[1..i-1] end if
if ch!='0' then return res[1..i] end if
end for
return res
end function
procedure play()
sequence unused
string equation
integer error,idx
atom res
new_rset()
printf(1,"Enter an expression which evaluates to exactly 24\n"&
"Use all of, and only, the digits %d, %d, %d, and %d\n"&
"You may only use the operators + - * /\n"&
"Parentheses and spaces are allowed\n",rset)
while 1 do
equation = strip(gets(0))
if upper(equation)="Q" then exit end if
if equation="?" then
puts(1,"\n")
integer r_solve24 = routine_id("solve24") -- see below
if r_solve24=-1 then -- (someone copied just this code out?)
puts(1,"no solve24 routine\n")
else
call_proc(r_solve24,{rset})
end if
else
{error,res,unused,idx} = eval(equation, rset)
if error!=0 then
printf(1," %s on the %s character%s\n",{errorcodes[error],card(idx),errorchar(equation,idx)})
elsif idx<=length(equation) then
printf(1,"\neval() returned only having processed %d of %d characters\n",{idx,length(equation)})
elsif length(unused) then
printf(1," not all the digits were used\n",error)
elsif res!=24 then
printf(1,"\nresult is %s, not 24\n",{strip0(res)})
else
puts(1," correct! Press any key to quit\n")
if getc(0) then end if
exit
end if
end if
puts(1,"enter Q to give up and quit\n")
end while
end procedure
play()

View file

@ -0,0 +1,40 @@
is_num = (s):
x = s ord(0)
if (x >= "0"ord && x <= "9"ord): true.
else: false.
.
nums = (s):
res = ()
0 to (s length, (b):
c = s(b)
if (is_num(c)):
res push(c).
.)
res.
try = 1
while (true):
r = rand string
digits = (r(0),r(1),r(2),r(3))
"\nMy next four digits: " print
digits join(" ") say
digit_s = digits ins_sort string
("Your expression to create 24 (try ", try, "): ") print
entry = read slice(0,-1)
expr = entry eval
parse = nums(entry)
parse_s = parse clone ins_sort string
try++
if (parse length != 4):
("Wrong number of digits:", parse) say.
elsif (parse_s != digit_s):
("Wrong digits:", parse) say.
elsif (expr == 24):
"You won!" say
entry print, " => 24" say
return().
else:
(entry, " => ", expr string, " != 24") join("") say.
.

View file

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

View file

@ -0,0 +1,74 @@
import Darwin
import Foundation
println("24 Game")
println("Generating 4 digits...")
func randomDigits() -> Int[] {
var result = Int[]();
for var i = 0; i < 4; i++ {
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 = Int[]()
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(digit.toInt()!)
case "+", "-", "*", "/":
enteredOperations.append(character)
case "\n":
println()
default:
println("Invalid expression")
}
}
// check value of expression provided by the operator
var value = Int()
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!")
}
}
}
if value != 24 {
println("The value of the provided expression is \(value) instead of 24!")
} else {
println("Congratulations, you found a solution!")
}