From b9945e8097b4aa58a1b6ce933b285619cd28b7f0 Mon Sep 17 00:00:00 2001 From: Lumen Keyes Date: Sat, 6 Jul 2024 00:18:29 -0600 Subject: [PATCH] new way of doing things! it's slower :(( --- src/print.zig | 271 +++++++++++++++++++++++------------------ src/selectiveParse.zig | 52 ++++++++ 2 files changed, 206 insertions(+), 117 deletions(-) create mode 100644 src/selectiveParse.zig diff --git a/src/print.zig b/src/print.zig index 3e38092..17b7367 100644 --- a/src/print.zig +++ b/src/print.zig @@ -1,4 +1,4 @@ -//TODO: +//TODO: const std = @import("std"); const clap = @import("clap"); const print = std.debug.print; @@ -11,28 +11,19 @@ const expect = std.testing.expect; const assert = std.debug.assert; const Card = struct { - name: []const u8 = "",//string - mana_cost: []const u8 = "",//string - cmc: f32 = 0,//technically a float? but I think we can always cast safely cast. EDIT: NOPE - type_line: []const u8 = "",//string - oracle_text: []const u8 = "",//string - power: []const u8 = "",//coerced to string - toughness: []const u8 = "",//coerced to string - card_faces: ?[]Card = null,//array of cards + name: []const u8 = "", //string + mana_cost: []const u8 = "", //string + cmc: f32 = 0, //technically a float? but I think we can always cast safely cast. EDIT: NOPE + type_line: []const u8 = "", //string + oracle_text: []const u8 = "", //string + power: []const u8 = "", //coerced to string + toughness: []const u8 = "", //coerced to string + card_faces: ?[]Card = null, //array of cards }; -const TextCard = struct { - lines: [][]const u8 = undefined -}; +const TextCard = struct { lines: [][]const u8 = undefined }; -const PandocOptions = &[_][]const u8{ - "pandoc", - "out.md", - "-o", "out.pdf", - "--pdf-engine", "xelatex", - "-V", "mainfont:Liberation Mono", - "-V", "geometry:margin=0cm" -}; +const PandocOptions = &[_][]const u8{ "pandoc", "out.md", "-o", "out.pdf", "--pdf-engine", "xelatex", "-V", "mainfont:Liberation Mono", "-V", "geometry:margin=0cm" }; //dimension constants and defaults const cardWidth = 30; @@ -41,7 +32,6 @@ const minCardHeight = 5; const pageHeight = 66; var heightMayVary = false; - const formatString = "{s: <" ++ std.fmt.digits2(cardWidth) ++ "}"; const lineFormatter = "|" ++ formatString; const spacer: []const u8 = "|" ++ (" " ** cardWidth); @@ -51,10 +41,10 @@ const pageWidth = fullWidthSpacer.len; const markdownFormatString = "```" ++ (" " ** (pageWidth - 4)) ++ "\n"; test "Check constants" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - const paddedLine = try std.fmt.allocPrint(gpa.allocator(), lineFormatter, .{"hello> woooooooooooooooooooorl"}); - try expect(paddedLine.len == spacer.len); - try expect(pageWidth == markdownFormatString.len); + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + const paddedLine = try std.fmt.allocPrint(gpa.allocator(), lineFormatter, .{"hello> woooooooooooooooooooorl"}); + try expect(paddedLine.len == spacer.len); + try expect(pageWidth == markdownFormatString.len); } pub fn main() !void { @@ -62,7 +52,9 @@ pub fn main() !void { //TODO: properly handle program arguments _ = args.next(); //handle program name (args[0]) - const listFileName: []const u8 = args.next() orelse {return error.ExpectedArgument;}; + const listFileName: []const u8 = args.next() orelse { + return error.ExpectedArgument; + }; heightMayVary = stringToBool(args.next()); var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); @@ -70,66 +62,114 @@ pub fn main() !void { const allocator = arena.allocator(); const oracleFile = try cwd.openFile(oracleFileName, .{}); - var jsonReader = json.reader(allocator, oracleFile.reader()); - const parsedJson = try json.parseFromTokenSource([]Card, allocator, &jsonReader, .{.ignore_unknown_fields = true}); + // var jsonReader = json.reader(allocator, oracleFile.reader()); + // const parsedJson = try json.parseFromTokenSource([]Card, allocator, &jsonReader, .{.ignore_unknown_fields = true}); - var allCards = std.StringHashMap(Card).init(allocator); - for(parsedJson.value) |cardObj| { - try allCards.put(cardObj.name, cardObj); - } - parsedJson.deinit(); - - var line = std.ArrayList(u8).init(allocator); - + var cardNames = std.ArrayList([]const u8).init(allocator); const listReader = (try cwd.openFile(listFileName, .{})).reader(); - var allPrinted = std.ArrayList(u8).init(allocator); - - var cards = std.ArrayList(TextCard).init(allocator); - // var pages = std.ArrayList(page).init(allocator); + var line = std.ArrayList(u8).init(allocator); while (listReader.streamUntilDelimiter(line.writer(), '\n', null)) { defer line.clearRetainingCapacity(); - const cardName = line.items[indexOf(u8, line.items, " ").? + 1..indexOf(u8, line.items, "(").? - 1]; - assert(cardName.len > 0); - const cardText = try card(allCards.get(cardName).?); - try cards.append(cardText); - } else |err| switch(err) { + const cardName = line.items[indexOf(u8, line.items, " ").? + 1 .. indexOf(u8, line.items, "(").? - 1]; + try cardNames.append(try allocator.dupe(u8, cardName)); + } else |err| switch (err) { error.EndOfStream => {}, else => return err, } - - for(cards.items) |cardText| { - std.debug.print("{any}\n", .{cardText}); + + var depth: u32 = 0; + var cardString = std.ArrayList(u8).init(allocator); + var cards = std.StringHashMap(Card).init(allocator); + while (oracleFile.reader().readByte()) |char| { + if (char == '{') depth += 1; + if (depth != 0) try cardString.append(char); + if (char == '}') { + depth -= 1; + if (depth == 0) { + // print("{s}\n", .{cardString.items}); + const parsedCard = try std.json.parseFromSlice(Card, allocator, cardString.items, .{ .ignore_unknown_fields = true }); + var lookupTimer = try std.time.Timer.start(); + for (cardNames.items, 0..) |cardName, i| { + if (std.mem.eql(u8, parsedCard.value.name, cardName)) { + // print("{s}\n", .{parsedCard.value.name}); + try cards.putNoClobber(try allocator.dupe(u8, parsedCard.value.name), (try allocator.dupe(Card, &[_]Card{parsedCard.value}))[0]); + _ = cardNames.orderedRemove(i); + } + } + cardString.clearAndFree(); + print("took {d:.10}\n", .{lookupTimer.read() / (1000 * 1000 * 1000)}); + } + } + } else |e| { + switch (e) { + error.EndOfStream => {}, + else => { + return e; + }, + } } + var cardIterator = cards.valueIterator(); + while (cardIterator.next()) |cardObj| { + print("{any}\n", .{cardObj}); + } + + // var allCards = std.StringHashMap(Card).init(allocator); + // for(parsedJson.value) |cardObj| { + // try allCards.put(cardObj.name, cardObj); + // } + // parsedJson.deinit(); + // + + // var allPrinted = std.ArrayList(u8).init(allocator); + + // var cards = std.ArrayList(TextCard).init(allocator); + // // var pages = std.ArrayList(page).init(allocator); + // while (listReader.streamUntilDelimiter(line.writer(), '\n', null)) { + // defer line.clearRetainingCapacity(); + // const cardName = line.items[indexOf(u8, line.items, " ").? + 1..indexOf(u8, line.items, "(").? - 1]; + // assert(cardName.len > 0); + // const cardText = try card(allCards.get(cardName).?); + // try cards.append(cardText); + // } else |err| switch(err) { + // error.EndOfStream => {}, + // else => return err, + // } + // + // for(cards.items) |cardText| { + // std.debug.print("{any}\n", .{cardText}); + // } //sort the cards - std.mem.sort(TextCard, cards.items, {}, compareTwo); + // std.mem.sort(TextCard, cards.items, {}, compareTwo); //TODO (fixme): absolutely GARBAGE hack to get pandoc to preserve whitespace - try allPrinted.appendSlice(markdownFormatString); + // try allPrinted.appendSlice(markdownFormatString); - var rowToPrint = std.ArrayList(TextCard).init(allocator); - for(cards.items) |cardObj| { - try rowToPrint.append(cardObj); - std.debug.print("{any}\n", .{cardObj}); - if(rowToPrint.items.len >= 3) { - try cardRow.print(allocator, rowToPrint.items, &allPrinted); - rowToPrint.clearAndFree(); - } - } else { - try cardRow.print(allocator, rowToPrint.items, &allPrinted); - try allPrinted.appendSlice(markdownFormatString); - std.debug.print("{s}", .{allPrinted.items}); - try cwd.writeFile(.{.sub_path = "out.md", .data = allPrinted.items}); - rowToPrint.clearAndFree(); - var pandocProcess = std.process.Child.init(PandocOptions, allocator); - _ = try pandocProcess.spawnAndWait(); - } + // var rowToPrint = std.ArrayList(TextCard).init(allocator); + // for(cards.items) |cardObj| { + // try rowToPrint.append(cardObj); + // std.debug.print("{any}\n", .{cardObj}); + // if(rowToPrint.items.len >= 3) { + // try cardRow.print(allocator, rowToPrint.items, &allPrinted); + // rowToPrint.clearAndFree(); + // } + // // } else { + // try cardRow.print(allocator, rowToPrint.items, &allPrinted); + // try allPrinted.appendSlice(markdownFormatString); + // std.debug.print("{s}", .{allPrinted.items}); + // try cwd.writeFile(.{.sub_path = "out.md", .data = allPrinted.items}); + // rowToPrint.clearAndFree(); + // var pandocProcess = std.process.Child.init(PandocOptions, allocator); + // _ = try pandocProcess.spawnAndWait(); + // } } fn compareTwo(_: void, a: TextCard, b: TextCard) bool { return a.lines.len < b.lines.len; } -fn card(cardObj: Card,) !TextCard { +fn card( + cardObj: Card, +) !TextCard { var buffer: [cardHeight * 1024]u8 = undefined; var cardTextAllocator = std.heap.FixedBufferAllocator.init(&buffer); defer cardTextAllocator.reset(); @@ -139,36 +179,38 @@ fn card(cardObj: Card,) !TextCard { var fullUnformattedText = std.ArrayList(u8).init(cta); try fullUnformattedText.appendSlice(cardObj.name); try fullUnformattedText.appendSlice(try std.mem.concat(cta, u8, &[_][]const u8{ - if(cardObj.mana_cost.len > 0) " " else "", + if (cardObj.mana_cost.len > 0) " " else "", cardObj.mana_cost, " (", cardObj.type_line, ") >> ", cardObj.oracle_text, - if(cardObj.power.len > 0) " >> " else "", + if (cardObj.power.len > 0) " >> " else "", cardObj.power, - if(cardObj.power.len > 0) "/" else "", + if (cardObj.power.len > 0) "/" else "", cardObj.toughness, })); - - if(cardObj.card_faces) |faces| { - for(faces, 0..) |face, idx| { + + if (cardObj.card_faces) |faces| { + for (faces, 0..) |face, idx| { try fullUnformattedText.appendSlice(face.oracle_text); - if(face.power.len > 0) try fullUnformattedText.appendSlice(" "); + if (face.power.len > 0) try fullUnformattedText.appendSlice(" "); try fullUnformattedText.appendSlice(face.power); - if(face.power.len > 0) try fullUnformattedText.appendSlice("/"); + if (face.power.len > 0) try fullUnformattedText.appendSlice("/"); try fullUnformattedText.appendSlice(face.toughness); - if(idx == 0) try fullUnformattedText.appendSlice(" // "); + if (idx == 0) try fullUnformattedText.appendSlice(" // "); } } var line = std.ArrayList(u8).init(cta); var word = std.ArrayList(u8).init(cta); - for(fullUnformattedText.items) |char| { - try switch(char) { + for (fullUnformattedText.items) |char| { + try switch (char) { '\n', ' ' => addWord(&word, &line, &cardText), - else => if(std.ascii.isASCII(char)) {try word.append(char);} + else => if (std.ascii.isASCII(char)) { + try word.append(char); + }, }; } else { try addWord(&word, &line, &cardText); @@ -177,12 +219,12 @@ fn card(cardObj: Card,) !TextCard { try cardText.append(lineToBeAdded); line.clearAndFree(); } - while(wrongCardHeight(cardText.items.len)) { + while (wrongCardHeight(cardText.items.len)) { try cardText.append(" " ** (cardWidth - 2)); } try cardText.append(" " ** (cardWidth - 2)); // return cardText.items; - return TextCard{.lines = try cardText.toOwnedSlice()}; + return TextCard{ .lines = try cardText.toOwnedSlice() }; } fn wrongCardHeight(length: usize) bool { @@ -190,47 +232,47 @@ fn wrongCardHeight(length: usize) bool { } fn addWord(word: *std.ArrayList(u8), line: *std.ArrayList(u8), cardText: *std.ArrayList([]const u8)) !void { - if(line.items.len + word.items.len >= (cardWidth)) { - const lineToBeAdded = std.mem.trimRight(u8, try line.toOwnedSlice(), " "); - assert(lineToBeAdded.len < 30); - try cardText.append(lineToBeAdded); - line.clearAndFree(); - } - try line.appendSlice(word.items); - try line.append(' '); - word.clearAndFree(); + if (line.items.len + word.items.len >= (cardWidth)) { + const lineToBeAdded = std.mem.trimRight(u8, try line.toOwnedSlice(), " "); + assert(lineToBeAdded.len < 30); + try cardText.append(lineToBeAdded); + line.clearAndFree(); + } + try line.appendSlice(word.items); + try line.append(' '); + word.clearAndFree(); } const linesList = std.MultiArrayList(cardRow); -const cardRow = struct{ - first: []const u8 = spacer, +const cardRow = struct { + first: []const u8 = spacer, second: []const u8 = spacer, - third: []const u8 = spacer, - last: []const u8 = "\n", + third: []const u8 = spacer, + last: []const u8 = "\n", fn print(allocator: std.mem.Allocator, cards: []TextCard, allPrinted: *std.ArrayList(u8)) !void { - _ = allocator; + _ = allocator; var gpa = std.heap.GeneralPurposeAllocator(.{}){}; var lines = linesList{}; defer lines.deinit(gpa.allocator()); - for(cards, 0..) |cardObj, cardNo| { + for (cards, 0..) |cardObj, cardNo| { //const cardText = try card(cardObj); const cardText = cardObj.lines; - for(cardText, 0..) |line, idx| { + for (cardText, 0..) |line, idx| { //this step is probably unnecessary const strippedLine = std.mem.trimRight(u8, line, " "); const paddedLine = try std.fmt.allocPrint(gpa.allocator(), lineFormatter, .{strippedLine}); const theoreticalLength = (paddedLine.len * 3) + 1; assert(paddedLine.len == spacer.len); assert(theoreticalLength == pageWidth); - const placeholder = if(idx < lines.items(.first).len) lines.get(idx) else cardRow{}; - const new: cardRow = switch(cardNo) { - 0 => .{.first = paddedLine}, - 1 => .{.first = placeholder.first, .second = paddedLine}, - 2 => .{.first = placeholder.first, .second = placeholder.second, .third = paddedLine}, - else => unreachable + const placeholder = if (idx < lines.items(.first).len) lines.get(idx) else cardRow{}; + const new: cardRow = switch (cardNo) { + 0 => .{ .first = paddedLine }, + 1 => .{ .first = placeholder.first, .second = paddedLine }, + 2 => .{ .first = placeholder.first, .second = placeholder.second, .third = paddedLine }, + else => unreachable, }; - if(idx < lines.items(.first).len) { + if (idx < lines.items(.first).len) { lines.set(idx, new); } else { try lines.append(gpa.allocator(), new); @@ -238,20 +280,15 @@ const cardRow = struct{ } } const rowHeight = lines.items(.first).len; - while(remainingPage(allPrinted.items.len) <= rowHeight) { + while (remainingPage(allPrinted.items.len) <= rowHeight) { try allPrinted.appendSlice(fullWidthSpacer); } - for(lines.items(.first), 0..) |_,idx| { - const line = lines.get(idx); - const printedWidth = line.first.len + line.second.len + line.third.len + line.last.len; - assert(printedWidth == pageWidth); - const fullLine = try std.mem.concat(gpa.allocator(), u8, &[_][]const u8{ - line.first, - line.second, - line.third, - line.last - }); - try allPrinted.appendSlice(fullLine); + for (lines.items(.first), 0..) |_, idx| { + const line = lines.get(idx); + const printedWidth = line.first.len + line.second.len + line.third.len + line.last.len; + assert(printedWidth == pageWidth); + const fullLine = try std.mem.concat(gpa.allocator(), u8, &[_][]const u8{ line.first, line.second, line.third, line.last }); + try allPrinted.appendSlice(fullLine); } } }; diff --git a/src/selectiveParse.zig b/src/selectiveParse.zig new file mode 100644 index 0000000..09f3be2 --- /dev/null +++ b/src/selectiveParse.zig @@ -0,0 +1,52 @@ +const std = @import("std"); +const cwd = std.fs.cwd; +const json = std.json; +const print = std.debug.print; +const oracleFileName = "oracle-cards-20240701090158.json"; + +const Card = struct { + name: []const u8 = "", //string + mana_cost: []const u8 = "", //string + cmc: f32 = 0, //technically a float? but I think we can always cast safely cast. EDIT: NOPE + type_line: []const u8 = "", //string + oracle_text: []const u8 = "", //string + power: []const u8 = "", //coerced to string + toughness: []const u8 = "", //coerced to string + card_faces: ?[]Card = null, //array of cards +}; + +const testCardName = "Raffine, Scheming Seer"; + +const cardList = std.MultiArrayList(Card); +pub fn main() !void { + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena.deinit(); + + const allocator = arena.allocator(); + const oracleFile = try cwd().openFile(oracleFileName, .{}); + const fileReader = oracleFile.reader(); + // var jsonReader = json.reader(allocator, oracleFile.reader()); + // var fields = std.ArrayList(Field).init(allocator); + // var isVal = false; + // var cards = std.StringHashMap(*StringHashMap); + // var currentCard = std.ArrayList(std.json.Token).init(allocator); + var depth: u32 = 0; + var cardString = std.ArrayList(u8).init(allocator); + var idx: u32 = 0; + while (fileReader.readByte()) |char| { + if (char == '{') depth += 1; + if (depth != 0) try cardString.append(char); + if (char == '}') { + depth -= 1; + if (depth == 0) { + // print("{s}\n", .{cardString.items}); + const parsedCard = try std.json.parseFromSlice(Card, allocator, cardString.items, .{ .ignore_unknown_fields = true }); + print("{s}\n", .{parsedCard.value.name}); + cardString.clearAndFree(); + } + } + idx += 1; + } else |e| { + return e; + } +}