Re: Best way to learn 2d games with D?
On 2020-03-15 18:58, Steven Schveighoffer via Digitalmars-d-learn wrote: I'd prefer to do it with D. How about raylib in conjunction with thin d bindings? I prefer it over sdl, sfml and the like. https://www.raylib.com/examples.html (make sure to enable js for embedded examples) https://code.dlang.org/packages/raylib-d https://github.com/raysan5/raylib/blob/master/BINDINGS.md Should I just start with another language and then migrate to D later? If you can stomach lua(jit), check out love2d. Docs and provided game tutorials are super easy to follow: https://love2d.org/ https://love2d.org/wiki/Category:Tutorials Lastly, if you're more interested in the gamedev aspect, there's also the option to pick your poison from this curated mixed list of slim and fat 2d game engines: https://thomasgervraud.com/best-2d-game-engine/
Re: wordladder - code improvement
On 2020-01-31 09:44, mark via Digitalmars-d-learn wrote: I can't use the levenshtien distance because although it is a better solution, [...] Nah, it isn't, sorry for the noise, should have slept before sending the message, was thinking of hamming distance: auto a = "abcd"; auto b = "bcda"; auto hammingDistance(string a, string b) { return zip(a, b).count!(t => t[0] != t[1]); } levenshteinDistance(a, b).writeln; // => 2 hammingDistance(a, b).writeln; // => 4 main() [...] doesn't match the behaviour There's also std.range.tee if you ever need to perform additional side-effects in a range pipeline, which restores the original dot printing: write("Try "); auto res = generate!(() => genLadder(words.dup, STEPS)) .enumerate(1) .tee!(_ => write('.'), No.pipeOnPop) // No.pipeOnPop ensures we're not one dot short .find!(a => !a[1].empty) .front; writeln(" ", res[0]); genLadder() [...] is so compact. Thinking about it, you could even eliminate the prev variable all together when using ladder.back in compWords. Regarding const correctness, this article and thread might contain useful information: https://forum.dlang.org/thread/2735451.YHZktzbKJo@lyonel By the way, keep the documentation improvements coming, much appreciated!
Re: wordladder - code improvement
From one noob to another: Not much of a difference, but levenshteinDistance seems to be a good fit here. About as fast as your solution, slightly lower memory usage. byCodeUnit/byChar might shave off a few more ms. For small scripts like these I'm usually not even bothering with const correctness and selective imports. There's also import std; but that might lead to ambiguous imports. --- import std.algorithm, std.array, std.conv, std.datetime.stopwatch, std.functional, std.random, std.range, std.stdio, std.uni; enum WORDFILE = "/usr/share/hunspell/en_GB.dic"; enum WORDSIZE = 4; enum STEPS = WORDSIZE; // could be verified at compile-time static assert(WORDSIZE % 2 == 0, "WORDSIZE should be even"); alias WordList = string[]; alias WordSet = bool[string]; void main() { auto sw = StopWatch(AutoStart.yes); auto words = getWords(WORDFILE, WORDSIZE); // would be slicker with proper destructuring support auto res = generate!(() => genLadder(words.dup, STEPS)) .enumerate(1) .find!(a => !a[1].empty) .front; writeln("tries: ", res[0]); res[1].each!writeln; writeln(sw.peek); // or sw.peek.total!"msecs" } WordSet getWords(string filename, uint wordsize) { return File(filename).byLine .map!(line => line.until!(not!isAlpha)) .filter!(word => word.count == wordsize) .map!(word => word.to!string.toUpper) .assocArray(true.repeat); } WordList genLadder(WordSet words, uint steps) { WordList ladder; string update(WordList comps) { ladder ~= comps.choice; words.remove(ladder.back); return ladder.back; } WordList compWords(string prev) { return words.byKey.filter!(word => levenshteinDistance(word, prev) == 1).array; } auto prev = update(words.byKey.array); foreach (comps; generate!(() => compWords(prev)).take(steps + 1)) { if (comps.empty) return comps; prev = update(comps); } if (levenshteinDistance(ladder.front, ladder.back) < WORDSIZE) return []; return ladder; }
Re: Reading a file of words line by line
On 2020-01-16 04:54, Jesse Phillips via Digitalmars-d-learn wrote: [...] .map!(word => word.to!string.toUpper) .array .sort .uniq .map!(x => tuple (x, 0)) .assocArray ; .each!(word => words[word.to!string.toUpper] = 0); isn't far off, but could also be (sans imports): return File(filename).byLine .map!(line => line.until!(not!isAlpha)) .filter!(word => word.count == wordsize) .map!(word => word.to!string.toUpper) .assocArray(0.repeat);
Re: Reading a file of words line by line
On 2020-01-15 16:34, mark via Digitalmars-d-learn wrote: Is this as compact as it _reasonably_ can be? How about this? auto uniqueWords(string filename, uint wordsize) { import std.algorithm, std.array, std.conv, std.functional, std.uni; return File(filename).byLine .map!(line => line.until!(not!isAlpha)) .filter!(word => word.count == wordsize) .map!(word => word.to!string.toUpper) .array .sort .uniq; }
Re: Using tasks without GC?
Creates a Task on the GC heap that calls an alias. If possible, there's also scopedTask, which allocates on the stack: https://dlang.org/phobos/std_parallelism.html#.scopedTask So my question is: Has anyone done any analysis over how "dangerous" it is to use GC'd tasks for _small_ tasks (in terms of milliseconds)? Nothing major, but https://github.com/mratsim/weave/tree/master/benchmarks/fibonacci puts quite a bit of pressure on various implementations. You might want to profile ./pfib 40: import std; ulong fib(uint n) { if (n < 2) return n; auto x = scopedTask!fib(n-1); // vs. Task!fib(n-1); taskPool.put(x); auto y = fib(n-2); return x.yieldForce + y; // {yield,spin,work}Force } void main(string[] args) { enforce(args.length == 2, "Usage: fib "); auto n = args[1].to!uint; // defaultPoolThreads(totalCPUs); writefln!"fib(%d) = %d"(n, fib(n)); } At least D isn't locking up beyond 12 tasks; looking at you, stdlib-nim. :)
Re: Finding Max Value of Column in Multi-Dimesional Array
On 7/5/19 9:56 PM, ag0aep6g via Digitalmars-d-learn wrote: On 05.07.19 20:49, Samir wrote: As a follow-on to my earlier question, is there a way to pass a variable to the `map` function that specifies the column, rather than hard-coding it? I'm thinking of something like: p.map!("a[column]").maxElement.writeln; You can't do that with the string style, because the string is turned into a function inside of `map`. Your `column` isn't visible there. It works when you pass an actual callable instead, e.g. a lambda: p.map!(a => a[column]).maxElement.writeln; Furthermore, Samir, the parameter `a` can be renamed to whatever you prefer or what fits the code at hand best, e.g. `(row => row[column])`, as opposed to the string version, where only a small set of mostly single character names is supported.
Re: Finding Max Value of Column in Multi-Dimesional Array
On 7/5/19 9:56 PM, ag0aep6g via Digitalmars-d-learn wrote: On 05.07.19 20:49, Samir wrote: As a follow-on to my earlier question, is there a way to pass a variable to the `map` function that specifies the column, rather than hard-coding it? I'm thinking of something like: p.map!("a[column]").maxElement.writeln; You can't do that with the string style, because the string is turned into a function inside of `map`. Your `column` isn't visible there. It works when you pass an actual callable instead, e.g. a lambda: p.map!(a => a[column]).maxElement.writeln; Furthermore, Samir, the parameter `a` can be renamed to whatever you prefer or what fits the code at hand best, e.g. `(row => row[column])`, as opposed to the string version, where only a small set of mostly single character names is supported.
Re: Help with Regular Expressions (std.regex)
On 3/3/19 7:07 PM, Samir via Digitalmars-d-learn wrote: I am belatedly working my way through the 2018 edition of the Advent of Code[1] programming challenges using D and am stumped on Problem 3[2]. The challenge requires you to parse a set of lines in the format: #99 @ 652,39: 24x23 #100 @ 61,13: 15x24 #101 @ 31,646: 16x28 I would like to store each number (match) as an element in an array so that I can refer to them by index. There is also std.file.slurp which makes this quite easy: slurp!(int, int, int, int, int)("03.input", "#%d @ %d,%d: %dx%d"); You can then later expand the matches in a loop and process the claims: foreach(id, offX, offY, width, height; ...
Re: d word counting approach performs well but has higher mem usage
Assoc array allocations? Yup. AAs do keep their memory around (supposedly for reuse). [...] Why it consumes so much is a question to the implementation. [...] I guess built-in AAs just love to hoard. What a darn shame. This way I'm missing out on all those slick internet benchmark points. :) Guess I have to find a workaround then, since it's swapping memory like crazy on larger real-world inputs on my fairly low-end machine. What did I do wrong? Well, you didn't actually put the keys into the AA ;) I'm guessing you didn't look closely at the output, otherwise you would've noticed that something was wrong. [...] ``` Error: associative arrays can only be assigned values with immutable keys, not char[] ``` [...] But when you iterate later, pretty much every key is in fact a reference to some older memory, which is still somewhere on the GC heap; you don't get a segfault, but neither do you get correct "words". You are absolutely right, I dismissed the aforementioned error without a second thought as soon as the compiler stopped complaining by throwing a const declaration at it. Oh well, should have read the assoc array spec page more thoroughly since it contains this very snippet here: ``` auto word = line[wordStart .. wordEnd]; ++dictionary[word.idup]; // increment count for word ``` And yes, using more irregular log files as input instead of the concatenated uniform dict reveals quite a bit of nonsense that is being printed to stdout. Thank you, Stanislav, for taking the time to explain all this.
d word counting approach performs well but has higher mem usage
Hi there, the task is simple: count word occurrences from stdin (around 150mb in this case) and print sorted results to stdout in a somewhat idiomatic fashion. Now, d is quite elegant while maintaining high performance compared to both c and c++, but I, as a complete beginner, can't identify where the 10x memory usage (~300mb, see results below) is coming from. Unicode overhead? Internal buffer? Is something slurping the whole file? Assoc array allocations? Couldn't find huge allocs with dmd -vgc and -profile=gc either. What did I do wrong? ```d === void main() { import std.stdio, std.algorithm, std.range; int[string] count; foreach(const word; stdin.byLine.map!splitter.joiner) { ++count[word]; } //or even: //foreach(line; stdin.byLine) { //foreach(const word; line.splitter) { //++count[word]; //} //} count.byKeyValue .array .sort!((a, b) => a.value > b.value) .each!(a => writefln("%d %s", a.value, a.key)); } ``` ```c++ (for reference) = #include #include #include #include using namespace std; int main() { string s; unordered_map count; std::ios::sync_with_stdio(false); while (cin >> s) { count[s]++; } vector> temp {begin(count), end(count)}; sort(begin(temp), end(temp), [](const auto& a, const auto& b) {return b.second < a.second;}); for (const auto& elem : temp) { cout << elem.second << " " << elem.first << '\n'; } } ``` Results on an old celeron dual core (wall clock and res mem): 0:08.78, 313732 kb <= d dmd 0:08.25, 318084 kb <= d ldc 0:08.38, 38512 kb <= c++ idiomatic (above) 0:07.76, 30276 kb <= c++ boost 0:08.42, 26756 kb <= c verbose, hand-rolled hashtable Mem and time measured like so: /usr/bin/time -v $cmd < input >/dev/null Input words file creation (around 300k * 50 words): tr '\n' ' ' < /usr/share/dict/$lang > joined for i in {1..50}; do cat joined >> input; done word count sample output: [... snip ...] 50 ironsmith 50 gloried 50 quindecagon 50 directory's 50 hydrobiological Compilation flags: dmd -O -release -mcpu=native -ofwc-d-dmd wc.d ldc2 -O3 -release -flto=full -mcpu=native -ofwc-d-ldc wc.d clang -std=c11 -O3 -march=native -flto -o wp-c-clang wp.c clang++ -std=c++17 -O3 -march=native -flto -o wp-cpp-clang wp-boost.cpp Versions: dmd: v2.082.1 ldc: 1.12.0 (based on DMD v2.082.1 and LLVM 6.0.1) llvm/clang: 6.0.1