153 lines
4.3 KiB
Zig
153 lines
4.3 KiB
Zig
const std = @import("std");
|
|
const rand = std.Random;
|
|
// (hint: errors cannot be handled at comptime)
|
|
var stdout: std.fs.File.Writer = undefined;
|
|
var stdin: std.fs.File.Reader = undefined;
|
|
|
|
fn opType(x: u8) i32 {
|
|
return switch (x) {
|
|
'-', '+' => 1,
|
|
'/', '*' => 2,
|
|
'(', ')' => -1,
|
|
else => 0,
|
|
};
|
|
}
|
|
|
|
fn toRpn(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
|
|
var rpnString = std.ArrayList(u8).init(allocator);
|
|
defer rpnString.deinit();
|
|
|
|
var rpnStack = std.ArrayList(u8).init(allocator);
|
|
defer rpnStack.deinit();
|
|
|
|
var lastToken: u8 = '#';
|
|
|
|
for (input) |token| {
|
|
if (token >= '1' and token <= '9') {
|
|
try rpnString.append(token);
|
|
} else if (opType(token) == 0) {
|
|
continue;
|
|
} else if (opType(token) > opType(lastToken) or token == '(') {
|
|
try rpnStack.append(token);
|
|
lastToken = token;
|
|
} else {
|
|
while (rpnStack.items.len > 0) {
|
|
const top = rpnStack.pop().?;
|
|
if (top == '(') {
|
|
break;
|
|
}
|
|
try rpnString.append(top);
|
|
}
|
|
if (token != ')') {
|
|
try rpnStack.append(token);
|
|
}
|
|
}
|
|
}
|
|
|
|
while (rpnStack.items.len > 0) {
|
|
try rpnString.append(rpnStack.pop().?);
|
|
}
|
|
|
|
if (rpnString.items.len > 0) {
|
|
try stdout.print("your formula results in {s}\n", .{rpnString.items});
|
|
} else {
|
|
stdout.print("no input available.\n", .{}) catch {};
|
|
}
|
|
|
|
return rpnString.toOwnedSlice();
|
|
}
|
|
|
|
fn calculate(input: []const u8, list: *[4]u32) f32 {
|
|
var stack = std.ArrayList(f32).init(std.heap.page_allocator);
|
|
defer stack.deinit();
|
|
|
|
var accumulator: f32 = 0.0;
|
|
|
|
for (input) |token| {
|
|
if (token >= '1' and token <= '9') {
|
|
const digit = @as(u32, token - '0');
|
|
|
|
// Find and mark the used digit
|
|
var found = false;
|
|
for (list, 0..) |val, idx| {
|
|
if (val == digit) {
|
|
list[idx] = 10;
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
stdout.print(" invalid digit: {d} \n", .{digit}) catch {};
|
|
}
|
|
|
|
stack.append(accumulator) catch {};
|
|
accumulator = @floatFromInt(digit);
|
|
} else {
|
|
const a = stack.pop().?;
|
|
|
|
accumulator = switch (token) {
|
|
'-' => a - accumulator,
|
|
'+' => a + accumulator,
|
|
'/' => a / accumulator,
|
|
'*' => a * accumulator,
|
|
else => accumulator, // NOP
|
|
};
|
|
}
|
|
}
|
|
|
|
stdout.print("your formula results in {d}\n", .{accumulator}) catch {};
|
|
return accumulator;
|
|
}
|
|
|
|
pub fn main() !void {
|
|
stdout = std.io.getStdOut().writer();
|
|
stdin = std.io.getStdIn().reader();
|
|
var prng = rand.DefaultPrng.init(@as(u64, @intCast(std.time.timestamp())));
|
|
const random = prng.random();
|
|
// only values from 1 --> 9 (inclusive)
|
|
var list = [_]u32{
|
|
@mod(random.int(u32), 9) + 1,
|
|
@mod(random.int(u32), 9) + 1,
|
|
@mod(random.int(u32), 9) + 1,
|
|
@mod(random.int(u32), 9) + 1,
|
|
};
|
|
|
|
try stdout.print("form 24 with using + - / * {d} {d} {d} {d}\n", .{ list[0], list[1], list[2], list[3] });
|
|
|
|
// Get user input
|
|
var buffer: [1024]u8 = undefined;
|
|
const input = try stdin.readUntilDelimiterOrEof(buffer[0..], '\n') orelse "";
|
|
|
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
|
defer arena.deinit();
|
|
const allocator = arena.allocator();
|
|
|
|
// Convert to RPN
|
|
const rpnInput = try toRpn(allocator, input);
|
|
if (rpnInput.len == 0) {
|
|
stdout.print("exit.\n", .{}) catch {};
|
|
return;
|
|
}
|
|
|
|
const result = calculate(rpnInput, &list);
|
|
|
|
var allUsed = true;
|
|
for (list) |val| {
|
|
if (val != 10) {
|
|
allUsed = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (allUsed) {
|
|
try stdout.print("and you used all numbers\n", .{});
|
|
if (result == 24.0) {
|
|
try stdout.print("you won\n", .{});
|
|
} else {
|
|
try stdout.print("but your formula doesn't result in 24\n", .{});
|
|
}
|
|
} else {
|
|
try stdout.print("you didn't use all the numbers\n", .{});
|
|
}
|
|
}
|