Day 10
This commit is contained in:
		
							parent
							
								
									eaa958fbbf
								
							
						
					
					
						commit
						5b8558cac3
					
				|  | @ -0,0 +1,27 @@ | |||
| const std = @import("std"); | ||||
| 
 | ||||
| pub fn build(b: *std.build.Builder) void { | ||||
|     // Standard target options allows the person running `zig build` to choose | ||||
|     // what target to build for. Here we do not override the defaults, which | ||||
|     // means any target is allowed, and the default is native. Other options | ||||
|     // for restricting supported target set are available. | ||||
|     const target = b.standardTargetOptions(.{}); | ||||
| 
 | ||||
|     // Standard release options allow the person running `zig build` to select | ||||
|     // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. | ||||
|     const mode = b.standardReleaseOptions(); | ||||
| 
 | ||||
|     const exe = b.addExecutable("day10", "src/main.zig"); | ||||
|     exe.setTarget(target); | ||||
|     exe.setBuildMode(mode); | ||||
|     exe.install(); | ||||
| 
 | ||||
|     const run_cmd = exe.run(); | ||||
|     run_cmd.step.dependOn(b.getInstallStep()); | ||||
|     if (b.args) |args| { | ||||
|         run_cmd.addArgs(args); | ||||
|     } | ||||
| 
 | ||||
|     const run_step = b.step("run", "Run the app"); | ||||
|     run_step.dependOn(&run_cmd.step); | ||||
| } | ||||
|  | @ -0,0 +1,94 @@ | |||
| {{<{{{{([{[([[()<>]{<>{}}]<([]())(()<>)>)((({}())[()[]])<<[][]>[{}[]]>)]{{(<{}<>>{<><>}]([<>[]]< | ||||
| [(<{{[{(<({{<<[]()><<>{}>>([<>[]]{<><>})}})>)}]}}>[{(<{({[{[[({}())((){})]({{}[]})]<<[<>{}]([][])>({<>()} | ||||
| (({<{[{({(([[([]())({}())]]({[[]{}]([][]))<((){})<{}<>>>))[(([<>[]]<[]>)(([]{}){{}{}}))])})[({<[{ | ||||
| ([{{[([<({<<<([]())[()[]]>{<()[]>[[]()]}>[{<[]{}><[]>>{<<>()>{[]()}}]>[[[[[]{}]([]<>)]<{<>{}} | ||||
| [[((<({<(<{<<{{}()}{[][]}>[((){})]>}>{((<({}<>)<{}()>>[[<>()]])<<<[][]><<>[]>>{<{}[]>(<>())}>)<{[[{ | ||||
| [{<{{{{<([{[(<[]<>>(<>[])){({}<>)([]<>)}]{{([][])[<>{}]}{<[]<>>(<>{})}}}])<<{[<[<>{}]<(){}>>{<{}<>><<> | ||||
| (({({([(<[[([[{}{}]([]<>}][(<>()){(){}}])]](({{{{}<>}<{}[]>}([{}[]][(){}])}[(<[]{}>({}()))<<<><>>>])<[{ | ||||
| [{<((<{(<{<<{[()()](()<>)}<({}[])([]<>)>>{(<<><>>[[]{}])[[[]()](<>[])]}>{[[({}<>)([]<>)][[{}[] | ||||
| {<{<{{(<[[{[[({}[])[()[]]]([()<>][{}[]])]<<({}())[{}{}]><[<>[]](<><>)>>}(([([]{})((){})]((<>)([]{}))))]<{<<< | ||||
| <{(<<(<[<{<[{[<>[]][{}{}]}{{()<>}{<><>}>]>[<(([]{})[[]])>]}<[<([{}{}][<><>]){([]{})}>]({<{<>()}>{ | ||||
| {[[<{{{<<<[<((()<>)({}{}))<{{}()}>>]<((([]{}){{}<>})[{{}<>}([]{})])({{()[]}[[]()]}[{{}()}({ | ||||
| <[[[{{([{[({[<{}[]>[{}()]]{<()>}}({<()()>}<<<>()>{[]}>))]((({({}[])>{[(){}]{<><>}})(({()[]}[()<>] | ||||
| [([([([<[{{<[[{}[]]{<>{}}][<{}>(()[])]>[({<>()}(()[])){<[][]>{()[]}}]}}<{(({()}([]()))(([]())<()[]>))<((<>{} | ||||
| <{[{(({([([[{((){})[[]]>{{{}[]}[<>()]}]])]{([([<[]{}>((){})]<[()<>]<()()>>)][<<{<>{}}{<><> | ||||
| [[{{(([{(({[[{{}[]}]][<<<>()>({}{})>[[{}<>]{{}<>}]]}[(({{}}{[][]}){[{}{}][<>[]]})(<<<>{}><<><>>>)])<[ | ||||
| [[{([<<([[<(<{<>()}<[][]>>{[<>[]]{()[]}}){[<[][]><{}()>][([]())<<><>>]}>]((<<[(){}][(){}]><([])>>)) | ||||
| [{[<{(([(([([(<>[]}(<>{})][<{}[]>[()[]]])<{[{}<>]<[]<>>}{{[]<>}{{}{}}}>]<<{[<>{}](<>())}{{()[]}{<>{}}}>[ | ||||
| {({<[(((<{<<[[()<>]]<({}<>)>>>[<({[]<>}{()<>})[[()<>][<><>]]>({[{}[]]({}<>)}[<(){}>(<>())])]}><[{<[[<> | ||||
| <(((({{(<({[<<[]<>>>([()()]{<>()})][<[{}{}]{<>()}>{{{}{}}[[][]]}]}{(<<<><>>(()<>)>(<<>()>[()[]])) | ||||
| [<{{[{[[[<(({<()()>[(){}]}[([]())[(){}]]))>{[<[[[]]<[][]>]{[[][]](()())}>[(<<>()>{[]<>})(({}())<{}[]>) | ||||
| (<[[((<<({[(([()[]]([]<>)){{(){}}})]{<(<<><>><[]{}>)<<{}<>]([]<>)>>}}){(<{<{[]{}}[{}<>]>}>{({(<><>)<()[]>}{(( | ||||
| {[{((<{<<<<([<[]{}>[[][]]]<[[]()][<>[]]>)[[<{}[]>{{}()}](<()<>>[<>[]])]>>[{([<()[]>{{}[]}](({}{} | ||||
| (<([<((<{[<<(((){})<<><>>)<[{}()]<[]<>>}>[([[]{}](()[]))]>[<{({}()){{}()}}>[(([]<>)({}[])){ | ||||
| {((((<(({[(<{<()]([][])}>){[<[[][]]>]<{{{}<>}[[][]]}>}]}[<{([{[]{}}]{[(){}]<<>()>})[(<()<>>{()<> | ||||
| <<{([{<[[[<{([[]<>]){[<>()][(){}]}}[{(()[])[()[]]}]>][{{[{{}[]}<()<>>]>[[{(){}}[<>[]]][[<>[]]({}() | ||||
| <((<[<(([<[{({<><>}(()[]))}]<[<[{}()]<()[]>>(<()()>)][[(<>())<()())]<{<>}<{}>>]>>({{<<<>[]><<>( | ||||
| [({{{{{{(([[<<()()><<>[]>>[{[]<>}]]{(<{}<>>(()[]))<<[][]>(()())>}]([<({}()><[][]>>]<{[[][]]<[]<>>}( | ||||
| (<(<{{<[{{{[<[<>[]]<[]{}>>[{<>{}}{()()}]]{<<{}()>(<>())>[[{}[]]]}}}}][{([{[([]{})<()[]>][[<>{}]{()[]}]}(([() | ||||
| {[<<(<<<{[<<<<[]<>><()[]>>[({}[])[[]<>]]><((<><>)[{}<>])[{{}{}}[[]()]]>>{{{[<><>]<<>()>}[<[]{}>([][])] | ||||
| <(<{<(<({[[{((()[])[{}<>])([<>()]>}{[({}{})[(){}]]<[()<>]({}[])>}]{[<{[]{}}><{[]{}}[[][]]>][[<{}<>><()[]>]<[ | ||||
| {<({[<((<<<{{([]<>}{<><>}}<{<>{}}[[]<>]>}>{<[{{}}(()())]>}>(<<{[(){}]<()[]>}({(){}}[()<>])>[<<<>[]>{[] | ||||
| {(({<{{{{{((<{[]<>>(<>{})>[[<>()]])<<(()())[<>]><[(){}][{}{}]>>)}({([[[]]]{<{}{}><()[]>})<{[(){}][[]()]}> | ||||
| <<[<<[((({[[(<{}[]>({}())){[()()]}][{{<>{}}<<>()>}[<{}[]>[<>[]]]]]{<(([]())([]()))>{([()()]<<>[]>)[< | ||||
| {([<<<({((<{{[<>[]][<>{}]}<<<>[]>[[][]]>}[{[()[]]<<>[]>}<[{}{}]<<><>>>]>({[<[]<>>]<<()()>([][])>}(((< | ||||
| (<{<((<{[[<[(<[]{}>{<>{}})][<([][])[{}<>]>[<{}<>>]]><<[(<>[])[{}<>]]{<{}{}><{}[]>}>(<([]<>){()[]}>)>]]}{({[<( | ||||
| [{{(({<<<<{{<({}()){{}{}}>[(()[])]}[([(){}]{<>[]})[(<>())[{}]]]}>[<<<{[]{}}{{}{}}>]{<[{}<>]>{(()())}}>[{(<[]< | ||||
| {[<<{<[[({{<<{()[]}<<><>>>([[]<>>[{}[]])>}[[[([]<>)[<>{}]]]<<[<>()](<>{})>>]})(((({({}[])<<><>>}([<>])))((< | ||||
| [{(({({<({(<{{[][]}({}<>)}[{()()}{[][]}]>(((<><>)(<>()))([{}()][{}()])))([{[[]()]<[]{}>}{( | ||||
| {<{{<[<<[(<([({}())[{}()]]{{{}<>}<[]>}){[((){})<[][]>]<([]())({}[])>}>{<(((){})[()<>])(<()[]>[(){}] | ||||
| {({({<{{(<([<[<><>]((){})>{{()[]}<<>{}>}]{[(<>())<{}[]>][{()<>}[[]()]>})>[[<{([])[()[]]}><<[(){}]({}())>>]{ | ||||
| (<{{(<<<{(<(({<><>}{()[]})<[{}[]]([]())>)([(()<>)[[]<>]]({[]()}{{}{}}))))[(<{{()[]}<()[]>}((<><>))>[[ | ||||
| <<[<([{<<[[({<[]<>><<>()>}{([]<>)[[]<>]}){[<{}{}><()[]>]<{<>()}{<>()}>}]{{<({}{})>})]>[<({< | ||||
| (<<[[({[({(<{{[]{}}<[]{}}}>[<<()<>><{}<>>>(<()()>{{}<>})])}{<({({}[])<()>}<([]())<{}<>>>)<<[( | ||||
| [<(<{(([(<([[<<>{}>(<>{})]](((()[])[[]()])[[{}<>]({}{})]))><<{<([]<>){[][]}>[{<>[]}<()<>>]}>(<((<>[]){()<>} | ||||
| [<{[[{(([[{[{<[]<>>(<>[])}<<<>()>{{}{}}>][({[][]}<<>>){(<>[])[<><>]}]}(([([][])(<>[])]{(()())}))](<<{ | ||||
| ((<{<<([<[(([{()()}((){})][<()[]><()[]>])<{({}<>){{}<>}}>)[{(<<><>>)<{{}[]}>}({(<>()){()}}{([ | ||||
| [({{{{((([({{(<>[])[[]<>]}([{}])}(({<><>}{<>()})[[{}[]]]))<{[[<>{}](()[])](<()<>>{[]()})}{{<()() | ||||
| [<[<({[[({[[[<<>[]>]({[]}[<><>])]{[[()<>]([]())]<({}{})[[][]]>}]}<<(([()()]<()<>>)<{()()}[()[]]> | ||||
| {<([[<[<<(([<(()[])(()<>)>{[<><>](<>[])]]{({{}})}){<((<><>)<{}<>>)((()[])[[]()])>})<<(<(())( | ||||
| <[<((<{(<[[({{{}()}({}{})}}<[[()<>]]<[()()][<>]>>]<[([()()]({}<>))[<{}()>([]<>)]]>][{[[(()())[()]][[<>[] | ||||
| [{(<(<[((<{(({(){}}[()[]])<{[][]}(<>{})>)[(<<><>>[()[]]]{[{}[]]{()<>}}]}><[<[[{}()](()[])][(<>()){<>()}]>[{ | ||||
| ([({<({{{[[<[{{}<>}([][])]{[(){}]{()<>}}>][{[{[]<>}][<{}()>]}]]}{((<[{{}[]}(()()))[{<>[]}]>({(<>{})<[]<>>} | ||||
| {[({[<[([(<{((<>{})<{}{}>)}(<[[]()]<{}{}>>({{}[]}{[]<>}))><[((()[])(())){([]<>)[()[]]}]<({() | ||||
| [(<<<([{[[[<<<<>>{{}<>}>[{[]()}]>[([[]{}]{[]<>}){[<>()]}]]]]}]<<((<([{[][]}<{}<>>]<[[]{}][[]<>])){{[<>[] | ||||
| {[{{[[{{[<[<<{{}<>}<[]{}>><<()[]>[<>[]]>>[([<>{}](()()))]]>{({([{}[]](<><>))<<(){}>(<>{})>}({([]<>)[{}[])}(<< | ||||
| <{([[{<[<{{([(<>{})[<>()]]){{[()[]]([])}}}[{<((){})([]())>}(<{[][]}<<>{}>>[[[][]]<()()>])]}>[ | ||||
| {(<[({{(<<<{[(()())]<[<>[]][{}{}]>}[[<()[]>{[][]}]]>(<((<>())[()[]]){{()[]}{[][]}}>({{[]<>}<[][]>}(<[]{} | ||||
| <{{[{((((<[{({[]{}}<(){}>)}[[{[][]}<<>{}>]<<[][]>{[]}>]]>{{([((){})<<>{}>]{{()()}})<[<<>()>](<<>>[() | ||||
| <([({(<<<{[<{(()<>)(<>[])}([<>]{<>{}})>]<(<<<><>><{}()>>[([][]){[]<>}])>}{[([[[]<>]{(){}}]<[{}<>]{{}<>} | ||||
| {<<<[{[(<[([([[]()]<()[]>)(([]())({}[]))]<[[()<>]]<[(){}]<[][]>>>)(<{<[][]>)<(()<>)<{}[]>> | ||||
| {[[<[[<(<[[{(<()<>>)<{{}<>}[[][]]>}<<(()()){[]{}}>{<[]()>>>]]>)({<<<<[{}{}]{<>()}>{<<><>>([]{})}>>[([<()()>( | ||||
| [[[{({{({[{[(({}())(<>[]))<<<>[]>[[]<>]>]<<<()()><<>>>[({}())(<>[])]>}[({<(){}>({}{})}[[{}()]]){[[[]<> | ||||
| <(((<<[{[[<({({}<>)[{}()]}[{[]{}}([]())]){([[]<>]<[]<>>)[(()[])[{}[]]]}>(<<<{}[]><()[]>)>[[<{}( | ||||
| [<<{[{{<<[[{<<()[]>(())><<{}()][<>()]>}({[{}{}][<>()]}<([]())([])>)]({{{[][]}[<>{}]}<[()]{{}()}>}(({ | ||||
| {([(<[[<(<<<(<<><>><{}<>>)({{}()}[<>()])>{([(){}][[][]]){[<><>]{<><>}}}>>(({(<<><>><()<>>){{()<>}{(){}}}} | ||||
| [(<([[[([(({[[<>[]]]}))([{{[{}()]([]<>)}{{<>[]}[[][]]}}(<([]())>[([]{}){()<>}])][<{<()[]><()()>}>{<([ | ||||
| {([[<<[[<[[[<[{}[]]{[]<>}>[<{}()>{<>[]}]]]<[<{[][]}(<>[])>[[{}[]]<[][]>]][((()[])[<>{}]){{{}()}[(){}]}]>]> | ||||
| {[[[<<{{[<<<([{}[]]<<>[]>)([()]<{}{}>)>({<<>{}>(()[])})>[(((<><>>{<>{}})<<<>[]>[[]()]>)({(()( | ||||
| [[[{<<(({{[((<{}<>>[{}])({<>{}}<{}{}>))[(<{}()>(<>{}))(<<><>>{{}{}})]]({{<()>}}(<{(){}](<><>) | ||||
| (({{[[[<[{<{[<{}()><<>{}>]}({[[]()]<{}[]>])>}[<{{(<><>)<{}()>}{{{}<>}{{}[]}}}(([<>[]]([][])) | ||||
| <[<<{({[(<(<{({}<>)<[][]>}{(()[])({}[])}>{(<{}{}>>})>([<<<<>{}>((){})>[(()())[[]()]]><{[{}<>]<<> | ||||
| [{<{[(<[[[{({({}<>)(()<>)}{<[][]>})}{[<[()[]]{[]<>]>{<{}()>(()())}]{[<()()>{<>[]}]<[<><>]>}}] | ||||
| ({{<{[[[([({{<<>()>(()<>)}(<{}()><()[]>)}<[[{}()]<{}[]>]{((){}){{}[]}}>)[([{<><>}<()<>>][(<><>)(()())] | ||||
| (({<{{{[([{<<<{}{}>{[]{}}>([<>[]]{[]{}})>}{<<{[]{}}[[]{}]>{<<>{}>([]())}><(<(){}>({}[]))[(<>[])(()<>)]> | ||||
| <[<(<{[[<([({[<>()][<>{}]}{{()()}[<><>]})]<[[<[]()>]<[{}<>]([])>]{<[<>[]]<<>()>]((<>())[<>{}])}>)([{<[[][]] | ||||
| <<{{((({<<[[<{<>()}(()())>[(()[])[()<>]]]{({{}[]}[<><>])}]<{<<<><>>{{}[]}>}<[<[][]>[{}[]]](<()()>{[]{}}) | ||||
| [<<{<{([{(({[{()[]}{()}][({}{})(()[])]}{({<>()})({[]()}({}[]))}))}][[[([[{<>[]}[{}[]]][[<><>]<()[]>]]([ | ||||
| [([[{{<(<[{(<<()<>>><[[]()]{()()}>)<(({}()){[]<>})>}]>)>{<[<{{((()())({}<>)>{([]{}){{}<>}}}}<({ | ||||
| ((<<{(<[(<[[<({})>[{[][]}[<>[]]]]]>)]>)}([(<[[([(([][]))[{{}()}([][])]][((<><>){[]()})])]]<<( | ||||
| <<<<(<{[{[({<{(){}}[<>]>[<[]<>>{<>()}]}[<[<>()]>{[[]<>][{}[]}}])(<{<(){}>[{}{}]}<(()<>)<()[]>>>)][<{{<[]< | ||||
| (([[<{[({{{[<<<><>>(()())>({[]<>}(<>()))]{<[<>()][{}{}]>([[]()]((){}))}}((<({}{})[<>]>([<>()]{(){}})))}[<{([< | ||||
| {[([<<[([[<[(<[]()>{()[]})<{<>()}{(){}}>]><<{<[][]><{}()>}(<[]<>>([]<>])>>]{[[<<{}<>>({}[] | ||||
| {{[<<(<({[<<{<[]<>>}{(<>())}>[{[<>]{(){}}}]>]}{{{<([()<>]{<>{}})(<()[]>[[]()])><[<<>[]>({}{})]((()())[{ | ||||
| [{{[<{<<{{<[<<()()>[{}]>([{}{}]({}{}))]{(<[][]>([][]))(([]{})<<>[]>)}>}({{<{<>[]}[<>()]>(({ | ||||
| [<{[(<<[<<(([[<>[]]][([]())({}<>}])){(({[]()}{()<>})[<[]{}>(<><>)])[<[{}[]][{}{}]><{(){}}<{}{}>>]}>({<<[[]() | ||||
| [({[<<<({<({({{}<>}[[]{}])}({({}<>)<<>[]>}))([<{(){}}>])>}{<{[[{{}{}}(<>{})]]<[[()[]]<<><>>]{[<><>]<{}()> | ||||
| [<{<<<<(([([[{{}()}[<>]][((){})[[]{}]]](({[]()}[[]()])[{[]()}(<>[])])){[{<<><>>{{}<>}}<{()[]}[[] | ||||
| [{({<(((<({{({[]()}))[((()())<[][]>)<{<>{}}(<><>)>]}{[<[[][]](<><>)>][[{<>{}}[<>{}]](<<>[]>{[][]})]})>)))>} | ||||
| [[{[[{({[([(<<<>[]>[<><>]>([{}()][<>()]))<<[<>{}]{{}<>}>[<<>{}>([]{}]]>])<(<(<[]()>)[(()[]) | ||||
| <([(<<[<<({{{([]{})}[{()<>}<[]()>]}}{(<{[]{}}([][])>)})[[[<[[][]]<<><>>><{{}{}}(<><>)>]<<(()())[(){}]>{ | ||||
| [(<{[{({[({<{<{}[]><<>()>}{<{}()>[[][]]}><<{{}()}{(){}}>>}[<{{<>{}}{()())}>]){[<[{()()}<[]()>]><[[{ | ||||
| <{<[{([([<<[<[<>()]{(){}}>][({{}[]}((){}))[<[][]><()<>>]]>>{{{<{<><>}{(){}}>({<><>}<()))}({<()><{}[]>}(<( | ||||
| ({((([[{([<[(([]{})){[()<>][<><>]}]>{[<<{}{}><()[]>>(<<>>)]({<<><>>[<>{}]}{<[]{}><<>{}>})}])[(<(([<><>][{}{ | ||||
| <[<(([(({([[<(()[])[[]{}]>{<<>{}>(<>{})}]]([([<>{}]{[]{}})][{<()>{()[]}}(({}[])(<>[]))]))})({{[(({(){}}[<> | ||||
|  | @ -0,0 +1,424 @@ | |||
| const std = @import("std"); | ||||
| 
 | ||||
| pub fn main() anyerror!void { | ||||
|     var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | ||||
|     defer arena.deinit(); | ||||
|     const alloc = &arena.allocator; | ||||
| 
 | ||||
|     // Read our input | ||||
|     var f = try std.fs.cwd().openFile("input", .{}); | ||||
|     defer f.close(); | ||||
|     var contents = try f.readToEndAlloc(alloc, std.math.maxInt(u32)); | ||||
|     defer alloc.free(contents); | ||||
| 
 | ||||
|     var lit = std.mem.tokenize(contents, "\n"); | ||||
|     var corrupt_score: u32 = 0; | ||||
|     var completion_scores = std.ArrayList(u64).init(alloc); | ||||
|     defer completion_scores.deinit(); | ||||
|     var line_id: usize = 0; | ||||
|     while (lit.next()) |line| { | ||||
|         //std.log.debug("{any}", .{nodes}); | ||||
|         var tree = try line_to_tree(alloc, line, line_id); | ||||
|         corrupt_score += tree.corrupt; | ||||
|         if (tree.corrupt == 0) { | ||||
|             // Try completion | ||||
|             var score = try tree.autocomplete(); | ||||
|             std.log.debug("Line {} autocompletion score {}", .{line_id, score}); | ||||
|             try completion_scores.append(score); // score | ||||
|         } | ||||
|         line_id += 1; | ||||
|     } | ||||
|     std.log.info("[Part 1] Sum of corrupt line scores: {}", .{corrupt_score}); | ||||
|     std.sort.sort(u64, completion_scores.items, {}, comptime std.sort.asc(u64)); | ||||
| 
 | ||||
|     std.log.info( | ||||
|         "[Part 2] Completion scores: {}", | ||||
|         .{completion_scores.items[completion_scores.items.len/2]} | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| fn line_to_tree(alloc: *std.mem.Allocator, line: []const u8, id: usize) !Tree { | ||||
|     var tkzr = Tokenizer.init(line); | ||||
|     var tkns = std.ArrayList(Token).init(alloc); | ||||
|     var corrupt_score: u32 = 0; | ||||
|     while (true) { | ||||
|         var tkn = tkzr.next(); | ||||
|         if (tkn.tag != .eos) { | ||||
|             try tkns.append(tkn); | ||||
|         } | ||||
|         else { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     //std.log.debug("{} tokens", .{tkns.items.len}); | ||||
|     var nodes = std.ArrayList(Node).init(alloc); | ||||
|     try nodes.append(.{ | ||||
|         .index = 0, | ||||
|         .parent = 0, | ||||
|         .tag = .root, | ||||
|         .start_index = 0, | ||||
|     }); | ||||
|     var current_node: usize = 0; | ||||
|     for (tkns.items) |tkn, index| { | ||||
|         switch(tkn.tag) { | ||||
|             .r_paren, | ||||
|             .r_brace, | ||||
|             .r_bracket, | ||||
|             .r_angle_bracket, | ||||
|             => { | ||||
|                 if (current_node == 0) { | ||||
|                     std.log.debug("Closing token before opening token: {}", | ||||
|                                   .{tkn}); | ||||
|                     break; | ||||
|                 } | ||||
|                 else { | ||||
|                     //std.log.warn("Current node: {}", .{current_node}); | ||||
|                     nodes.items[current_node].end_index = index; | ||||
|                     if (nodes.items[current_node].tag != token_tag_to_node_tag(tkns.items[index].tag)) { | ||||
|                         std.log.warn( | ||||
|                             "Line {}: mismatched tags: {} != {}", | ||||
|                             .{id, tkns.items[nodes.items[current_node].start_index].tag, | ||||
|                               tkns.items[index].tag} | ||||
|                         ); | ||||
|                         corrupt_score += switch(tkns.items[index].tag) { | ||||
|                             .r_paren => @as(u32, 3), | ||||
|                             .r_bracket => @as(u32, 57), | ||||
|                             .r_brace => @as(u32, 1197), | ||||
|                             .r_angle_bracket => @as(u32, 25137), | ||||
|                             else => @as(u32, 0), | ||||
|                         }; | ||||
|                         break; | ||||
|                     } | ||||
|                     current_node = nodes.items[current_node].parent; | ||||
|                 } | ||||
|             }, | ||||
|             .eos, | ||||
|             .invalid, | ||||
|             => unreachable, | ||||
|             else => { | ||||
|                 // Opens a new node | ||||
|                 var node = Node { | ||||
|                     .index = nodes.items.len + 1, | ||||
|                     .parent = current_node, | ||||
|                     .start_index = index, | ||||
|                     .tag = switch(tkn.tag) { | ||||
|                         .l_paren => .paren, | ||||
|                         .l_brace => .brace, | ||||
|                         .l_bracket => .bracket, | ||||
|                         .l_angle_bracket => .angle_bracket, | ||||
|                         else => unreachable, | ||||
|                     } | ||||
|                 }; | ||||
|                 try nodes.append(node); | ||||
|                 try nodes.items[current_node].children.append(alloc, nodes.items.len - 1); | ||||
|                 current_node = nodes.items.len - 1; | ||||
|                 //std.log.warn("Start new node from token index {} at {}: {any}", | ||||
|                 //            .{index, current_node, node}); | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
|     return Tree { | ||||
|         .nodes = nodes, | ||||
|         .tokens = tkns, | ||||
|         .corrupt = corrupt_score, | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| pub const Tree = struct { | ||||
|     nodes: std.ArrayList(Node), | ||||
|     tokens: std.ArrayList(Token), | ||||
|     corrupt: u32 = 0, | ||||
| 
 | ||||
|     pub fn autocomplete(self: *Tree) anyerror!u64 { | ||||
|         // I guess we want to traverse the tree, adding in tokens for end_index | ||||
|         // where necessary | ||||
|         var node = self.nodes.items[0]; | ||||
|         var score: u64 = 0; | ||||
|         for (node.children.items) |n| { | ||||
|             score += try self.complete(&self.nodes.items[n], score); | ||||
|         } | ||||
|         return score; | ||||
|     } | ||||
| 
 | ||||
|     fn complete(self: *Tree, node: *Node, score: u64) anyerror!u64 { | ||||
|         var s = score; | ||||
|         for (node.*.children.items) |n| { | ||||
|             s += try self.complete(&self.nodes.items[n], score); | ||||
|         } | ||||
|         if (node.*.end_index) |ei| { | ||||
|             return s; | ||||
|         } | ||||
|         else { | ||||
|             try self.tokens.append(.{ | ||||
|                 .tag = switch(node.*.tag) { | ||||
|                     .paren => .r_paren, | ||||
|                     .brace => .r_brace, | ||||
|                     .bracket => .r_bracket, | ||||
|                     .angle_bracket => .r_angle_bracket, | ||||
|                     else => .invalid, | ||||
|                 }, | ||||
|                 .loc = .{.start = 0, .end = 0}, // fake | ||||
|             }); | ||||
|             node.*.end_index = self.tokens.items.len - 1; | ||||
|             s *= 5; | ||||
|             s += switch(node.*.tag) { | ||||
|                 .paren => @as(u64, 1), | ||||
|                 .brace => @as(u64, 3), | ||||
|                 .bracket => @as(u64, 2), | ||||
|                 .angle_bracket => @as(u64, 4), | ||||
|                 else => @as(u64, 0), | ||||
|             }; | ||||
|         } | ||||
|         return s; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| pub const Node = struct { | ||||
|     index: usize, | ||||
|     parent: usize, | ||||
|     children: std.ArrayListUnmanaged(usize) = .{}, | ||||
|     tag: Tag, | ||||
|     start_index: usize, | ||||
|     end_index: ?usize = null, | ||||
|     pub const Tag = enum { | ||||
|         root, | ||||
|         paren, | ||||
|         brace, | ||||
|         bracket, | ||||
|         angle_bracket, | ||||
|         invalid, | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| fn token_tag_to_node_tag(t: Token.Tag) Node.Tag { | ||||
|     switch(t) { | ||||
|         .l_paren, | ||||
|         .r_paren, | ||||
|         => return .paren, | ||||
|         .l_brace, | ||||
|         .r_brace, | ||||
|         => return .brace, | ||||
|         .l_bracket, | ||||
|         .r_bracket, | ||||
|         => return .bracket, | ||||
|         .l_angle_bracket, | ||||
|         .r_angle_bracket, | ||||
|         => return .angle_bracket, | ||||
|         else => return .invalid | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub const Token = struct { | ||||
|     tag: Tag, | ||||
|     loc: Loc, | ||||
| 
 | ||||
|     pub const Loc = struct { | ||||
|         start: usize, | ||||
|         end: usize, | ||||
|     }; | ||||
|     pub const Tag = enum { | ||||
|         l_paren, | ||||
|         r_paren, | ||||
|         l_brace, | ||||
|         r_brace, | ||||
|         l_bracket, | ||||
|         r_bracket, | ||||
|         l_angle_bracket, | ||||
|         r_angle_bracket, | ||||
|         eos, | ||||
|         invalid, | ||||
|     }; | ||||
| 
 | ||||
|     pub fn lexeme(tag: Tag) ?[]const u8 { | ||||
|         return switch (tag) { | ||||
|             .l_paren => "(", | ||||
|             .r_paren => ")", | ||||
|             .l_brace => "{", | ||||
|             .r_brace => "}", | ||||
|             .l_bracket => "[", | ||||
|             .r_bracket => "]", | ||||
|             .l_angle_bracket => "<", | ||||
|             .r_angle_bracket => ">", | ||||
|             else => "", | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| pub const Tokenizer = struct { | ||||
|     index: usize, | ||||
|     buffer: []const u8, | ||||
| 
 | ||||
|     pub fn init(buffer: []const u8) Tokenizer { | ||||
|         return Tokenizer{ | ||||
|             .buffer = buffer, | ||||
|             .index = 0, | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     pub fn next(self: *Tokenizer) Token { | ||||
|         const start_index = self.index; | ||||
|         var result = Token { | ||||
|             .tag = .eos, | ||||
|             .loc = .{ | ||||
|                 .start = start_index, | ||||
|                 .end   = undefined, | ||||
|             }, | ||||
|         }; | ||||
|         while (self.index < self.buffer.len) : (self.index += 1) { | ||||
|             const c = self.buffer[self.index]; | ||||
|             switch (c) { | ||||
|                 '(' => { | ||||
|                     result.tag = .l_paren; | ||||
|                     self.index += 1; | ||||
|                     break; | ||||
|                 }, | ||||
|                 ')' => { | ||||
|                     result.tag = .r_paren; | ||||
|                     self.index += 1; | ||||
|                     break; | ||||
|                 }, | ||||
|                 '{' => { | ||||
|                     result.tag = .l_brace; | ||||
|                     self.index += 1; | ||||
|                     break; | ||||
|                 }, | ||||
|                 '}' => { | ||||
|                     result.tag = .r_brace; | ||||
|                     self.index += 1; | ||||
|                     break; | ||||
|                 }, | ||||
|                 '[' => { | ||||
|                     result.tag = .l_bracket; | ||||
|                     self.index += 1; | ||||
|                     break; | ||||
|                 }, | ||||
|                 ']' => { | ||||
|                     result.tag = .r_bracket; | ||||
|                     self.index += 1; | ||||
|                     break; | ||||
|                 }, | ||||
|                 '<' => { | ||||
|                     result.tag = .l_angle_bracket; | ||||
|                     self.index += 1; | ||||
|                     break; | ||||
|                 }, | ||||
|                 '>' => { | ||||
|                     result.tag = .r_angle_bracket; | ||||
|                     self.index += 1; | ||||
|                     break; | ||||
|                 }, | ||||
|                 else => { | ||||
|                     result.tag = .invalid; | ||||
|                     self.index += 1; | ||||
|                     break; | ||||
|                 }, | ||||
|             } | ||||
|         } | ||||
|         if (result.tag == .eos) { | ||||
|             result.loc.start = self.index; | ||||
|         } | ||||
|         result.loc.end = self.index; | ||||
|         return result; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| test "tokenizer - all" { | ||||
|     try testTokenize("()[]{}<>", &.{ | ||||
|         .l_paren, .r_paren, .l_bracket, .r_bracket, .l_brace, .r_brace, | ||||
|         .l_angle_bracket, .r_angle_bracket | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| test "tokenizer - early end" { | ||||
|     try testTokenize("({", &.{ | ||||
|         .l_paren, .l_brace, | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| test "tokenizer - invalid" { | ||||
|     try testTokenize("<d", &.{ | ||||
|         .l_angle_bracket, .invalid, | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| fn testTokenize(source: []const u8, expected_tokens: []const Token.Tag) !void { | ||||
|     var tokenizer = Tokenizer.init(source); | ||||
|     for (expected_tokens) |expected_token_id| { | ||||
|         const token = tokenizer.next(); | ||||
|         if (token.tag != expected_token_id) { | ||||
|             std.debug.panic("expected {s}, found {s}\n", .{ @tagName(expected_token_id), @tagName(token.tag) }); | ||||
|         } | ||||
|     } | ||||
|     const last_token = tokenizer.next(); | ||||
|     try std.testing.expect(last_token.tag == .eos); | ||||
|     try std.testing.expect(last_token.loc.start == source.len); | ||||
| } | ||||
| 
 | ||||
| test "ok" { | ||||
|     var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | ||||
|     defer arena.deinit(); | ||||
|     const alloc = &arena.allocator; | ||||
|     var tree = try line_to_tree(alloc, "[<>({}){}[([])<>]]", 1); | ||||
|     try std.testing.expectEqual(@as(u32, 0), tree.corrupt); | ||||
| } | ||||
| 
 | ||||
| test "a" { | ||||
|     var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | ||||
|     defer arena.deinit(); | ||||
|     const alloc = &arena.allocator; | ||||
|     var tree = try line_to_tree(alloc, "{([(<{}[<>[]}>{[]{[(<()>", 1); | ||||
|     try std.testing.expectEqual(@as(u32, 1197), tree.corrupt); | ||||
| } | ||||
| 
 | ||||
| test "b" { | ||||
|     var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | ||||
|     defer arena.deinit(); | ||||
|     const alloc = &arena.allocator; | ||||
|     var tree = try line_to_tree(alloc, "[[<[([]))<([[{}[[()]]]", 1); | ||||
|     try std.testing.expectEqual(@as(u32, 3), tree.corrupt); | ||||
| } | ||||
| 
 | ||||
| test "c" { | ||||
|     var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | ||||
|     defer arena.deinit(); | ||||
|     const alloc = &arena.allocator; | ||||
|     var tree = try line_to_tree(alloc, "[{[{({}]{}}([{[{{{}}([]", 1); | ||||
|     try std.testing.expectEqual(@as(u32, 57), tree.corrupt); | ||||
| } | ||||
| 
 | ||||
| test "d" { | ||||
|     var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | ||||
|     defer arena.deinit(); | ||||
|     const alloc = &arena.allocator; | ||||
|     var tree = try line_to_tree(alloc, "[<(<(<(<{}))><([]([]()", 1); | ||||
|     try std.testing.expectEqual(@as(u32, 3), tree.corrupt); | ||||
| } | ||||
| 
 | ||||
| test "e" { | ||||
|     var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | ||||
|     defer arena.deinit(); | ||||
|     const alloc = &arena.allocator; | ||||
|     var tree = try line_to_tree(alloc, "<{([([[(<>()){}]>(<<{{", 1); | ||||
|     try std.testing.expectEqual(@as(u32, 25137), tree.corrupt); | ||||
| } | ||||
| 
 | ||||
| test "autocomplete simple" { | ||||
|     var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | ||||
|     defer arena.deinit(); | ||||
|     const alloc = &arena.allocator; | ||||
|     var tree = try line_to_tree(alloc, "<", 1); | ||||
|     try std.testing.expectEqual(@as(u32, 0), tree.corrupt); | ||||
|     var score = try tree.autocomplete(); | ||||
|     try std.testing.expectEqual(@as(u64, 4), score); | ||||
| } | ||||
| 
 | ||||
| test "autocomplete" { | ||||
|     var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | ||||
|     defer arena.deinit(); | ||||
|     const alloc = &arena.allocator; | ||||
|     var tree = try line_to_tree(alloc, "<{([{{}}[<[[[<>{}]]]>[]]", 1); | ||||
|     try std.testing.expectEqual(@as(u32, 0), tree.corrupt); | ||||
|     var score = try tree.autocomplete(); | ||||
|     try std.testing.expectEqual(@as(u64, 294), score); | ||||
| } | ||||
		Loading…
	
		Reference in New Issue