module HangmanService; import std.stdio; import std.file; import std.string; import std.conv; //import std.windows.charset; import ASockets; const PORT = 53260; // TODO: Remove when D handles SIGPIPE... extern (C) { alias void function(int) sighandler_t; const int SIGPIPE = 13; sighandler_t signal(int signum, sighandler_t handler); void ignore_sigpipe(int signo) {} } struct Word { string word; int score; } Word*[][] words; Word*[string] wordReference; char upcase(char c) { if (c>='a' && c<='z') c -= 32; return c; } string process(string line) { line = toupper(line); int[256] score; bool[256] garbage; int pos = find(line, ' '); if (pos>0) { foreach (c;line[pos+1..$]) garbage[c] = true; line = line[0..pos]; } foreach (c;line) garbage[c] = true; int[] wordIndexes; wordloop: foreach (n,word;words[line.length]) { foreach (i,c;line) if (c=='_') { if (garbage[upcase(word.word[i])]) continue wordloop; } else { if (c!=upcase(word.word[i])) continue wordloop; } bool found = false; foreach (i,c;line) if (c=='_') { score[upcase(word.word[i])] += word.score; found = true; } if (found) wordIndexes ~= n; } struct Match { char c; int score; int opCmp(Match* m) { return m.score-score; } } Match[] matches; for (char c='a';c<='z';c++) score[c-32] += score[c]; long total; foreach (c,s;score['A'..'Z']) if (s) { matches ~= Match(c+'A', s); total += s; } matches.sort; string matchString; foreach (ref m;matches) //matchString ~= m.c; matchString ~= format("%s - %.1f%%\n", m.c, cast(float)m.score/total*100); //writefln("%s", fromMBSz(toString(matchString.ptr), 1252)); matchString ~= "--------\n"; matchString ~= format("%d words matched\n", wordIndexes.length); static int lineLength; lineLength = line.length; struct ComplexWord { int index; int opCmp(ComplexWord* m) { return words[lineLength][m.index].score - words[lineLength][index].score; } } if (wordIndexes.length<100) { (cast(ComplexWord[])wordIndexes).sort; foreach(n;wordIndexes) with (*words[lineLength][n]) matchString ~= format("%s - %d points\n", word, score); } return matchString ~ \n; } class Connection { LineBufferedSocket socket; this(LineBufferedSocket socket) { this.socket = socket; socket.handleReadLine = &onReadLine; } void onReadLine(LineBufferedSocket sender, string line) { sender.send(process(strip(line))); //sender.disconnect(); } } alias GenericServerSocket!(LineBufferedSocket) LineServerSocket; class HangmanService { LineServerSocket listener; this() { listener = new LineServerSocket(); listener.handleAccept = &onAccept; } void run() { auto host = new InternetHost(); host.getHostByAddr("127.0.0.1"); listener.listen(PORT, host.addrList[0]); socketManager.loop(); } void onAccept(LineBufferedSocket incoming) { new Connection(incoming); } } void main() { foreach (fn;listdir(".", "*-*.*")) { //writef("Loading %s... \r", fn); fflush(stdout); fn = fn[2..$]; int sep1 = find(fn, '-'); int sep2 = find(fn, '.'); //writefln("%s / %d / %d", fn, sep1, sep2); string category = fn[0..sep1]; string classification = fn[sep1+1..sep2]; int size = toInt(fn[sep2+1..$]); int score = (100-size) * 100; if (classification == "proper-names") score /= 10; else if (classification == "abbreviations") score /= 2; lineloop: foreach(line;splitlines(cast(string)read(fn))) if (line.length) { foreach(ref c;line) if (c>=127) continue lineloop; // if (c>='a' && c<='z') // c -= 32; if (line in wordReference) { if (wordReference[line].score < score) wordReference[line].score = score; } else { if (words.length<=line.length) words.length = line.length+1; auto word = new Word; *word = Word(line, score); words[line.length] ~= word; wordReference[line] = word; } } } signal(SIGPIPE, &ignore_sigpipe); auto application = new HangmanService(); application.run(); }