summaryrefslogtreecommitdiff
path: root/quackleio
diff options
context:
space:
mode:
authorJason Katz-Brown <jason@airbnb.com>2013-08-25 02:17:13 -0700
committerJason Katz-Brown <jason@airbnb.com>2013-08-25 02:17:13 -0700
commit9306cb60c32082c5403931de0823a9fd5daa196c (patch)
treeca1b6eb695fdf3f0c2294e92416b272164bae642 /quackleio
parent8fb2c681cecc01b46b0f4ba02d5cc177c4747b1c (diff)
Initial git commit.
Diffstat (limited to 'quackleio')
-rw-r--r--quackleio/.gitignore6
-rw-r--r--quackleio/LICENSE5
-rw-r--r--quackleio/README6
-rw-r--r--quackleio/TODO5
-rw-r--r--quackleio/dict.cpp130
-rw-r--r--quackleio/dict.h91
-rw-r--r--quackleio/dictfactory.cpp36
-rw-r--r--quackleio/dictfactory.h40
-rw-r--r--quackleio/dictimplementation.cpp104
-rw-r--r--quackleio/dictimplementation.h49
-rw-r--r--quackleio/flexiblealphabet.cpp131
-rw-r--r--quackleio/flexiblealphabet.h49
-rw-r--r--quackleio/froggetopt.cpp660
-rw-r--r--quackleio/froggetopt.h121
-rw-r--r--quackleio/gcgio.cpp377
-rw-r--r--quackleio/gcgio.h47
-rw-r--r--quackleio/iotest/.gitignore6
-rw-r--r--quackleio/iotest/capp.gcg34
-rw-r--r--quackleio/iotest/iotest.cpp78
-rw-r--r--quackleio/iotest/iotest.pro29
-rw-r--r--quackleio/iotest/trademarkedboards.cpp148
-rw-r--r--quackleio/iotest/trademarkedboards.h40
-rw-r--r--quackleio/logania.h61
-rw-r--r--quackleio/quackleio.pro34
-rw-r--r--quackleio/queenie.cpp87
-rw-r--r--quackleio/queenie.h62
-rw-r--r--quackleio/streamingreporter.cpp53
-rw-r--r--quackleio/streamingreporter.h50
-rw-r--r--quackleio/util.cpp212
-rw-r--r--quackleio/util.h96
30 files changed, 2847 insertions, 0 deletions
diff --git a/quackleio/.gitignore b/quackleio/.gitignore
new file mode 100644
index 0000000..f878785
--- /dev/null
+++ b/quackleio/.gitignore
@@ -0,0 +1,6 @@
+Makefile
+obj
+Makefile.Debug
+Makefile.Release
+debug
+release
diff --git a/quackleio/LICENSE b/quackleio/LICENSE
new file mode 100644
index 0000000..8233446
--- /dev/null
+++ b/quackleio/LICENSE
@@ -0,0 +1,5 @@
+Copyright (c) 2005-2006, Jason Katz-Brown and John O'Laughlin.
+
+libquackleio, the Quackle input/output library, is under the same license
+as libquackle in the parent directory. Please see quackle/LICENSE for license
+information.
diff --git a/quackleio/README b/quackleio/README
new file mode 100644
index 0000000..d7ed61e
--- /dev/null
+++ b/quackleio/README
@@ -0,0 +1,6 @@
+IO library for saving and loading Quackle data structures.
+
+Supported formats:
+
+- GCG
+ See http://www.poslfit.com/scrabble/gcg
diff --git a/quackleio/TODO b/quackleio/TODO
new file mode 100644
index 0000000..01e57b2
--- /dev/null
+++ b/quackleio/TODO
@@ -0,0 +1,5 @@
+GCG:
+
+challenge bonus
+internation-rules endgame score adjustment
+time penalties
diff --git a/quackleio/dict.cpp b/quackleio/dict.cpp
new file mode 100644
index 0000000..e949ef0
--- /dev/null
+++ b/quackleio/dict.cpp
@@ -0,0 +1,130 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <vector>
+#include <map>
+
+#include "dict.h"
+#include "util.h"
+
+using namespace std;
+using namespace Dict;
+
+WordList::SortType WordList::sortType = Playability;
+
+WordList::WordList()
+{
+}
+
+WordList::~WordList()
+{
+}
+
+void WordList::setSortBy(SortType _sortType)
+{
+ sortType = _sortType;
+}
+
+bool operator<(const Dict::Word &word1, const Dict::Word &word2)
+{
+ switch (Dict::WordList::sortType)
+ {
+ case Dict::WordList::Alphabetical:
+ return word1.word < word2.word;
+
+ case Dict::WordList::Playability:
+ if (word1.playability != word2.playability)
+ return word1.playability > word2.playability;
+
+ if (word1.word.length() != word2.word.length())
+ return word1.word.length() < word2.word.length();
+
+ // fall through
+
+ case Dict::WordList::Probability:
+ return word1.probability > word2.probability;
+
+ case Dict::WordList::Length:
+ case Dict::WordList::LengthLongestFirst:
+ {
+ bool ret;
+ if (word1.word.length() != word2.word.length())
+ ret = word1.word.length() < word2.word.length();
+ else
+ ret = word1.word < word2.word;
+
+ if (Dict::WordList::sortType == Dict::WordList::LengthLongestFirst)
+ return !ret;
+ return ret;
+ }
+ }
+
+ return false;
+}
+
+ExtensionList Word::extensionsByLength(int length, const ExtensionList &list)
+{
+ ExtensionList ret;
+
+ for (ExtensionList::const_iterator it = list.begin(); it != list.end(); ++it)
+ {
+ if ((*it).extensionLetterString.length() == length)
+ {
+ Extension extension(*it);
+ extension.word = QuackleIO::Util::letterStringToQString((*it).extensionLetterString);
+ ret.append(extension);
+ }
+ }
+
+ return ret;
+}
+
+ExtensionList Word::getFrontExtensionList() const
+{
+ return getExtensionList(true);
+}
+
+ExtensionList Word::getBackExtensionList() const
+{
+ return getExtensionList(false);
+}
+
+ExtensionList Word::getExtensionList(bool front) const
+{
+ ExtensionList ret;
+
+ const vector<Quackle::ExtensionWithInfo> *list = front? &frontExtensions : &backExtensions;
+
+ for (vector<Quackle::ExtensionWithInfo>::const_iterator it = list->begin(); it != list->end(); ++it)
+ {
+ Extension extension(*it);
+ extension.word = QuackleIO::Util::letterStringToQString((*it).extensionLetterString);
+ ret.append(extension);
+ }
+
+ return ret;
+}
+
+Extension::Extension(const Quackle::ExtensionWithInfo extensionWithInfo)
+{
+ playability = extensionWithInfo.playability;
+ probability = extensionWithInfo.probability;
+ british = extensionWithInfo.british;
+}
diff --git a/quackleio/dict.h b/quackleio/dict.h
new file mode 100644
index 0000000..4935e4b
--- /dev/null
+++ b/quackleio/dict.h
@@ -0,0 +1,91 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef QUACKLEIO_DICT_H
+#define QUACKLEIO_DICT_H
+
+#include <vector>
+
+#include <QStringList>
+
+#include <alphabetparameters.h>
+#include <generator.h>
+
+namespace Dict
+{
+
+class Extension : public Quackle::ExtensionWithInfo
+{
+public:
+ Extension() {}
+ Extension(const Quackle::ExtensionWithInfo extensionWithInfo);
+ QString word;
+};
+
+typedef QList<Extension> ExtensionList;
+
+class Word : public Quackle::WordWithInfo
+{
+public:
+ QString word;
+
+ static ExtensionList extensionsByLength(int length, const ExtensionList &list);
+
+ ExtensionList getFrontExtensionList() const;
+ ExtensionList getBackExtensionList() const;
+
+private:
+ ExtensionList getExtensionList(bool front) const;
+};
+
+class WordList : public QList<Word>
+{
+public:
+ WordList();
+ ~WordList();
+
+ enum SortType { Alphabetical, Playability, Length, LengthLongestFirst, Probability };
+
+ void setSortBy(SortType sortType);
+ static SortType sortType;
+};
+
+typedef QList<WordList> WordListList;
+
+class Querier
+{
+public:
+ virtual ~Querier() {};
+
+ enum QueryFlags { None = 0x0000, WithExtensions = 0x0001, NoRequireAllLetters = 0x0002, CallUpdate = 0x0004 };
+
+ virtual WordList query(const QString &query, int flags = None) = 0;
+ virtual QString alphagram(const QString &letters) const = 0;
+ virtual bool isBritish(const Quackle::LetterString &word) = 0;
+ virtual bool isLoaded() const = 0;
+};
+
+}
+
+// Returns true if word1 is less playable than word2;
+// otherwise returns false.
+bool operator<(const Dict::Word &word1, const Dict::Word &word2);
+
+#endif
diff --git a/quackleio/dictfactory.cpp b/quackleio/dictfactory.cpp
new file mode 100644
index 0000000..1166390
--- /dev/null
+++ b/quackleio/dictfactory.cpp
@@ -0,0 +1,36 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include "dictfactory.h"
+#include "dictimplementation.h"
+
+using namespace QuackleIO;
+
+Dict::Querier *DictFactory::m_querier = 0;
+
+Dict::Querier *DictFactory::querier()
+{
+ if (!m_querier)
+ {
+ m_querier = new DictImplementation;
+ }
+
+ return m_querier;
+}
diff --git a/quackleio/dictfactory.h b/quackleio/dictfactory.h
new file mode 100644
index 0000000..9693179
--- /dev/null
+++ b/quackleio/dictfactory.h
@@ -0,0 +1,40 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef QUACKLE_DICTFACTORY_H
+#define QUACKLE_DICTFACTORY_H
+
+#include "dict.h"
+
+namespace QuackleIO
+{
+
+class DictFactory
+{
+public:
+ static Dict::Querier *querier();
+
+private:
+ static Dict::Querier *m_querier;
+};
+
+}
+
+#endif
diff --git a/quackleio/dictimplementation.cpp b/quackleio/dictimplementation.cpp
new file mode 100644
index 0000000..5ea2e15
--- /dev/null
+++ b/quackleio/dictimplementation.cpp
@@ -0,0 +1,104 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <alphabetparameters.h>
+#include <datamanager.h>
+#include <generator.h>
+#include <lexiconparameters.h>
+#include <quackleio/util.h>
+
+#include "dictimplementation.h"
+
+QuackleIO::DictImplementation::DictImplementation()
+{
+}
+
+QuackleIO::DictImplementation::~DictImplementation()
+{
+}
+
+Dict::WordList QuackleIO::DictImplementation::query(const QString &query, int flags)
+{
+ QString modifiedQuery = query;
+ modifiedQuery.replace(".", "?");
+
+ int anagramFlags = Quackle::Generator::ClearBlanknesses;
+
+ if (flags & Dict::Querier::NoRequireAllLetters)
+ anagramFlags |= Quackle::Generator::NoRequireAllLetters;
+
+ QRegExp wildcardRegexp("[\\*/]");
+ if (wildcardRegexp.indexIn(modifiedQuery) >= 0)
+ {
+ if (!(flags & Dict::Querier::NoRequireAllLetters))
+ anagramFlags |= Quackle::Generator::AddAnyLetters;
+
+ modifiedQuery.replace(wildcardRegexp, QString());
+ }
+
+ vector<Quackle::LetterString> words(m_generator.anagramLetters(QuackleIO::Util::encode(modifiedQuery), anagramFlags));
+ Dict::WordList ret;
+
+ vector<Quackle::LetterString>::const_iterator end = words.end();
+ for (vector<Quackle::LetterString>::const_iterator it = words.begin(); it != end; ++it)
+ {
+ Dict::Word dictWord;
+ dictWord.word = QuackleIO::Util::letterStringToQString(*it);
+ dictWord.wordLetterString = (*it);
+ m_generator.storeWordInfo(&dictWord);
+
+ if (flags & WithExtensions)
+ m_generator.storeExtensions(&dictWord);
+
+ ret.push_back(dictWord);
+ }
+
+ if (flags & NoRequireAllLetters)
+ {
+ ret.setSortBy(Dict::WordList::LengthLongestFirst);
+ }
+ else
+ {
+ ret.setSortBy(Dict::WordList::Alphabetical);
+ }
+
+ qSort(ret);
+
+ return ret;
+}
+
+QString QuackleIO::DictImplementation::alphagram(const QString &letters) const
+{
+ return QuackleIO::Util::letterStringToQString(QuackleIO::Util::alphagram(QuackleIO::Util::encode(letters)));
+}
+
+bool QuackleIO::DictImplementation::isLoaded() const
+{
+ return QUACKLE_LEXICON_PARAMETERS->hasSomething();
+}
+
+bool QuackleIO::DictImplementation::isBritish(const Quackle::LetterString &word)
+{
+ Quackle::WordWithInfo wordWithInfo;
+ wordWithInfo.wordLetterString = word;
+ m_generator.storeWordInfo(&wordWithInfo);
+ return wordWithInfo.british;
+}
+
diff --git a/quackleio/dictimplementation.h b/quackleio/dictimplementation.h
new file mode 100644
index 0000000..8773f6f
--- /dev/null
+++ b/quackleio/dictimplementation.h
@@ -0,0 +1,49 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef QUACKLE_DICTIMPLEMENTATION_H
+#define QUACKLE_DICTIMPLEMENTATION_H
+
+#include <generator.h>
+
+#include "dict.h"
+
+namespace QuackleIO
+{
+
+class DictImplementation : public Dict::Querier
+{
+public:
+ DictImplementation();
+ virtual ~DictImplementation();
+
+ virtual Dict::WordList query(const QString &query, int flags = None);
+ virtual QString alphagram(const QString &letters) const;
+ virtual bool isBritish(const Quackle::LetterString &word);
+ virtual bool isLoaded() const;
+
+private:
+ Quackle::Generator m_generator;
+};
+
+}
+
+#endif
+
diff --git a/quackleio/flexiblealphabet.cpp b/quackleio/flexiblealphabet.cpp
new file mode 100644
index 0000000..aca6e00
--- /dev/null
+++ b/quackleio/flexiblealphabet.cpp
@@ -0,0 +1,131 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <QtCore>
+
+#include "flexiblealphabet.h"
+#include "util.h"
+
+using namespace QuackleIO;
+
+FlexibleAlphabetParameters::FlexibleAlphabetParameters()
+{
+}
+
+bool FlexibleAlphabetParameters::load(const QString &filename)
+{
+ QFile file(filename);
+
+ if (!file.exists())
+ {
+ UVcout << "alphabet parameters do not exist: " << QuackleIO::Util::qstringToString(filename) << endl;
+ return false;
+ }
+
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+ {
+ UVcout << "Could not open " << QuackleIO::Util::qstringToString(filename) << endl;
+ return false;
+ }
+
+ QTextStream stream(&file);
+ stream.setCodec(QTextCodec::codecForName("UTF-8"));
+
+ QString line;
+ Quackle::Letter letter = QUACKLE_FIRST_LETTER;
+ while (!stream.atEnd())
+ {
+ line = stream.readLine().simplified();
+ QStringList strings = line.split(QRegExp("\\s+"));
+
+ if (line.startsWith("#"))
+ continue;
+
+ if (strings.isEmpty())
+ continue;
+
+ QString text = strings.front();
+ const UVString textUV = QuackleIO::Util::qstringToString(text);
+ strings.pop_front();
+
+ const bool isBlank = text.startsWith("blank", Qt::CaseInsensitive);
+
+ if (isBlank)
+ {
+ if (strings.size() < 2)
+ {
+ UVcerr << "Error reading in alphabet: Blank specification does not specify count and score.";
+ continue;
+ }
+ }
+ else
+ {
+ if (strings.size() < 4)
+ {
+ UVcerr << "Error reading in alphabet: Letter specification does specify blank text, count, score, and vowelness.";
+ continue;
+ }
+ }
+
+ QString blankText;
+ if (!isBlank)
+ {
+ blankText = strings.front();
+ strings.pop_front();
+ }
+
+
+ bool ok = false;
+ int score = strings.takeFirst().toInt(&ok);
+ if (!ok)
+ UVcerr << "Score of letter " << textUV << " is unparsable.";
+
+ int count = strings.takeFirst().toInt(&ok);
+ if (!ok)
+ UVcerr << "Count of letter " << textUV << " is unparsable.";
+
+ bool isVowel = false;
+ if (!isBlank)
+ {
+ isVowel = strings.takeFirst().toInt(&ok);
+ if (!ok)
+ UVcerr << "Vowelness of letter " << textUV << " is unparsable. (Must be 0 or 1.)";
+ }
+
+ if (isBlank)
+ {
+ setCount(QUACKLE_BLANK_MARK, count);
+ setScore(QUACKLE_BLANK_MARK, score);
+ }
+ else
+ {
+ const UVString blankTextUV = QuackleIO::Util::qstringToString(blankText);
+
+ setLetterParameter(letter, Quackle::LetterParameter(letter, textUV, blankTextUV, score, count, isVowel));
+ ++letter;
+
+ //UVcout << "New letter " << textUV << " [" << (int)letter << "]" << endl;
+ }
+ }
+
+ file.close();
+ return true;
+}
+
diff --git a/quackleio/flexiblealphabet.h b/quackleio/flexiblealphabet.h
new file mode 100644
index 0000000..cd4abae
--- /dev/null
+++ b/quackleio/flexiblealphabet.h
@@ -0,0 +1,49 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef QUACKLE_FLEXIBLEALPHABET_H
+#define QUACKLE_FLEXIBLEALPHABET_H
+
+#include "alphabetparameters.h"
+
+class QString;
+
+namespace QuackleIO
+{
+
+class FlexibleAlphabetParameters : public Quackle::AlphabetParameters
+{
+public:
+ FlexibleAlphabetParameters();
+
+ // Loads alphabet in our format.
+ // Lines of file should have format:
+ // <text (utf8)> <blank text (utf8)> <score (int)> <count (int)> <isVowel (0 or 1)>
+ // OR
+ // blank <score (int)> <count (int)>
+ // OR
+ // # some comment
+ bool load(const QString &filename);
+};
+
+}
+
+#endif
+
diff --git a/quackleio/froggetopt.cpp b/quackleio/froggetopt.cpp
new file mode 100644
index 0000000..68f20fe
--- /dev/null
+++ b/quackleio/froggetopt.cpp
@@ -0,0 +1,660 @@
+/**********************************************************************
+ * Copyright (c) 2003, 2004, froglogic Porten & Stadlbauer GbR
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the froglogic nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ **********************************************************************/
+
+#define QT_NO_CAST_ASCII
+#define QT_NO_ASCII_CAST
+
+#include <QtCore>
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "froggetopt.h"
+
+/**
+ \class GetOpt
+
+ \brief A command line option parser.
+
+ This class helps to overcome the repetitive, tedious and
+ error-prone task of parsing the command line options passed to your
+ application by the user. Specify the acceptable syntax with a
+ minimum of statements in a readable way, check it against the
+ actual arguments passed and find the retrieved values in variables
+ of your program. The name \em GetOpt is based on similar utilities
+ build into the Unix shell and other languages.
+
+ A command line that a user might have entered is:
+
+ \code
+ app -v --config=my.cnf -Wall input.dat
+ \endcode
+
+ The typical usage has three stages:
+
+ -# Construct a parser specifying what arguments to parse
+ -# Set up the list of allowed and required options
+ -# Run the parser
+
+ For the first step there are three different constructors that
+ either take arguments directly from \c main(), \c QApplication or a
+ user specified list. Setting up the accepted syntax is done by a
+ set of \c add functions like addSwitch(). The final step of running
+ the parser is simply done by calling parse().
+
+ A short example implementing a \c --verbose switch:
+
+ \code
+ int main(int argc, char **argv)
+ {
+ GetOpt opts(argc, argv);
+ bool verbose;
+ opts.addSwitch("verbose", &verbose);
+ if (!opts.parse())
+ return 1;
+ if (verbose)
+ cout << "VERBOSE mode on" << endl;
+ ...
+ \endcode
+
+ For a better understanding of the function names we'll better
+ define some terms used in the API and its documentation:
+
+ - \em Argument An argument is a plain text token like e.g. a file
+ name one typically passes to an editor when invoking it.
+ - \em Switch A switch is an on/off kind of argument without the need
+ of additional information. Example: \c --debug.
+ - \em Option An option is a normally optional argument with a key-value
+ syntax like \c --output=out.txt or \c -I/usr/include.
+ - \em Short \em Option A short option is a one letter option with a
+ preceding dash. Like \c -v.
+ - \em Long \em Option A long option has a more verbose,
+ multi-letter name like \c --debug.
+ .
+
+ \author froglogic GbR <contact@froglogic.com>
+ */
+
+
+/**
+ Constructs a command line parser from the arguments stored in a
+ previously created QApplication instance.
+
+ Example usage:
+ \code
+ QApplication a(argc, argv);
+
+ GetOpt opt;
+ \endcode
+
+ This constructor is probably the most convenient one to use in a
+ regular Qt application. Note that QApplication may already have
+ removed Qt (or X11) specific arguments. Also see
+ QApplication::argv() and QApplication::argc().
+ */
+GetOpt::GetOpt()
+{
+ if ( !QCoreApplication::instance() )
+ qFatal( "GetOpt: requires a QApplication instance to be constructed first" );
+
+ init( QCoreApplication::instance()->argc(), QCoreApplication::instance()->argv(), 1 );
+}
+
+/**
+ \internal
+ */
+GetOpt::GetOpt( int offset )
+{
+ if ( !QCoreApplication::instance() )
+ qFatal( "GetOpt: requires a QApplication instance to be constructed first" );
+
+ init( QCoreApplication::instance()->argc(), QCoreApplication::instance()->argv(), offset );
+}
+
+/**
+ Construct a command line parser from the array \a argv of string
+ pointers with the size \a argc. Those parameters have the form
+ typically found in the \c main() function. That means that you can
+ simply pass on the arguments specified by the user of your
+ application.
+
+ Example usage:
+
+ \code
+ int main(int argc, char **argv) {
+ GetOpt opt(argc, argv);
+ ...
+ }
+ \endcode
+ */
+GetOpt::GetOpt( int argc, char *argv[] )
+{
+ init( argc, argv );
+}
+
+/**
+ Construct a command line parser from the arguments specified in the
+ list of arguments \a a. This constructor is convenient in those
+ cases where you want to parse a command line assembled on-the-fly
+ instead of relying on the \c argc and \c arg parameters passed to
+ the \c main() function.
+ */
+ GetOpt::GetOpt( const QStringList &a )
+: args( a )
+{
+ init( 0, 0 );
+}
+
+/**
+ \internal
+ */
+void GetOpt::init( int argc, char *argv[], int offset )
+{
+ numReqArgs = numOptArgs = 0;
+ currArg = 1; // appname is not part of the arguments
+ if ( argc ) {
+ // application name
+ aname = QFileInfo( QString::fromUtf8( argv[0] ) ).fileName();
+ // arguments
+ for ( int i = offset; i < argc; ++i )
+ args.append( QString::fromUtf8( argv[i] ) );
+ }
+}
+
+/**
+ \fn bool GetOpt::parse()
+
+ Parse the command line arguments specified in the constructor under
+ the conditions set by the various \c add*() functions. On success,
+ the given variable reference will be initialized with their
+ respective values and true will be returned. Returns false
+ otherwise.
+
+ In the future there'll be a way to retrieve an error message. In
+ the current version the message will be printed to \c stderr.
+ */
+
+/**
+ \internal
+ */
+bool GetOpt::parse( bool untilFirstSwitchOnly )
+{
+ // qDebug( "parse(%s)", args.join( QString( "," ) ).toLocal8Bit().constData() );
+ // push all arguments as we got them on a stack
+ // more pushes might following when parsing condensed arguments
+ // like --key=value.
+ QStack<QString> stack;
+
+ if (!args.empty())
+ {
+ QStringList::const_iterator it = args.end();
+ while ( it != args.begin() ) {
+ --it;
+ stack.push( *it );
+ }
+ }
+
+ const OptionConstIterator obegin = options.begin();
+ const OptionConstIterator oend = options.end();
+ enum { StartState, ExpectingState, OptionalState } state = StartState;
+ Option currOpt;
+ enum TokenType { LongOpt, ShortOpt, Arg, End } t, currType = End;
+ bool extraLoop = true; // we'll do an extra round. fake an End argument
+ while ( !stack.isEmpty() || extraLoop ) {
+ QString a;
+ QString origA;
+ // identify argument type
+ if ( !stack.isEmpty() ) {
+ a = stack.pop();
+ currArg++;
+ origA = a;
+ // qDebug( "popped %s", a.toLocal8Bit().constData() );
+ if ( a.startsWith( QString::fromLatin1( "--" ) ) ) {
+ // recognized long option
+ a = a.mid( 2 );
+ if ( a.isEmpty() ) {
+ qWarning( "'--' feature not supported, yet" );
+ exit( 2 );
+ }
+ t = LongOpt;
+ // split key=value style arguments
+ int equal = a.indexOf( '=' );
+ if ( equal >= 0 ) {
+ stack.push( a.mid( equal + 1 ) );
+ currArg--;
+ a = a.left( equal );
+ }
+ } else if ( a.length() == 1 ) {
+ t = Arg;
+ } else if ( a[0] == '-' ) {
+#if 0 // compat mode for -long style options
+ if ( a.length() == 2 ) {
+ t = ShortOpt;
+ a = a[1];
+ } else {
+ a = a.mid( 1 );
+ t = LongOpt;
+ // split key=value style arguments
+ int equal = a.find( '=' );
+ if ( equal >= 0 ) {
+ stack.push( a.mid( equal + 1 ) );
+ currArg--;
+ a = a.left( equal );
+ }
+ }
+#else
+ // short option
+ t = ShortOpt;
+ // followed by an argument ? push it for later processing.
+ if ( a.length() > 2 ) {
+ stack.push( a.mid( 2 ) );
+ currArg--;
+ }
+ a = a[1];
+#endif
+ } else {
+ t = Arg;
+ }
+ } else {
+ // faked closing argument
+ t = End;
+ }
+ // look up among known list of options
+ Option opt;
+ if ( t != End ) {
+ OptionConstIterator oit = obegin;
+ while ( oit != oend ) {
+ const Option &o = *oit;
+ if ( ( t == LongOpt && a == o.lname ) || // ### check state
+ ( t == ShortOpt && a[0].unicode() == o.sname ) ) {
+ opt = o;
+ break;
+ }
+ ++oit;
+ }
+ if ( t == LongOpt && opt.type == OUnknown ) {
+ if ( currOpt.type != OVarLen ) {
+ qWarning( "Unknown option --%s", a.toLocal8Bit().constData() );
+ return false;
+ } else {
+ // VarLength options support arguments starting with '-'
+ t = Arg;
+ }
+ } else if ( t == ShortOpt && opt.type == OUnknown ) {
+ if ( currOpt.type != OVarLen ) {
+ qWarning( "Unknown option -%c", a[0].unicode() );
+ return false;
+ } else {
+ // VarLength options support arguments starting with '-'
+ t = Arg;
+ }
+ }
+
+ } else {
+ opt = Option( OEnd );
+ }
+
+ // interpret result
+ switch ( state ) {
+ case StartState:
+ if ( opt.type == OSwitch ) {
+ setSwitch( opt );
+ setOptions.insert( opt.lname, 1 );
+ setOptions.insert( QString( QChar( opt.sname ) ), 1 );
+ } else if ( opt.type == OArg1 || opt.type == ORepeat ) {
+ state = ExpectingState;
+ currOpt = opt;
+ currType = t;
+ setOptions.insert( opt.lname, 1 );
+ setOptions.insert( QString( QChar( opt.sname ) ), 1 );
+ } else if ( opt.type == OOpt || opt.type == OVarLen ) {
+ state = OptionalState;
+ currOpt = opt;
+ currType = t;
+ setOptions.insert( opt.lname, 1 );
+ setOptions.insert( QString( QChar( opt.sname ) ), 1 );
+ } else if ( opt.type == OEnd ) {
+ // we're done
+ } else if ( opt.type == OUnknown && t == Arg ) {
+ if ( numReqArgs > 0 ) {
+ if ( reqArg.stringValue->isNull() ) { // ###
+ *reqArg.stringValue = a;
+ } else {
+ qWarning( "Too many arguments" );
+ return false;
+ }
+ } else if ( numOptArgs > 0 ) {
+ if ( optArg.stringValue->isNull() ) { // ###
+ *optArg.stringValue = a;
+ } else {
+ qWarning( "Too many arguments" );
+ return false;
+ }
+ }
+ } else {
+ qFatal( "unhandled StartState case %d", opt.type );
+ }
+ break;
+ case ExpectingState:
+ if ( t == Arg ) {
+ if ( currOpt.type == OArg1 ) {
+ *currOpt.stringValue = a;
+ state = StartState;
+ } else if ( currOpt.type == ORepeat ) {
+ currOpt.listValue->append( a );
+ state = StartState;
+ } else {
+ abort();
+ }
+ } else {
+ QString n = currType == LongOpt ?
+ currOpt.lname : QString( QChar( currOpt.sname ) );
+ qWarning( "Expected an argument after '%s' option", n.toLocal8Bit().constData() );
+ return false;
+ }
+ break;
+ case OptionalState:
+ if ( t == Arg ) {
+ if ( currOpt.type == OOpt ) {
+ *currOpt.stringValue = a;
+ state = StartState;
+ } else if ( currOpt.type == OVarLen ) {
+ currOpt.listValue->append( origA );
+ // remain in this state
+ } else {
+ abort();
+ }
+ } else {
+ // optional argument not specified
+ if ( currOpt.type == OOpt )
+ *currOpt.stringValue = currOpt.def;
+ if ( t != End ) {
+ // re-evaluate current argument
+ stack.push( origA );
+ currArg--;
+ }
+ state = StartState;
+ }
+ break;
+ }
+
+ if ( untilFirstSwitchOnly && opt.type == OSwitch )
+ return true;
+
+ // are we in the extra loop ? if so, flag the final end
+ if ( t == End )
+ extraLoop = false;
+ }
+
+ if ( numReqArgs > 0 && reqArg.stringValue->isNull() ) {
+ qWarning( "Lacking required argument" );
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ \internal
+ */
+void GetOpt::addOption( Option o )
+{
+ // ### check for conflicts
+ options.append( o );
+}
+
+/**
+ Adds a switch with the long name \a lname. If the switch is found
+ during parsing the bool \a *b will bet set to true. Otherwise the
+ bool will be initialized to false.
+
+Example:
+
+\code
+GetOpt opt;
+bool verbose;
+opt.addSwitch("verbose", &verbose);
+\endcode
+
+The boolean flag \c verbose will be set to true if \c --verbose has
+been specified in the command line; false otherwise.
+ */
+void GetOpt::addSwitch( const QString &lname, bool *b )
+{
+ Option opt( OSwitch, 0, lname );
+ opt.boolValue = b;
+ addOption( opt );
+ // ### could do all inits at the beginning of parse()
+ *b = false;
+}
+
+/**
+ \internal
+ */
+void GetOpt::setSwitch( const Option &o )
+{
+ assert( o.type == OSwitch );
+ *o.boolValue = true;
+}
+
+/**
+ Registers an option with the short name \a s and long name \a l to
+ the parser. If this option is found during parsing the value will
+ be stored in the string pointed to by \a v. By default \a *v will
+ be initialized to \c QString::null.
+ */
+void GetOpt::addOption( char s, const QString &l, QString *v )
+{
+ Option opt( OArg1, s, l );
+ opt.stringValue = v;
+ addOption( opt );
+ *v = QString::null;
+}
+
+/**
+ Registers a long option \a l that can have a variable number of
+ corresponding value parameters. As there currently is no way to
+ tell the end of the value list the only sensible use of this option
+ is at the end of the command line.
+
+Example:
+
+\code
+QStringList args;
+opt.addVarLengthOption("exec", &args);
+\endcode
+
+Above code will lead to "-f" and "test.txt" being stored in \a args
+upon
+
+\code
+myapp --exec otherapp -f test.txt
+\endcode
+ */
+void GetOpt::addVarLengthOption( const QString &l, QStringList *v )
+{
+ Option opt( OVarLen, 0, l );
+ opt.listValue = v;
+ addOption( opt );
+ *v = QStringList();
+}
+
+/**
+ Registers an option with the short name \a s that can be specified
+ repeatedly in the command line. The option values will be stored in
+ the list pointed to by \a v. If no \a s option is found \a *v will
+ remain at its default value of an empty QStringList instance.
+
+Example:
+
+To parse the \c -I options in a command line like
+\code
+myapp -I/usr/include -I/usr/local/include
+\endcode
+
+you can use code like this:
+
+\code
+GetOpt opt;
+QStringList includes;
+opt.addRepeatableOption('I', &includes);
+opt.parse();
+\endcode
+ */
+void GetOpt::addRepeatableOption( char s, QStringList *v )
+{
+ Option opt( ORepeat, s, QString::null );
+ opt.listValue = v;
+ addOption( opt );
+ *v = QStringList();
+}
+
+/**
+ Registers an option with the long name \a l that can be specified
+ repeatedly in the command line.
+
+ \sa addRepeatableOption( char, QStringList* )
+ */
+void GetOpt::addRepeatableOption( const QString &l, QStringList *v )
+{
+ Option opt( ORepeat, 0, l );
+ opt.listValue = v;
+ addOption( opt );
+ *v = QStringList();
+}
+
+/**
+ Adds a long option \a l that has an optional value parameter. If
+ the value is not specified by the user it will be set to \a def.
+
+Example:
+
+\code
+GetOpt opt;
+QString file;
+opt.addOptionalOption("dump", &file, "<stdout>");
+\endcode
+
+\sa addOption
+ */
+void GetOpt::addOptionalOption( const QString &l, QString *v,
+ const QString &def )
+{
+ addOptionalOption( 0, l, v, def );
+}
+
+/**
+ Adds a short option \a s that has an optional value parameter. If
+ the value is not specified by the user it will be set to \a def.
+ */
+void GetOpt::addOptionalOption( char s, const QString &l,
+ QString *v, const QString &def )
+{
+ Option opt( OOpt, s, l );
+ opt.stringValue = v;
+ opt.def = def;
+ addOption( opt );
+ *v = QString::null;
+}
+
+/**
+ Registers a required command line argument \a name. If the argument
+ is missing parse() will return false to indicate an error and \a *v
+ will remain with its default QString::null value. Otherwise \a *v
+ will be set to the value of the argument.
+
+Example:
+
+To accept simple arguments like
+
+\code
+myeditor letter.txt
+\endcode
+
+use a call like:
+
+\code
+QString &file;
+opt.addArgument("file", &file);
+\endcode
+
+Note: the \a name parameter has a rather descriptive meaning for
+now. It might be used for generating a usage or error message in
+the future. Right now, the only current use is in relation with the
+isSet() function.
+ */
+void GetOpt::addArgument( const QString &name, QString *v )
+{
+ Option opt( OUnknown, 0, name );
+ opt.stringValue = v;
+ reqArg = opt;
+ ++numReqArgs;
+ *v = QString::null;
+}
+
+/**
+ Registers an optional command line argument \a name. For a more
+ detailed description see the addArgument() documentation.
+
+ */
+void GetOpt::addOptionalArgument( const QString &name, QString *v )
+{
+ Option opt( OUnknown, 0, name );
+ opt.stringValue = v;
+ optArg = opt;
+ ++numOptArgs;
+ *v = QString::null;
+}
+
+/**
+ Returns true if the (long) option or switch \a name has been found
+ in the command line; returns false otherwise. Leading hyphens are
+ not part of the name.
+
+ As the set/not set decision can also be made depending on the value
+ of the variable reference used in the respective \c add*() call
+ there's generally little use for this function.
+ */
+
+bool GetOpt::isSet( const QString &name ) const
+{
+ return setOptions.find( name ) != setOptions.end();
+}
+
+/**
+ \fn int GetOpt::currentArgument() const
+ \internal
+ */
diff --git a/quackleio/froggetopt.h b/quackleio/froggetopt.h
new file mode 100644
index 0000000..7376dd4
--- /dev/null
+++ b/quackleio/froggetopt.h
@@ -0,0 +1,121 @@
+/**********************************************************************
+ * Copyright (c) 2003, 2004, froglogic Porten & Stadlbauer GbR
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the froglogic nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ **********************************************************************/
+
+#ifndef FROGGETOPT_H
+#define FROGGETOPT_H
+
+#include <QStringList>
+#include <QMap>
+
+class GetOpt {
+public:
+ GetOpt();
+ GetOpt( int offset );
+ GetOpt( int argc, char *argv[] );
+ GetOpt( const QStringList &a );
+
+ QString appName() const { return aname; }
+
+ // switch (no arguments)
+ void addSwitch( const QString &lname, bool *b );
+
+ // options (with arguments, sometimes optional)
+ void addOption( char s, const QString &l, QString *v );
+ void addVarLengthOption( const QString &l, QStringList *v );
+ void addRepeatableOption( char s, QStringList *v );
+ void addRepeatableOption( const QString &l, QStringList *v );
+ void addOptionalOption( const QString &l, QString *v,
+ const QString &def );
+ void addOptionalOption( char s, const QString &l,
+ QString *v, const QString &def );
+
+ // bare arguments
+ void addArgument( const QString &name, QString *v );
+ void addOptionalArgument( const QString &name, QString *v );
+
+ bool parse( bool untilFirstSwitchOnly );
+ bool parse() { return parse( false ); }
+
+ bool isSet( const QString &name ) const;
+
+ int currentArgument() const { return currArg; }
+
+private:
+ enum OptionType { OUnknown, OEnd, OSwitch, OArg1, OOpt, ORepeat, OVarLen };
+
+ struct Option;
+ friend struct Option;
+
+ struct Option {
+ Option( OptionType t = OUnknown,
+ char s = 0, const QString &l = QString::null )
+ : type( t ),
+ sname( s ),
+ lname( l ),
+ boolValue( 0 ) { }
+
+ OptionType type;
+ char sname; // short option name (0 if none)
+ QString lname; // long option name (null if none)
+ union {
+ bool *boolValue;
+ QString *stringValue;
+ QStringList *listValue;
+ };
+ QString def;
+ };
+
+ QList<Option> options;
+ typedef QList<Option>::const_iterator OptionConstIterator;
+ QMap<QString, int> setOptions;
+
+ void init( int argc, char *argv[], int offset = 1 );
+ void addOption( Option o );
+ void setSwitch( const Option &o );
+
+ QStringList args;
+ QString aname;
+
+ int numReqArgs;
+ int numOptArgs;
+ Option reqArg;
+ Option optArg;
+
+ int currArg;
+};
+
+#endif
+
diff --git a/quackleio/gcgio.cpp b/quackleio/gcgio.cpp
new file mode 100644
index 0000000..7c06e3b
--- /dev/null
+++ b/quackleio/gcgio.cpp
@@ -0,0 +1,377 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <QtCore>
+
+#include <datamanager.h>
+
+#include "game.h"
+#include "gcgio.h"
+#include "util.h"
+
+using namespace QuackleIO;
+
+GCGIO::GCGIO()
+{
+}
+
+Quackle::Game *GCGIO::read(QTextStream &stream, int flags)
+{
+ Quackle::Game *ret = new Quackle::Game;
+ Quackle::PlayerList players;
+
+ Quackle::Rack incompleteRack;
+ bool hasIncompleteRack = false;;
+
+ const bool canMaintainCrosses = flags & Logania::MaintainBoardPreparation;
+
+ bool gameStarted = false;
+
+ QString line;
+ while (!stream.atEnd())
+ {
+ line = stream.readLine();
+ QStringList strings = line.split(QRegExp("\\s+"), QString::SkipEmptyParts);
+
+ if (line.startsWith("#"))
+ {
+ if (line.startsWith("#player"))
+ {
+ QString firstChunk = strings.front();
+ int id = firstChunk.right(1).toInt();
+
+ strings.pop_front();
+
+ if (strings.isEmpty())
+ {
+ UVcerr << "GCG error reading " << Util::qstringToString(line) << ": no player abbreviation in #player" << endl;
+ return ret;
+ }
+
+ QString abbreviation = strings.front();
+ strings.pop_front();
+
+ if (strings.isEmpty())
+ {
+ UVcerr << "GCG error reading " << Util::qstringToString(line) << ": no player name in #player" << endl;
+ return ret;
+ }
+
+ QString name = strings.join(" ");
+
+ Quackle::Player newPlayer(Util::qstringToString(name), Quackle::Player::HumanPlayerType);
+ newPlayer.setId(id);
+ newPlayer.setAbbreviatedName(Util::qstringToString(abbreviation));
+ players.push_back(newPlayer);
+ }
+ else if (line.startsWith("#title"))
+ ret->setTitle(Util::qstringToString(line.right(line.length() - 7)));
+ else if (line.startsWith("#description"))
+ ret->setDescription(Util::qstringToString(line.right(line.length() - 13)));
+ else if (line.startsWith("#note") && ret->hasPositions())
+ ret->currentPosition().setExplanatoryNote(Util::qstringToString(line.right(line.length() - 6)));
+ else if (line.startsWith("#rack") && ret->hasPositions())
+ {
+ QString firstChunk = strings.front();
+ int id = firstChunk.right(1).toInt();
+
+ strings.pop_front();
+
+ if (strings.isEmpty())
+ {
+ UVcerr << "GCG error reading " << Util::qstringToString(line) << ": no rack in #rack" << endl;
+ return ret;
+ }
+
+ const QString rackString = strings.front();
+ const Quackle::Rack rack(Util::encode(rackString));
+
+ ret->currentPosition().setPlayerRack(/* zero index */ id - 1, rack);
+ }
+ else if (line.startsWith("#incomplete"))
+ {
+ strings.pop_front();
+
+ const QString rackString = strings.isEmpty()? QString() : strings.front();
+ incompleteRack = Util::encode(rackString);
+ hasIncompleteRack = true;
+ }
+ }
+ else if (line.startsWith(">"))
+ {
+ if (!gameStarted)
+ {
+ ret->setPlayers(players);
+ gameStarted = true;
+ }
+
+ strings.pop_front();
+
+ if (strings.isEmpty())
+ {
+ UVcerr << "GCG error reading " << Util::qstringToString(line) << ": incomplete move" << endl;
+ return ret;
+ }
+
+ const QString rackString = strings.front();
+ strings.pop_front();
+
+ // end of game unused tiles bonus
+ if (rackString.startsWith("(") && rackString.endsWith(")"))
+ {
+ // end the game
+ if (ret->hasPositions())
+ ret->commitCandidate(canMaintainCrosses);
+ else
+ ret->addPosition();
+ continue;
+ }
+
+ if (strings.isEmpty())
+ {
+ UVcerr << "GCG error reading " << Util::qstringToString(line) << ": incomplete move" << endl;
+ return ret;
+ }
+
+ const Quackle::Rack rack(Util::encode(rackString));
+
+ Quackle::Move move = Quackle::Move::createNonmove();
+
+ const QString firstMoveBite = strings.front();
+ if (firstMoveBite.startsWith("--"))
+ {
+ Quackle::Move lastMoveMade = ret->currentPosition().moveMade();
+ lastMoveMade.setIsChallengedPhoney(true);
+ ret->currentPosition().setMoveMade(lastMoveMade);
+ }
+ else if (firstMoveBite.startsWith("-"))
+ {
+ const QString exchangedLetters = firstMoveBite.right(firstMoveBite.length() - 1);
+ if (exchangedLetters.isEmpty())
+ move = Quackle::Move::createPassMove();
+ else
+ move = Quackle::Move::createExchangeMove(Util::encode(exchangedLetters));
+ }
+ else if (firstMoveBite.startsWith("(time)"))
+ {
+ strings.pop_front();
+
+ if (strings.isEmpty())
+ {
+ UVcerr << "GCG error reading " << Util::qstringToString(line) << ": incomplete move" << endl;
+ return ret;
+ }
+ }
+ else if (firstMoveBite.startsWith("(challenge)"))
+ {
+ strings.pop_front();
+
+ if (strings.isEmpty())
+ {
+ UVcerr << "GCG error reading " << Util::qstringToString(line) << ": incomplete move" << endl;
+ return ret;
+ }
+
+ Quackle::Move move = ret->currentPosition().moveMade();
+ move.setScoreAddition(readSignedInt(strings.front()));
+ ret->currentPosition().setMoveMade(move);
+ }
+ else
+ {
+ const QString positionString = firstMoveBite;
+
+ strings.pop_front();
+
+ if (strings.isEmpty())
+ {
+ UVcerr << "GCG error reading " << Util::qstringToString(line) << ": incomplete move" << endl;
+ return ret;
+ }
+
+ const QString placeTiles = strings.front();
+ strings.pop_front();
+
+ // if score is negative, it is rescored later to the proper score
+ int score = -1;
+
+ if (!strings.isEmpty())
+ score = readSignedInt(strings.front());;
+
+ move = Quackle::Move::createPlaceMove(Util::qstringToString(positionString), Util::encode(placeTiles));
+ move.score = score;
+ }
+
+ if (move.isAMove())
+ {
+ if (ret->hasPositions())
+ ret->commitCandidate(canMaintainCrosses);
+ else
+ ret->addPosition();
+
+ ret->currentPosition().setCurrentPlayerRack(rack);
+ ret->currentPosition().ensureMovePrettiness(move);
+ ret->currentPosition().ensureMoveTilesDoNotIncludePlayThru(move);
+
+ int correctScore = ret->currentPosition().calculateScore(move);
+ if (move.score < 0)
+ {
+ move.score = correctScore;
+ }
+ else
+ {
+ if (correctScore != move.score)
+ {
+ move.setScoreAddition(move.score - correctScore);
+ move.score = correctScore;
+ }
+ }
+
+ ret->currentPosition().setMoveMade(move);
+ }
+ }
+ }
+
+ if (!gameStarted || !ret->currentPosition().gameOver())
+ {
+ if (ret->hasPositions())
+ ret->commitCandidate(canMaintainCrosses);
+ else
+ ret->addPosition();
+
+ if (hasIncompleteRack)
+ {
+ ret->currentPosition().setCurrentPlayerRack(incompleteRack);
+ }
+ }
+
+ return ret;
+}
+
+int GCGIO::readSignedInt(const QString &intString) const
+{
+ QString bonus = intString;
+ int sign = 1;
+
+ if (bonus.startsWith("+"))
+ {
+ bonus = bonus.right(bonus.length() - 1);
+ }
+ else if (bonus.startsWith("-"))
+ {
+ sign = -1;
+ bonus = bonus.right(bonus.length() - 1);
+ }
+
+ return sign * bonus.toInt();
+}
+
+bool GCGIO::canRead(QTextStream &stream) const
+{
+ QString firstChunk;
+ stream >> firstChunk;
+ if (firstChunk.startsWith("#"))
+ return true;
+
+ return false;
+}
+
+void GCGIO::write(const Quackle::Game &game, QTextStream &stream)
+{
+ Quackle::PlayerList players = game.players();
+ for (Quackle::PlayerList::iterator it = players.begin(); it != players.end(); ++it)
+ {
+ stream << "#player" << (*it).id() + 1 << " " << Util::uvStringToQString((*it).abbreviatedName()) << " " << Util::uvStringToQString((*it).name()) << endl;
+ }
+
+ if (!game.title().empty())
+ stream << "#title " << Util::uvStringToQString(game.title()) << endl;
+
+ if (!game.description().empty())
+ stream << "#description " << Util::uvStringToQString(game.description()) << endl;
+
+ const Quackle::PositionList::const_iterator end(game.history().end());
+ for (Quackle::PositionList::const_iterator it = game.history().begin(); it != end; ++it)
+ {
+ Quackle::Move move = (*it).committedMove();
+ move.setPrettyTiles((*it).board().prettyTilesOfMove(move, /* don't mark playthru */ false));
+
+ if (move.isAMove())
+ {
+ int outputScore = move.score;
+ int outputScoreAddition = move.scoreAddition();
+
+ // special case != 5 score additions;
+ // GCG has no way to specify them, so we roll the score addition
+ // into the regular score silently
+ if (outputScoreAddition != 5)
+ {
+ outputScore = move.score + move.scoreAddition();
+ outputScoreAddition = 0;
+ }
+
+ stream << ">" << Util::uvStringToQString((*it).currentPlayer().abbreviatedName()) << ": " << Util::letterStringToQString((*it).currentPlayer().rack().alphaTiles()) << " " << Util::uvStringToQString(move.toString()) << " +" << outputScore << " " << outputScore + (*it).currentPlayer().score() << endl;
+
+ if (move.isChallengedPhoney())
+ {
+ stream << ">" << Util::uvStringToQString((*it).currentPlayer().abbreviatedName()) << ": " << Util::letterStringToQString((*it).currentPlayer().rack().alphaTiles()) << " -- -" << outputScore << " " << move.effectiveScore() + (*it).currentPlayer().score() << endl;
+ }
+
+ if (outputScoreAddition != 0)
+ {
+ QString nextRack = "UNKNOWN";
+ bool foundOne = false;
+ for (Quackle::PositionList::const_iterator secondIterator = it; secondIterator != end; ++secondIterator)
+ {
+ if ((*secondIterator).currentPlayer().id() == (*it).currentPlayer().id())
+ {
+ if (foundOne)
+ {
+ nextRack = Util::letterStringToQString((*secondIterator).currentPlayer().rack().alphaTiles());
+ break;
+ }
+ else
+ {
+ foundOne = true;
+ continue;
+ }
+ }
+ }
+
+ stream << ">" << Util::uvStringToQString((*it).currentPlayer().abbreviatedName()) << ": " << nextRack << " (challenge) " << ((outputScoreAddition > 0)? "+" : "") << outputScoreAddition << " " << (outputScoreAddition + outputScore + (*it).currentPlayer().score()) << endl;
+ }
+ }
+
+ if (!(*it).explanatoryNote().empty())
+ stream << "#note " << Util::uvStringToQString((*it).explanatoryNote()) << endl;
+ }
+
+ const Quackle::GamePosition &lastPosition = game.history().lastPosition();
+
+ if (!lastPosition.gameOver())
+ {
+ stream << "#rack" << lastPosition.currentPlayer().id() + 1 << " " << Util::letterStringToQString(lastPosition.currentPlayer().rack().alphaTiles()) << endl;
+ }
+}
+
+QString GCGIO::filter() const
+{
+ return QString("*.gcg");
+}
+
diff --git a/quackleio/gcgio.h b/quackleio/gcgio.h
new file mode 100644
index 0000000..67405ab
--- /dev/null
+++ b/quackleio/gcgio.h
@@ -0,0 +1,47 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef QUACKLE_GCGIO_H
+#define QUACKLE_GCGIO_H
+
+#include "logania.h"
+
+namespace QuackleIO
+{
+
+class GCGIO : public Logania
+{
+public:
+ GCGIO();
+ ~GCGIO() {};
+
+ virtual Quackle::Game *read(QTextStream &stream, int flags);
+ virtual bool canRead(QTextStream &stream) const;
+ virtual void write(const Quackle::Game &game, QTextStream &stream);
+ virtual QString filter() const;
+
+private:
+ int readSignedInt(const QString &intString) const;
+};
+
+}
+
+#endif
+
diff --git a/quackleio/iotest/.gitignore b/quackleio/iotest/.gitignore
new file mode 100644
index 0000000..f878785
--- /dev/null
+++ b/quackleio/iotest/.gitignore
@@ -0,0 +1,6 @@
+Makefile
+obj
+Makefile.Debug
+Makefile.Release
+debug
+release
diff --git a/quackleio/iotest/capp.gcg b/quackleio/iotest/capp.gcg
new file mode 100644
index 0000000..7c1a05c
--- /dev/null
+++ b/quackleio/iotest/capp.gcg
@@ -0,0 +1,34 @@
+#player1 Brian Brian Cappelletto
+#player2 Pakorn Pakorn Nemitrmansuk
+#title WSC 2001 Round 20: Brian Cappelletto vs. Pakorn Nemitrmansuk
+#description WSC 2001 Round 20: Brian Cappelletto vs. Pakorn Nemitrmansuk at Table 1
+#style wsc2001
+#incomplete
+>Brian: CNNTU?? 8b NoCTUrN +70 70
+>Pakorn: AFFIABE e8 TAFFIA +24 24
+>Brian: EEETVVY 12d VIVE +20 90
+>Pakorn: BEWWLYB 11g WEBBY +35 59
+>Brian: AEEETTY f8 UEY +32 122
+>Pakorn: LWGRAKE h10 WERGEL +45 104
+>Pakorn: LWGRAKE -- +0 59
+>Brian: AAEERTT b7 ANTEATER +70 192
+>Pakorn: LWGRAKE 7a KAW +22 81
+>Brian: NOPUUUX 13g XU +38 230
+>Pakorn: LEGGARI h2 REGALING +62 143
+>Brian: NOOPRRU a12 UPON +30 260
+>Pakorn: PHOLASR c13 HAP +35 178
+>Brian: EEMORSU 4h GRUESOME +74 334
+>Brian: ACDEJOQ (challenge) +5 339
+>Pakorn: DILTORS j1 DILUTORS +63 241
+>Brian: ACDEJOQ o1 JADE +36 375
+>Pakorn: ZSIDTLO m3 ZOOID +34 275
+>Brian: DEECOOQ n2 DEMO +35 410
+>Pakorn: NIRISTL 14h NITRILS +70 345
+>Brian: ACEHOOQ g1 OOH +21 431
+>Pakorn: SMORING 6m ISM +17 362
+>Brian: AACEENQ o6 MAC +21 452
+>Pakorn: LIGROIN h13 UNI +9 371
+>Brian: AEEINQT n11 QATS +13 465
+>Pakorn: LIGRONE o10 LIG +22 393
+>Brian: EEIN l7 EINE +8 473
+>Brian: (ENOR) +8 481
diff --git a/quackleio/iotest/iotest.cpp b/quackleio/iotest/iotest.cpp
new file mode 100644
index 0000000..87d167d
--- /dev/null
+++ b/quackleio/iotest/iotest.cpp
@@ -0,0 +1,78 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <QtCore>
+
+#include "datamanager.h"
+#include "game.h"
+#include "gcgio.h"
+#include "trademarkedboards.h"
+
+void testGCGIO();
+
+int main()
+{
+ Quackle::DataManager dataManager;
+ dataManager.setBoardParameters(new ScrabbleBoard());
+
+ testGCGIO();
+ return 0;
+}
+
+void testGCGIO()
+{
+ QuackleIO::GCGIO io;
+ QFile file("capp.gcg");
+
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+ {
+ cerr << "Could not open gcg" << endl;
+ return;
+ }
+
+ QTextStream in(&file);
+
+ Quackle::Game *game = io.read(in, QuackleIO::Logania::BasicLoad);
+ UVcout << game->history() << endl;
+
+ UVcout << "Final scores: " << endl;
+ Quackle::PlayerList players = game->currentPosition().endgameAdjustedScores();
+ const Quackle::PlayerList::const_iterator end(players.end());
+ for (Quackle::PlayerList::const_iterator it = players.begin(); it != end; ++it)
+ UVcout << *it << endl;
+
+ file.close();
+
+ QFile outFile("my-capp.gcg");
+
+ if (!outFile.open(QIODevice::WriteOnly | QIODevice::Text))
+ {
+ cerr << "Could not open gcg output file" << endl;
+ return;
+ }
+
+ QTextStream out(&outFile);
+ io.write(*game, out);
+
+ outFile.close();
+
+ delete game;
+}
+
diff --git a/quackleio/iotest/iotest.pro b/quackleio/iotest/iotest.pro
new file mode 100644
index 0000000..8550691
--- /dev/null
+++ b/quackleio/iotest/iotest.pro
@@ -0,0 +1,29 @@
+TEMPLATE = app
+DEPENDPATH += .
+INCLUDEPATH += . .. ../..
+
+# enable/disable debug symbols
+#CONFIG += debug
+
+debug {
+ OBJECTS_DIR = obj/debug
+ win32 { LIBS += -L../debug -L../../debug }
+}
+
+release {
+ OBJECTS_DIR = obj/release
+ win32 { LIBS += -L../release -L../../release }
+}
+
+LIBS += -L.. -L../.. -lquackle -lquackleio
+
+# Input
+HEADERS += trademarkedboards.h
+SOURCES += iotest.cpp trademarkedboards.cpp
+
+win32:!win32-g++ {
+ QMAKE_CFLAGS_DEBUG ~= s/-MDd/-MTd/
+ QMAKE_CXXFLAGS_DEBUG ~= s/-MDd/-MTd/
+ QMAKE_CFLAGS_RELEASE ~= s/-MD/-MT/
+ QMAKE_CXXFLAGS_RELEASE ~= s/-MD/-MT/
+}
diff --git a/quackleio/iotest/trademarkedboards.cpp b/quackleio/iotest/trademarkedboards.cpp
new file mode 100644
index 0000000..b9eb37c
--- /dev/null
+++ b/quackleio/iotest/trademarkedboards.cpp
@@ -0,0 +1,148 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include "trademarkedboards.h"
+
+ScrabbleBoard::ScrabbleBoard()
+{
+ m_name = MARK_UV("Scrabble Board");
+
+ const int letterm[15][15] =
+ {
+ // A B C D E F G H I J K L M N O
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1},
+ {1, 1, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1},
+ {2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1},
+ {1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1},
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1},
+ {1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1},
+ {1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2},
+ {1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 1, 1},
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1}
+ };
+
+ const int wordm[15][15] =
+ {
+ // A B C D E F G H I J K L M N O
+ {3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3},
+ {1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1},
+ {1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1},
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1},
+ {1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1},
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1},
+ {1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1},
+ {1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1},
+ {3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3}
+ };
+
+ for (int i = 0; i < 15; ++i)
+ {
+ for (int j = 0; j < 15; ++j)
+ {
+ m_letterMultipliers[i][j] = letterm[i][j];
+ m_wordMultipliers[i][j] = wordm[i][j];
+ }
+ }
+}
+
+//////
+
+SuperScrabbleBoard::SuperScrabbleBoard()
+{
+ m_height = 21;
+ m_width = 21;
+
+ m_startRow = 10;
+ m_startColumn = 10;
+
+ m_name = MARK_UV("Super Scrabble Board");
+
+ const int letterm[21][21] =
+ {
+ // A B C D E F G H I J K L M N O P Q R S T U
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1},
+ {1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1},
+ {2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2},
+ {1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1},
+ {1, 1, 4, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 4, 1, 1},
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1},
+ {2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2},
+ {1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1},
+ {1, 1, 4, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 4, 1, 1},
+ {1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1},
+ {2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2},
+ {1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1},
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1}
+ };
+ const int wordm[21][21] =
+ {
+ // A B C D E F G H I J K L M N O P Q R S T U
+ {4, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 4},
+ {1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1},
+ {1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1},
+ {1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1},
+ {1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1},
+ {3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3},
+ {1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1},
+ {1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1},
+ {1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1},
+ {1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1},
+ {1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1},
+ {3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3},
+ {1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1},
+ {1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1},
+ {1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1},
+ {1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1},
+ {4, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 4},
+ };
+
+ for (int i = 0; i < 21; ++i)
+ {
+ for (int j = 0; j < 21; ++j)
+ {
+ m_letterMultipliers[i][j] = letterm[i][j];
+ m_wordMultipliers[i][j] = wordm[i][j];
+ }
+ }
+}
diff --git a/quackleio/iotest/trademarkedboards.h b/quackleio/iotest/trademarkedboards.h
new file mode 100644
index 0000000..f596c8f
--- /dev/null
+++ b/quackleio/iotest/trademarkedboards.h
@@ -0,0 +1,40 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef QUACKLE_TRADEMARKEDBOARDS_H
+#define QUACKLE_TRADEMARKEDBOARDS_H
+
+#include "boardparameters.h"
+
+// Name: Scrabble Board
+class ScrabbleBoard : public Quackle::BoardParameters
+{
+public:
+ ScrabbleBoard();
+};
+
+// Name: Super Scrabble Board
+class SuperScrabbleBoard : public Quackle::BoardParameters
+{
+public:
+ SuperScrabbleBoard();
+};
+
+#endif
diff --git a/quackleio/logania.h b/quackleio/logania.h
new file mode 100644
index 0000000..8273603
--- /dev/null
+++ b/quackleio/logania.h
@@ -0,0 +1,61 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef QUACKLE_LOGANIA_H
+#define QUACKLE_LOGANIA_H
+
+#include <QString>
+
+class QTextStream;
+
+namespace Quackle
+{
+ class Game;
+}
+
+namespace QuackleIO
+{
+
+// Abstract interfaces for game log input/output
+
+class Logania
+{
+public:
+ virtual ~Logania() {};
+
+ // if MaintainBoardPreparation is not set, boards will not be prepared
+ // for analysis and you'll have to do this manually. If you set this flag
+ // DataManager and a generator need to be set up.
+ enum ReadFlags { BasicLoad = 0x0000, MaintainBoardPreparation = 0x0001 };
+
+ // allocates a new Game, fills it up, and returns it.
+ // Returned game is either 0, or a game with at least one position.
+ // Boards of game are ready for analysis if there is a DataManager set
+ // up; otherwise they won't have their crosses prepared
+ virtual Quackle::Game *read(QTextStream &stream, int flags) = 0;
+
+ virtual bool canRead(QTextStream &stream) const = 0;
+ virtual void write(const Quackle::Game &game, QTextStream &stream) = 0;
+ virtual QString filter() const = 0;
+};
+
+}
+
+#endif
diff --git a/quackleio/quackleio.pro b/quackleio/quackleio.pro
new file mode 100644
index 0000000..e883fb6
--- /dev/null
+++ b/quackleio/quackleio.pro
@@ -0,0 +1,34 @@
+TEMPLATE = lib
+INCLUDEPATH += . ..
+DEPENDPATH += . ..
+VERSION = 0.9
+QT -= gui
+debug {
+ OBJECTS_DIR = obj/debug
+ win32 { LIBS += -L../debug }
+}
+
+release {
+ OBJECTS_DIR = obj/release
+ win32 { LIBS += -L../release }
+}
+
+MOC_DIR = moc
+
+# enable/disable debug symbols
+#CONFIG += debug staticlib
+CONFIG += release staticlib
+CONFIG -= x11
+
+LIBS += -L.. -lquackle
+
+# Input
+HEADERS += gcgio.h logania.h queenie.h streamingreporter.h flexiblealphabet.h util.h froggetopt.h dict.h dictfactory.h dictimplementation.h
+SOURCES += gcgio.cpp queenie.cpp streamingreporter.cpp flexiblealphabet.cpp util.cpp froggetopt.cpp dict.cpp dictfactory.cpp dictimplementation.cpp
+
+win32:!win32-g++ {
+ QMAKE_CFLAGS_DEBUG ~= s/-MDd/-MTd/
+ QMAKE_CXXFLAGS_DEBUG ~= s/-MDd/-MTd/
+ QMAKE_CFLAGS_RELEASE ~= s/-MD/-MT/
+ QMAKE_CXXFLAGS_RELEASE ~= s/-MD/-MT/
+}
diff --git a/quackleio/queenie.cpp b/quackleio/queenie.cpp
new file mode 100644
index 0000000..7b02c7e
--- /dev/null
+++ b/quackleio/queenie.cpp
@@ -0,0 +1,87 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <iostream>
+
+#include <QtCore>
+
+#include "gcgio.h"
+#include "queenie.h"
+
+using namespace QuackleIO;
+
+Queenie *Queenie::m_self = 0;
+
+Queenie *Queenie::self()
+{
+ if (m_self == 0)
+ m_self = new Queenie();
+
+ return m_self;
+}
+
+void Queenie::cleanUp()
+{
+ delete m_self;
+ m_self = 0;
+}
+
+Queenie::Queenie()
+{
+ m_loganias.push_back(new GCGIO);
+
+ for (QList<Logania *>::const_iterator it = m_loganias.begin(); it != m_loganias.end(); ++it)
+ m_filters.push_back((*it)->filter());
+}
+
+Queenie::~Queenie()
+{
+ while (!m_loganias.isEmpty())
+ delete m_loganias.takeFirst();
+}
+
+Logania *Queenie::loganiaForFile(const QString &filename)
+{
+ for (QList<Logania *>::const_iterator it = m_loganias.begin(); it != m_loganias.end(); ++it)
+ {
+ QFile file(filename);
+
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+ return 0;
+
+ QTextStream in(&file);
+
+ if ((*it)->canRead(in))
+ return (*it);
+ }
+
+ return 0;
+}
+
+const QStringList &Queenie::filters() const
+{
+ return m_filters;
+}
+
+Logania *Queenie::defaultLogania()
+{
+ return m_loganias.front();
+}
+
diff --git a/quackleio/queenie.h b/quackleio/queenie.h
new file mode 100644
index 0000000..a1b0efb
--- /dev/null
+++ b/quackleio/queenie.h
@@ -0,0 +1,62 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef QUACKLE_QUEENIE_H
+#define QUACKLE_QUEENIE_H
+
+#include <QtCore/QStringList>
+
+namespace QuackleIO
+{
+
+class Logania;
+
+class Queenie
+{
+public:
+ ~Queenie();
+
+ static Queenie *self();
+
+ // deletes self and resets
+ static void cleanUp();
+
+ // returns 0 if no handler found for the file type
+ Logania *loganiaForFile(const QString &filename);
+
+ const QStringList &filters() const;
+
+ Logania *defaultLogania();
+
+protected:
+ Queenie();
+ Queenie(const Queenie&);
+ Queenie& operator=(const Queenie &);
+
+ QList<Logania *> m_loganias;
+ QStringList m_filters;
+
+private:
+ static Queenie *m_self;
+};
+
+}
+
+#endif
diff --git a/quackleio/streamingreporter.cpp b/quackleio/streamingreporter.cpp
new file mode 100644
index 0000000..eac7d6f
--- /dev/null
+++ b/quackleio/streamingreporter.cpp
@@ -0,0 +1,53 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <QtCore>
+
+#include "game.h"
+#include "streamingreporter.h"
+#include "util.h"
+
+using namespace QuackleIO;
+
+StreamingReporter::StreamingReporter()
+{
+}
+
+void StreamingReporter::reportGame(const Quackle::Game &game, Quackle::ComputerPlayer *computerPlayer, QTextStream &stream)
+{
+ UVString header;
+ Quackle::Reporter::reportHeader(game, &header);
+ stream << Util::uvStringToQString(header);
+
+ const Quackle::PositionList::const_iterator end(game.history().end());
+ for (Quackle::PositionList::const_iterator it = game.history().begin(); it != end; ++it)
+ {
+ UVString subreport;
+ Quackle::Reporter::reportPosition((*it), computerPlayer, &subreport);
+
+ // endl flushes the stream, which we want
+ stream << Util::uvStringToQString(subreport) << endl;
+ }
+
+ UVString stats;
+ Quackle::Reporter::reportGameStatistics(game, &stats);
+ stream << Util::uvStringToQString(stats);
+}
+
diff --git a/quackleio/streamingreporter.h b/quackleio/streamingreporter.h
new file mode 100644
index 0000000..e4d1f37
--- /dev/null
+++ b/quackleio/streamingreporter.h
@@ -0,0 +1,50 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef QUACKLE_STREAMINGREPORTER_H
+#define QUACKLE_STREAMINGREPORTER_H
+
+#include "reporter.h"
+
+class QTextStream;
+
+namespace Quackle
+{
+ class Game;
+}
+
+namespace QuackleIO
+{
+
+// Full-game reporter using Qt streaming.
+
+class StreamingReporter
+{
+public:
+ StreamingReporter();
+
+ // duplicates functionality of Quackle::Reporter::reportGame but suitable
+ // for streaming so everything doesn't appear in the file at once.
+ static void reportGame(const Quackle::Game &game, Quackle::ComputerPlayer *computerPlayer, QTextStream &stream);
+};
+
+}
+
+#endif
diff --git a/quackleio/util.cpp b/quackleio/util.cpp
new file mode 100644
index 0000000..e3f947d
--- /dev/null
+++ b/quackleio/util.cpp
@@ -0,0 +1,212 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <QtCore>
+
+#include <move.h>
+#include <rack.h>
+
+#include "dict.h"
+#include "dictfactory.h"
+#include "util.h"
+
+using namespace QuackleIO;
+
+UtilSettings *UtilSettings::m_self = 0;
+UtilSettings *UtilSettings::self()
+{
+ return m_self;
+}
+
+UtilSettings::UtilSettings()
+ : octothorpBritish(true), vowelFirst(false)
+{
+ m_self = this;
+}
+
+QString Util::moveToDetailedString(const Quackle::Move &move)
+{
+ QString prettyTiles = letterStringToQString(move.prettyTiles());
+
+ QString ret;
+
+ switch (move.action)
+ {
+ case Quackle::Move::Pass:
+ ret = QObject::tr("Pass");
+ break;
+
+ case Quackle::Move::Exchange:
+ ret = QObject::tr("Exch. %1").arg(prettyTiles);
+ break;
+
+ case Quackle::Move::UnusedTilesBonus:
+ ret = QObject::tr("2*(%1)").arg(letterStringToQString(Util::alphagram(move.usedTiles())));
+ break;
+
+ case Quackle::Move::TimePenalty:
+ ret = QObject::tr("%1 point time penalty").arg(move.effectiveScore());
+ break;
+
+ case Quackle::Move::Nonmove:
+ ret = QObject::tr("None");
+ break;
+
+ case Quackle::Move::Place:
+ ret = uvStringToQString(move.positionString()) + " ";
+ ret += prettyTiles;
+
+ if (UtilSettings::self()->octothorpBritish)
+ ret += symbolsFor(move.wordTiles());
+
+ if (move.isChallengedPhoney())
+ ret = QObject::tr("%1 [Challenged Off]").arg(ret);
+
+ break;
+ }
+
+ if (move.scoreAddition() != 0)
+ ret = QString("%1 [and %2%3]").arg(ret).arg(move.scoreAddition() > 0? QObject::tr("+") : QString()).arg(move.scoreAddition());
+
+ return ret;
+}
+
+QString Util::moveToSensitiveString(const Quackle::Move &move)
+{
+ QString ret;
+
+ if (move.action == Quackle::Move::Exchange)
+ ret = QObject::tr("Exch. %1").arg(move.prettyTiles().length());
+ else
+ ret = moveToDetailedString(move);
+
+ return ret;
+}
+
+UVString Util::qstringToString(const QString &qstring)
+{
+#if QUACKLE_USE_WCHAR_FOR_USER_VISIBLE
+ return qstring.toStdWString();
+#else
+ return string(qstring.toUtf8().data());
+#endif
+}
+
+QString Util::uvStringToQString(const UVString &uvString)
+{
+#if QUACKLE_USE_WCHAR_FOR_USER_VISIBLE
+ return QString::fromStdWString(uvString);
+#else
+ return QString::fromUtf8(uvString.c_str());
+#endif
+}
+
+Quackle::LetterString Util::encode(const QString &qstring)
+{
+ return QUACKLE_ALPHABET_PARAMETERS->encode(qstringToString(qstring));
+}
+
+Quackle::LetterString Util::nonBlankEncode(const QString &qstring)
+{
+ return QUACKLE_ALPHABET_PARAMETERS->clearBlankness(encode(qstring));
+}
+
+QString Util::letterStringToQString(const Quackle::LetterString &letterString)
+{
+ return uvStringToQString(QUACKLE_ALPHABET_PARAMETERS->userVisible(letterString));
+}
+
+QString Util::letterToQString(const Quackle::Letter &letter)
+{
+ return uvStringToQString(QUACKLE_ALPHABET_PARAMETERS->userVisible(letter));
+}
+
+string Util::qstringToStdString(const QString &qstring)
+{
+ return string(qstring.toAscii());
+}
+
+QString Util::stdStringToQString(const string &stdString)
+{
+ return QString::fromAscii(stdString.c_str());
+}
+
+Quackle::LetterString Util::alphagram(const Quackle::LetterString &word)
+{
+ return Quackle::String::alphabetize(word);
+}
+
+QString Util::alphagram(const QString &word)
+{
+ return letterStringToQString(Quackle::String::alphabetize(encode(word)));
+}
+
+Quackle::LetterString Util::arrangeLettersForUser(const Quackle::LetterString &word)
+{
+ Quackle::LetterString alphabetized = Quackle::String::alphabetize(word);
+
+ Quackle::LetterString vowels;
+ Quackle::LetterString nonvowels;
+ Quackle::LetterString blanks;
+ for (Quackle::LetterString::iterator it = alphabetized.begin(); it != alphabetized.end(); ++it)
+ {
+ if ((*it) == QUACKLE_BLANK_MARK)
+ blanks.push_back(*it);
+ else if (UtilSettings::self()->vowelFirst && QUACKLE_ALPHABET_PARAMETERS->isVowel(*it))
+ vowels.push_back(*it);
+ else
+ nonvowels.push_back(*it);
+ }
+
+ return vowels + nonvowels + blanks;
+}
+
+Quackle::LetterString Util::arrangeLettersForUser(const Quackle::Rack &rack)
+{
+ return arrangeLettersForUser(rack.tiles());
+}
+
+Quackle::Rack Util::makeRack(const QString &letters)
+{
+ return Quackle::Rack(QuackleIO::Util::encode(letters.toUpper().replace('.', "?")));
+}
+
+QString Util::arrangeLettersForUser(const QString &word)
+{
+ return letterStringToQString(arrangeLettersForUser(encode(word)));
+}
+
+QString Util::sanitizeUserVisibleLetterString(const QString &pipedString)
+{
+ QString pipedStringCopy = pipedString;
+ pipedStringCopy.replace("|", " ");
+ return pipedStringCopy.simplified();
+}
+
+QString Util::symbolsFor(const Quackle::LetterString &word)
+{
+ if (DictFactory::querier()->isBritish(word))
+ {
+ return "#";
+ }
+
+ return "";
+}
+
diff --git a/quackleio/util.h b/quackleio/util.h
new file mode 100644
index 0000000..4838d1e
--- /dev/null
+++ b/quackleio/util.h
@@ -0,0 +1,96 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef QUACKER_UTIL_H
+#define QUACKER_UTIL_H
+
+#include <QString>
+
+#include <alphabetparameters.h>
+#include <datamanager.h>
+#include <uv.h>
+
+namespace Quackle
+{
+ class Move;
+ class Rack;
+}
+
+namespace QuackleIO
+{
+
+class UtilSettings
+{
+public:
+ UtilSettings();
+ static UtilSettings *self();
+
+ bool octothorpBritish;
+ bool vowelFirst;
+
+private:
+ static UtilSettings *m_self;
+};
+
+class Util
+{
+public:
+ static UVString qstringToString(const QString &qstring);
+ static Quackle::LetterString encode(const QString &qstring);
+
+ // encode as above but clear blankess of all letters
+ static Quackle::LetterString nonBlankEncode(const QString &qstring);
+
+ static QString uvStringToQString(const UVString &stdWString);
+ static QString letterStringToQString(const Quackle::LetterString &letterString);
+ static QString letterToQString(const Quackle::Letter &letter);
+
+ // non-ui strings
+ static string qstringToStdString(const QString &qstring);
+ static QString stdStringToQString(const string &stdString);
+
+ static QString moveToDetailedString(const Quackle::Move &move);
+ static QString moveToSensitiveString(const Quackle::Move &move);
+
+ // make alphagram
+ static Quackle::LetterString alphagram(const Quackle::LetterString &word);
+ static QString alphagram(const QString &word);
+
+ // make pattern of letters user wants based on settings
+ static Quackle::LetterString arrangeLettersForUser(const Quackle::LetterString &word);
+ static Quackle::LetterString arrangeLettersForUser(const Quackle::Rack &rack);
+ static QString arrangeLettersForUser(const QString &word);
+
+ // make rack, converting letters to uppercase and changing "." into blank
+ static Quackle::Rack makeRack(const QString &letters);
+
+ // Some alphabets enclose some of their letters in pipes, like |TT|, if
+ // ambiguity could arise without letters being explicitly delimited.
+ // This method returns a string that has no pipes and each letter separated
+ // with a space.
+ static QString sanitizeUserVisibleLetterString(const QString &pipedString);
+
+ // Returns a string of symbols, like an octothorp for a british word.
+ static QString symbolsFor(const Quackle::LetterString &word);
+};
+
+}
+
+#endif