Здравствуйте! Есть одна программа для создания кроссвордов. Она состоит из двух частей: http://labfreetech.org/downloads/xwce/xwce-0.5.6-lin-src.tar.gz и http://labfreetech.org/downloads/xwcv/xwcv-0.5.1-lin-src.tar.gz.
Прошу её код хорошо покритиковать. Для остальных, чтобы могли посмотреть на её работу, дам ссылки на бинарники 32-бит: http://labfreetech.org/downloads/xwce/xwce-0.5.6-win-x86.exe, http://labfreetech.org/downloads/xwcv/xwcv-0.5.1-win-x86.exe. Qt-4.5.3.
Проекты OpenSource под GPLv2. Ссылки на SourceForge.net - http://sourceforge.net/projects/xwce/, http://sourceforge.net/projects/xwcv/.
Это мой первый код на C++(Qt). Жду комментариев
Добавлю небольшое описание: Сетка кроссворда представлена обычной таблицей TableCrosswordEdit(QTableWidget), слова загружаются в список слов ListWord(QStringList), толкования(вопросы) находятся в списке вопросов ListQuestions(QListWidget).
Структура файла - динамическая. Когда писал программы на Delphi - использовал статику - расходовалось лишнее дисковое пространство .
XWC: Пароль, количество строк, количество столбцов, ширина(высота) ячейки таблицы, шрифт, структура таблицы(w + 1(x) - белая ячейка, b + 1( c ) - чёрная), строка с данными CrosswordData(QString).
... if(file.open(QIODevice::WriteOnly))
{
QBrush BrushBlack = QBrush(Qt::black, Qt::SolidPattern);
QDataStream sfile(&file);
QChar sdata;
ushort idata;
if(State == false) sfile << strPassword;
sfile << TableCrosswordEdit->rowCount();
sfile << TableCrosswordEdit->columnCount();
sfile << TableCrosswordEdit->rowHeight(0);
sfile << TableCrosswordEdit->font();
for(int i = 0; i < TableCrosswordEdit->rowCount(); i++)
for(int j = 0; j < TableCrosswordEdit->columnCount(); j++)
{
if(TableCrosswordEdit->item(i,j)->background() == BrushBlack)
{
sdata = 'b';
idata = sdata.unicode() + 1;
sfile << idata;
}
else
{
sdata = 'w';
idata = sdata.unicode() + 1;
sfile << idata;
}
sdata = 0;
}
if(State == false) CrosswordToData(2);
if(State == false) sfile << CrosswordData;
file.close();
if(State == false) SaveStateCross = true;
else SaveStateTemplate = true;
} ...
...
for(int i = 0; i < ListWord.count(); i++)
{
CrosswordData.append(QChar('W'));
CrosswordData.append(QChar(ushort(i)));
CurrentString.clear();
CurrentString.append(ListWord.at(i));
CrosswordData.append(QChar(ushort(CurrentString.length())));
CrosswordData.append(ListWord.at(i));
}
for(int i = 0; i < ListQuestions->count(); i++)
{
CrosswordData.append(QChar('Q'));
CrosswordData.append(QChar(ushort(i)));
CrosswordData.append(QChar(ushort(ListQuestions->item(i)->text().length())));
CrosswordData.append(ListQuestions->item(i)->text());
} ...
у нас на сайте, есть раздел исходники, можешь добавить туда.
нцужно просто зайти залогинившись на форуме на сам crossplatform.ru и все увидишь.
Продолжаем знакомиться с исходником. Профессиональный кроссворд, версии 0.1.4 - это объединение двух предыдущих: создателя и отгадывателя, с последующей доработкой.
Изменения:
- Добавлена возможность автоматического создания сетки кроссворда(бета-версия).
- Добавлена возможность автоматического составления кроссворда(выбор слов из словаря). Первая бета-версия.
- Присутствуют обе возможности(создание и отгадывыание).
Отмечу, что выбор слов происходит в один проход и могут быть пропуски слов в сетке, после составления кроссворда.
http://sourceforge.net/projects/klest-crossword/files/0.1.4/(0.1.4) Отдельный проект на SourceForge.net - http://sourceforge.net/projects/klest-crossword/
В Клёст-кроссворде нет возможности сохранять пароль, в то время как в Crossword editor эта возможность есть. Проекты были разделены для большего удобства разработки.
P.S. Профессиональный кроссворд 0.1.7 = Клёст-кроссворд 0.1.7
Следующая версия программы - 0.1.5. http://sourceforge.net/projects/klest-crossword/files/0.1.5/.
Изменилась функция составления кроссворда, которая теперь позволяет заполнить всю сетку кроссворда словами.
Попробуй рассказать об игре на http://www.gamedev.ru/projects/forum/ Будет дополнительная реклама и возможно какие-нибудь советы и пожелания. Ну и удачи с проектом
А вот и новая версия 0.1.7. Изучаем http://sourceforge.net/projects/klest-crossword/files/0.1.7/.
Что изменено:
Если у кого-нибудь будет желание свою изменённую версию кроссворда далее распространять, то для этой цели я подготовил спекфайл для сборки программы в дистрибутиве ОС Linux, основанного на RPM-пакетах.
Также прошу найти в нём ошибки:
Продолжение: 0.1.8. http://sourceforge.net/projects/klest-crossword/files/0.1.8/.
Изменения:
Здравствуйте!
Хочу порадовать Вас тем, что я сделал дополнительный архив исходного кода, для сборки программы в ОС GNU / Linux Debian( / Ubuntu).
Для сборки deb-пакета необходимо наличие установленных пакетов: autotools-dev, dh-make, fakeroot, cdbs, dpkg, dpkg-dev и другие.
Команда сборки:
Следующая версия = 0.2.0.
http://sourceforge.net/projects/klest-crossword/files/0.2.0/: 0.2.0.
Важное изменение: добавление значков Oxygen. Ещё добавлены 2-а новых словаря: русский на 31 000 слов и английский на 41 000 слов. Теперь программа выглядит вот так -
Произведённые изменения:
xwicked,
xwicked, громоздкость ? Да ерунда. Имена неосновных узлов можно задавать покороче. Всё остальное хорошо сожмётся архиватором
Минусы двоичных форматов:
1. громоздкость самого формата. Давай, сохрани туда вектор или мапу Опупеешь.
2. Непереносимость и трудность переходов между версиями. Байт влево , байт вправо - расстрел на месте. Также нужно постоянно помнить и трястись над тем, чтобы (см п1) содержимое структур можно было бы побайтово копировать, а также чтобы не менялся порядок сохранения данных
3. за счёт чего увеличение ? Например, я сохраняю XML "вручную" (мне так показалось удобнее), а парсю готовым классом с открытыми исходниками. Ну добавит это всё от силы пару килобайт в модуль.
ЗАТО
- забудешь про пункт 2
- экономия кучи нервов и времени
- вложенность: можно для каждого класса определить функцию, которая дописывает в поток кусочек с XML-узлом класса.
- отладка. Попробуешь - поймёшь. Видно визуально, правится прямо в студии (ну это я про себя - у меня студия), она и UTF8 понимает, и форматирование расставит.
- непринуждённая расширяемость. Добавляй, что хочешь, удаляй, что хочешь.
лично я раньше сохранял в двоичные файлы, но когда узнал про XML - теперь никогда такой хренью не страдаю )))
xwicked, ох, а как весело поддерживать программы, где программист вовсю сохранял структурированные данные в двоичные файлы... Я вот сейчас такой проект веду. Как внезапно начинало рушиться - а поразбираешься, вот она, причина. Поменял местами переменные в структуре, а он, гат такой, в двоичные файлы любит записывать, в результате записывается указатель (и читается тоже). Не поленился, потратил два дня на переделывание в XML - теперь полёт нормальный )
Ещё один интересный момент: как думаешь, что сохранится в файл, если запишешь туда переменную типа B ?
struct A
{
int a;
A():a(0x00)
{
}
A(int a):a(a)
{
}
virtual ~A()
{
}
};
struct B:A
{
A a2;
int b;
B():a2(0x11),b(0x22)
{
}
};
B b;
int i=sizeof(b); //сколько ?
void* p=&b; //что там ?
xwicked, я прекрасно осведомлён о содержимом и устройстве простейшего XML, который использую очень часто
Я не навязываю. К этому сам потом придёшь, когда будешь зарабатывать на жизнь программированием. XML против бинарников - это экономия сил, времени и , соответственно, денег. Я советую именно потому, что всё это прошёл и знаю разницу. Есть выбор:
1) бинарник + малый объём + много гемора при отладке и совместимости версий
2) XML + чуть побольше объём + удобная отладка, поддержка и совместимость
А рост объёма сейчас мало кого волнует - ресурсы машин растут несоизмеримо быстрее.
xwicked, осторожно! Кроссворды тебя погубят
Программа доведена до стабильности. Релиз 0.2.1. http://sourceforge.net/projects/klest-crossword/files/0.2.1/.
Все изменения:
А в http://sourceforge.net/projects/klest-crossword/files/0.2.2/ 0.2.2 я реализовал импорт кроссворда из текстового формата AcrossLite первой версии. Вторая версия будет загружаться, но за исключением дополнительной головоломки.
Что нового:
Здравствуйте!
В http://sourceforge.net/projects/klest-crossword/files/0.2.8/ я добавил функции горизонтального и вертикального отражения кроссворда как изображения. Так же добавил инверсию цветов ячеек сетки кроссворда. Но... я не смог быстро придумать функцию обрезания сетки кроссворда, если он, например, получился меньше созданных рамок. Интересует самое простое решение данного вопроса. Благодарю!
Ещё изменения:
http://sourceforge.net/projects/klest-crossword/files/0.2.9 версия программы 0.2.9. В ней я походу вышел за предел стека Ошибку я уже нашёл.
QTextEdit textEdit;
textEdit.setHtml(strHTML);
#ifndef QT_NO_PRINTER
QPrinter printer(QPrinter::HighResolution);//Настройка принтера на высокое качество
printer.setOutputFormat(QPrinter::PostScriptFormat);//Выбор печати в файл PostScript
printer.setOutputFileName(sExportName);//Присваивание имени файла
textEdit.document()->print(&printer);//Сама печать
#endif
Хотелось бы отметить, что с появлением функции экспорта кроссворда в Across Lite TXT, у программы across lite 2.0 появилась возможность отгадывать не только американские кроссворды, но и классические, правда всё в английском языке. Можете поэксперементировать, ради интереса
Здравствуйте! Как я избавился от переполнения стека:
ushort usTable[50][50];//Массив сетки кроссворда
Если делал больше 50-ти, то отваливался импорт файла и запуск руководства пользователя ushort **usTable;//Массив сетки кроссворда
...
//Создание двумерного динамического массива
usTable = new ushort*[TableKlestCrossword->rowCount()];
for(int i = 0; i < TableKlestCrossword->rowCount(); i++)
usTable[i] = new ushort[TableKlestCrossword->columnCount()];
Далее введены константы://Определение путей констант, в соответствии с системой
#if defined(Q_WS_WIN)
#define PATH_TMP_SET QApplication::applicationDirPath() + "/settings.xwsc"
#define PATH_SHARE_DOC QApplication::applicationDirPath()
#define PATH_SHARE_APP QApplication::applicationDirPath()
#define PATH_TMP_STAT QApplication::applicationDirPath() + "/cstat.html"
#elif defined(Q_WS_X11)
#define PATH_TMP_SET "/tmp/klest-crossword-0.3.7/settings.xwsc"
#define PATH_SHARE_DOC "/usr/share/doc/klest-crossword-0.3.7"
#define PATH_SHARE_APP "/usr/share/klest-crossword-0.3.7"
#define PATH_TMP_STAT "/tmp/klest-crossword-0.3.7/cstat.html"
#elif defined(Q_WS_MAC)
#define PATH_TMP_SET QApplication::applicationDirPath() + "/settings.xwsc"
#define PATH_SHARE_DOC QApplication::applicationDirPath()
#define PATH_SHARE_APP QApplication::applicationDirPath()
#define PATH_TMP_STAT QApplication::applicationDirPath() + "/cstat.html"
#endif
//Пути для разработки и отладки программы
/*#define PATH_TMP_SET QApplication::applicationDirPath() + "/settings.xwsc"
#define PATH_SHARE_DOC QApplication::applicationDirPath()
#define PATH_SHARE_APP QApplication::applicationDirPath()
#define PATH_TMP_STAT QApplication::applicationDirPath() + "/cstat.html"*/
#define MODE_VIEW true
#define MODE_EDIT false
#define ACROSS_ENABLE true
#define ACROSS_DISABLE false
#define LANGUAGE_RUSSIAN true
#define LANGUAGE_ENGLISH false
#define TOOLBAR_SHOW true
#define TOOLBAR_HIDE false
#define EXPORT_YES true
#define EXPORT_NO false
#define TYPE_PDF 0
#define TYPE_POST_SCRIPT 1
Что позволило пути в программе менять всего один раз Так же появилась возможность убрать лишние условия и оформить в switch: switch(iTypeExport)
{
case TYPE_PDF:
sFilter = ".pdf";
break;
case TYPE_POST_SCRIPT:
sFilter = ".ps";
break;
case TYPE_HTML:
sFilter = ".html";
break;
case TYPE_TXT:
sFilter = ".txt";
break;
case TYPE_JPG:
sFilter = ".jpg";
break;
case TYPE_JPEG:
sFilter = ".jpeg";
break;
case TYPE_BMP:
sFilter = ".bmp";
break;
case TYPE_TIFF:
sFilter = ".tiff";
break;
case TYPE_PNG:
sFilter = ".png";
break;
case TYPE_XPM:
sFilter = ".xpm";
break;
case TYPE_XBM:
sFilter = ".xbm";
break;
case TYPE_PPM:
sFilter = ".ppm";
break;
case TYPE_OPEN_KLEST:
sFilter = ".ok";
break;
}
Введение структуры файла свойств://Структура файла свойств программы
struct TFileOptions
{
bool bModeWork,//Режим работы программы
bLanguageProgram,//Язык программы
bStateStandardToolbar,//Состояние показа стандартной панели
bStateExport,//Состояние экспортирования
bCurrentDictionary;//Текущий словарь
QString sModePassword,//Пароль режима
sPathCrossword,//Путь для кроссвордов
sPathExport,//Путь для экспорта
sPathTemplate;//Путь для шаблонов
int iNumberTimes,//Количество раз
iTypeExport;//Тип экспорта
};
http://sourceforge.net/projects/klest-crossword/files/0.3.7/. На данный момент это последняя версия, прошу...
можно немного встряну ))
предлагаю более ООП варианты:
с массивом лучше так
//A - класс кроссвоода
#include <vector>
class A
{
enum
{
e_W=50,
e_H=50,
e_init=0,
};
typedef ushort td_elem;//тип элемента
typedef std::vector<td_elem> td_row;//тип строки
typedef std::vector<td_row> td_table;//тип таблицы
td_table m_usTable;
A();
};
A::A()
:m_usTable(e_H,td_row(e_W,td_elem(e_init)))
{
}
//где-то в программе:
ushort current_row=4;
ushort current_col=7;
m_usTable[current_row][current_col]=td_elem('A');
//Определение путей констант, в соответствии с системой
class mydefines
{
public:
enum
{
MODE_VIEW =true,
MODE_EDIT =false,
ACROSS_ENABLE =true,
ACROSS_DISABLE =false,
LANGUAGE_RUSSIAN =true,
LANGUAGE_ENGLISH =false,
TOOLBAR_SHOW =true,
TOOLBAR_HIDE =false,
EXPORT_YES =true,
EXPORT_NO =false,
};
enum ee_path_id
{
PATH_TMP_SET ,
PATH_SHARE_DOC ,
PATH_SHARE_APP ,
PATH_TMP_STAT ,
};
enum ee_ext_id
{
TYPE_PDF ,
TYPE_POST_SCRIPT ,
TYPE_HTML ,
TYPE_TXT ,
TYPE_JPG ,
TYPE_JPEG ,
TYPE_BMP ,
TYPE_TIFF ,
TYPE_PNG ,
TYPE_XPM ,
TYPE_XBM ,
TYPE_PPM ,
TYPE_OPEN_KLEST ,
};
//Пути для разработки и отладки программы
static QString GetPath(ee_path_id id);
//расширение (без точки)
static QString GetExt(ee_ext_id id);
};
#include <map>
QString mydefines::GetPath(ee_path_id id)
{
typedef std::map<ee_path_id,QString> td_map;
static td_map _map;
if(_map.empty())
{
#if defined(Q_WS_WIN)
_map[PATH_TMP_SET ]=QApplication::applicationDirPath() + "/settings.xwsc";
_map[PATH_SHARE_DOC ]=QApplication::applicationDirPath();
_map[PATH_SHARE_APP ]=QApplication::applicationDirPath();
_map[PATH_TMP_STAT ]=QApplication::applicationDirPath() + "/cstat.html";
#elif defined(Q_WS_X11)
_map[PATH_TMP_SET ]="/tmp/klest-crossword-0.3.7/settings.xwsc";
_map[PATH_SHARE_DOC ]="/usr/share/doc/klest-crossword-0.3.7";
_map[PATH_SHARE_APP ]="/usr/share/klest-crossword-0.3.7";
_map[PATH_TMP_STAT ]="/tmp/klest-crossword-0.3.7/cstat.html";
#elif defined(Q_WS_MAC)
_map[PATH_TMP_SET ]=QApplication::applicationDirPath() + "/settings.xwsc";
_map[PATH_SHARE_DOC ]=QApplication::applicationDirPath();
_map[PATH_SHARE_APP ]=QApplication::applicationDirPath();
_map[PATH_TMP_STAT ]=QApplication::applicationDirPath() + "/cstat.html";
#endif
}
td_map::const_iterator it=_map.find(id);
if(it==_map.end())return "";
return it->second;
}
QString mydefines::GetExt(ee_ext_id id)
{
switch(id)
{
case TYPE_PDF :return "pdf";break;
case TYPE_POST_SCRIPT :return "ps" ;break;
case TYPE_HTML :return "html";break;
case TYPE_TXT :return "txt";break;
case TYPE_JPG :return "jpg";break;
case TYPE_JPEG :return "jpeg";break;
case TYPE_BMP :return "bmp";break;
case TYPE_TIFF :return "tiff";break;
case TYPE_PNG :return "png";break;
case TYPE_XPM :return "xpm";break;
case TYPE_XBM :return "xbm";break;
case TYPE_PPM :return "ppm";break;
case TYPE_OPEN_KLEST :return "ok" ;break;
}
return "";
}
QString filename=
mydefines::GetPath(mydefines::PATH_SHARE_DOC)
+"1234"
+"."
+mydefines::GetExt(mydefines::TYPE_BMP)
;
char Test[13][6] = {".pdf",".ps",".html",".txt",".jpg",".jpeg",".bmp",".tiff",".png",".xpm",".xbm",".ppm",".ok"}; // подготовка
.....
sFilter = Test[iTypeExport]; // замена свитча
>>Насчёт остального мне пока квалификации не хватает, чтобы понять, где что
задавай вопросы, расскажу, что там я сделал
свич - это великолепная штука, когда нужно выбрать одину из циферных констант, сравнивая со значением тестируемой переменной (как в mydefines::GetExt )
работает быстро, так как компилятор строит табличную адресацию, а не перебор множества условий, как можно было бы подумать. То есть, практически вычисляется тот же индекс, по которому берётся адрес перехода для jmp , делается переход.
Оптимизация констант:
enum eTypeCrossword {TYPE_PDF, TYPE_POST_SCRIPT, TYPE_RTF, TYPE_HTML, TYPE_TXT, TYPE_JPG, TYPE_JPEG, TYPE_BMP,
TYPE_TIFF, TYPE_PNG, TYPE_XPM, TYPE_XBM, TYPE_PPM, TYPE_OPEN_KLEST};
Экспорт в RTF вместе с изображением:QString TCrosswordGrid::wordToUnicode(QString sWord)
{
QString sTemp;
for (int i = 0; i < sWord.length(); i++)
//Добавляет один символ Unicode, если этого не получается сделать, то отображается знак вопроса
sTemp.append("\\u" + QString::number(sWord.at(i).unicode()) + "?");
return sTemp;
}
//Формирование RTF-документа и сохранение
void TCrosswordGrid::saveToRTF(QString sExportName, QString strRTF, QImage imgExport)
{
QByteArray baImage;
QBuffer buffer(&baImage);
buffer.open(QIODevice::WriteOnly);
imgExport.save(&buffer, "BMP");//BMP как обязательный формат изображения
baImage = baImage.toHex();//Побайтовое преобразование изображения в шестнадцатеричную форму
QFile ifile(sExportName);
QTextStream istream(&ifile);
istream.setCodec("UTF-8");//UTF-8 кодировка документа
ifile.open(QIODevice::WriteOnly);
//Добавление информации об изображении с сохранением изначального размера
istream << "{\\rtf1\n{\\pict\\wmetafile8\\picw" + QString::number(columnCount() * rowHeight(0) * 27) + "\\pich"
+ QString::number(rowCount() * rowHeight(0) * 27) + "\n";
int j = 0;
for (int i = 0; i < baImage.size(); i++)
{
if (j == 128)//Если количество символов в строке == 128
{
istream << "\n";//То перевод строки; Избавляет от ошибок, при чтении документа.
j = 0;
}
istream << baImage.at(i);
j++;
}
istream << "}\\par\\par\n";
istream << strRTF;
istream << "}";
ifile.close();
}
//Формирование RTF-текста вопросов и ответов
QString TCrosswordGrid::makeRTFText(QString ListWordH, QString ListWordV, QStringList ListOutV, QStringList ListOutH)
{
QString strRTF;
QString strText1;
QString strText2;
QString strText3;
for(int i = 0; i < ListOutH.count(); i++)
{
strText1.append(wordToUnicode(ListOutH.at(i)) + "\\par\n");
}
strText2.clear();
for(int i = 0; i < ListOutV.count(); i++)
{
strText2.append(wordToUnicode(ListOutV.at(i)) + "\\par\n");
}
strText3.clear();
strText3 = "{\\b " + wordToUnicode(tr("Horizontal")) + "}:\\par\n" + wordToUnicode(ListWordH) + "\\par\n" + "{\\b " + wordToUnicode(tr("Vertical"))
+"}:\\par\n" + wordToUnicode(ListWordV) + "\\par\n";
strRTF.append("{\\b " + wordToUnicode(tr("Horizontal")) + "}:\\par\n"
+ strText1 + "\\par\n"
"{\\b " + wordToUnicode(tr("Vertical")) + "}:\\par\n"
+ strText2 + "\\par\n"
"{\\b\\i " + wordToUnicode(tr("Answers")) + "}:\\par\n"
+ strText3 + "\\par\n");
return strRTF;
}
Использовался материал http://ru.wikipedia.org/wiki/Rich_Text_Format. http://sourceforge.net/projects/klest-crossword/files/1.0.0/.Все изменения:
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)