Add tasks for all the new languages
This commit is contained in:
parent
9dc3c2bb62
commit
bba7bfd280
13208 changed files with 134745 additions and 0 deletions
221
Task/24-game/Ceylon/24-game.ceylon
Normal file
221
Task/24-game/Ceylon/24-game.ceylon
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue