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,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();
}
}
}
}
}