const std = @import("std"); const stdout = std.io.getStdOut().writer(); fn println(comptime str: []const u8, args: anytype) void { print(str ++ "\n", args); } fn print(comptime str: []const u8, args: anytype) void { stdout.print(str, args) catch {}; } fn parse(comptime str: []const u8) [10]u8 { var new = std.mem.zeroes([10]u8); for (0..10) |i| { new[i] = str[i] - 65; } return new; } var p1 = parse("VRDTOUAPZX"); var p2 = parse("JSXCKEAGDE"); var count: u64 = 0; const ArrayListU8 = std.ArrayList(u8); const Node = struct { value: u8, depth: u8, tree: *Tree, }; const Tree = struct { alloc: std.mem.Allocator, nodes: std.AutoHashMap(u8, *Node), const Self = @This(); fn init(alloc: std.mem.Allocator) !*Self { var new = try alloc.create(Tree); new.alloc = alloc; new.nodes = std.AutoHashMap(u8, *Node).init(alloc); return new; } fn add_word(self: *Self, word: []const u8) !void { var tree_ptr: *Self = self; var depth: u8 = 0; for (word) |cu| { const c = cu - 65; if (tree_ptr.*.nodes.get(c)) |node| { tree_ptr = node.tree; } else { var new_node = try self.alloc.create(Node); new_node.value = c; new_node.depth = depth; new_node.tree = try Self.init(self.alloc); try tree_ptr.*.nodes.put(c, new_node); tree_ptr = new_node.tree; } depth += 1; } } }; pub fn main() !void { var allocator = std.heap.GeneralPurposeAllocator(.{}){}; var alloc = allocator.allocator(); const args = try std.process.argsAlloc(alloc); if (args.len == 3) { if (args[1].len != 10 and args[2].len != 10) { println("Invalid args", .{}); return; } println("Using c1={s} c2={s}", .{ args[1], args[2] }); for (0..10) |i| { p1[i] = args[1][i] - 65; p2[i] = args[2][i] - 65; } } var words = @embedFile("./10letterwordslist.txt"); var root = try Tree.init(alloc); var split = std.mem.split(u8, words, "\r\n"); while (split.next()) |item| { if (item.len == 10) { try root.add_word(item); } } var sr = try search3(0, root, root); if (sr.items.len == 0) { println("No results found \n", .{}); return; } println("items: {}", .{sr.items.len}); var r = sr.items[0]; var r1 = [10]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; var r2 = [10]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; for (p1, p2, r, 0..) |p_1, p_2, k, i| { r1[i] = ((p_1 + (26 - k)) % 26) + 65; r2[i] = ((p_2 + (26 - k)) % 26) + 65; r[i] = k + 65; } println("k: {s}", .{r}); println("r1: {s}", .{r1}); println("r2: {s}", .{r2}); println("Checked: {}", .{count}); } fn search3(depth: u8, tree1: *Tree, tree2: *Tree) !std.ArrayList([]u8) { var list = std.ArrayList([]u8).init(tree1.alloc); for (0..26) |validChari| { var validChar: u8 = @intCast(validChari); count += 1; var inv = 26 - validChar; var v1 = (p1[depth] + inv) % 26; var v2 = (p2[depth] + inv) % 26; var new_tree1 = tree1.nodes.get(v1); var new_tree2 = tree2.nodes.get(v2); if (new_tree1 == null or new_tree2 == null) { continue; } var sr = try search2(depth + 1, new_tree1.?.tree, new_tree2.?.tree); if (sr == null) { continue; } var r = sr.?; r[depth] = validChar; try list.append(r); } return list; } fn search2(depth: u8, tree1: *Tree, tree2: *Tree) !?[]u8 { if (depth == 10) { return try tree1.alloc.alloc(u8, 10); } for (0..26) |validChari| { var validChar: u8 = @intCast(validChari); count += 1; var inv = 26 - validChar; var v1 = (p1[depth] + inv) % 26; var v2 = (p2[depth] + inv) % 26; var new_tree1 = tree1.nodes.get(v1); var new_tree2 = tree2.nodes.get(v2); if (new_tree1 == null or new_tree2 == null) { continue; } var sr = try search2(depth + 1, new_tree1.?.tree, new_tree2.?.tree); if (sr == null) { continue; } var r = sr.?; r[depth] = validChar; return r; } return null; }