366 lines
12 KiB
C++
366 lines
12 KiB
C++
#include "qbrainfuck.h"
|
|
#include "ui_qbrainfuck.h"
|
|
|
|
QBrainfuck::QBrainfuck(QWidget *parent) :
|
|
QMainWindow(parent),
|
|
ui(new Ui::QBrainfuck)
|
|
{
|
|
ui->setupUi(this);
|
|
}
|
|
|
|
QBrainfuck::~QBrainfuck()
|
|
{
|
|
delete ui;
|
|
}
|
|
|
|
void QBrainfuck::on_encodeButton_clicked()
|
|
{
|
|
QByteArray text = ui->textTextEdit->document()->toPlainText().toLatin1();
|
|
ui->programTextEdit->setPlainText("");
|
|
ui->debugTextEdit->setHtml("");
|
|
|
|
// First pass : find decades/steps
|
|
QList<char> decades; // Store the decades for initial loop
|
|
decades.append(0);
|
|
QList<char> array; // Store the program's memory
|
|
array.append(0);
|
|
QList<char> steps; // Store the steps to construct the program
|
|
|
|
QString debugNumbers;
|
|
QString debugChars;
|
|
|
|
QByteArray::const_iterator textIterator;
|
|
for (textIterator = text.constBegin(); textIterator != text.constEnd(); ++textIterator) {
|
|
int max_diff = ui->maxSignsSpinBox->value()+1;
|
|
QList<char>::iterator index;
|
|
|
|
// Find nearest memory's case and store it
|
|
QList<char>::iterator arrayIterator;
|
|
for (arrayIterator = array.begin(); arrayIterator != array.end(); ++arrayIterator) {
|
|
if (qAbs(*arrayIterator-*textIterator) < max_diff) {
|
|
max_diff = qAbs(*arrayIterator-*textIterator);
|
|
index = arrayIterator;
|
|
}
|
|
}
|
|
|
|
// Add step and insert current value in the array, else add a decade if we don't find a case nearer than max_diff
|
|
if (max_diff <= ui->maxSignsSpinBox->value()) {
|
|
steps.append(*index);
|
|
*index = *textIterator;
|
|
} else {
|
|
steps.append(qRound(*textIterator/(float)ui->decadesSpinBox->value())*ui->decadesSpinBox->value());
|
|
decades.append(qRound(*textIterator/(float)ui->decadesSpinBox->value())*ui->decadesSpinBox->value());
|
|
array.append(*textIterator);
|
|
}
|
|
|
|
// Add current char to debug (with corresponding ASCII value)
|
|
debugNumbers += formatNumber(*textIterator);
|
|
debugChars += " " + QString(*textIterator);
|
|
}
|
|
|
|
qSort(decades);
|
|
|
|
// Second pass : write program
|
|
QString program = "";
|
|
|
|
ui->debugTextEdit->insertHtml("# The message<br /><br />" + QString(text) + "<br /><br /># In ASCII<br /><br />" + debugNumbers + "<br />" + debugChars + "<br /><br /># The memory<br /><br />");
|
|
|
|
for(int i = 0; i < ui->decadesSpinBox->value(); ++i) {
|
|
program += "+";
|
|
}
|
|
|
|
program += "\[";
|
|
|
|
QList<char>::iterator decadesIterator;
|
|
for (decadesIterator = decades.begin()+1; decadesIterator != decades.end(); ++decadesIterator) {
|
|
program += ">";
|
|
for(int i = 0; i < *decadesIterator; i+=ui->decadesSpinBox->value()) {
|
|
program += "+";
|
|
}
|
|
}
|
|
for(int i = 0; i < decades.size()-1; ++i) {
|
|
program += "<";
|
|
}
|
|
program += "-]";
|
|
|
|
// Print initial loop to debug
|
|
QString debugText;
|
|
for(int multiplier = 0; multiplier <= ui->decadesSpinBox->value(); ++multiplier) {
|
|
debugText += " <b>" + formatNumber(ui->decadesSpinBox->value()-multiplier) + "</b>";
|
|
|
|
for(int i = 1; i < decades.length(); ++i) {
|
|
debugText += formatNumber(decades[i]/ui->decadesSpinBox->value()*multiplier);
|
|
}
|
|
|
|
debugText += "<br />";
|
|
}
|
|
debugText += "<br />";
|
|
ui->debugTextEdit->insertHtml(debugText);
|
|
|
|
int prev_ptr = 0;
|
|
|
|
QList<char>::const_iterator stepsIterator;
|
|
textIterator = text.constBegin();
|
|
for (stepsIterator = steps.constBegin(); stepsIterator != steps.constEnd(); ++stepsIterator) {
|
|
int next_ptr = decades.indexOf(*stepsIterator);
|
|
|
|
if(next_ptr > prev_ptr) {
|
|
for(int i = 0; i < next_ptr-prev_ptr; ++i) {
|
|
program += ">";
|
|
}
|
|
} else {
|
|
for(int i = 0; i < prev_ptr-next_ptr; ++i) {
|
|
program += "<";
|
|
}
|
|
}
|
|
|
|
if(*textIterator > *stepsIterator) {
|
|
for(int i = 0; i < *textIterator-*stepsIterator; ++i) {
|
|
program += "+";
|
|
}
|
|
} else {
|
|
for(int i = 0; i < *stepsIterator-*textIterator; ++i) {
|
|
program += "-";
|
|
}
|
|
}
|
|
|
|
program += ".";
|
|
prev_ptr = next_ptr;
|
|
decades[next_ptr] = *textIterator;
|
|
|
|
// Print current memory and current letter
|
|
printMemory(decades, decades.length(), next_ptr, " " + QString(*textIterator));
|
|
|
|
++textIterator;
|
|
}
|
|
|
|
ui->programTextEdit->setPlainText(program);
|
|
ui->debugTextEdit->insertHtml("<br /><br /># The program<br /><br />" + program);
|
|
}
|
|
|
|
void QBrainfuck::on_decodeButton_clicked()
|
|
{
|
|
ui->textTextEdit->setPlainText("");
|
|
ui->debugTextEdit->setHtml("");
|
|
|
|
bool exit = false;
|
|
int ptr = 0;
|
|
int maxPtr = 0;
|
|
QByteArray text = ui->programTextEdit->document()->toPlainText().toLatin1();
|
|
QByteArray array = QByteArray(ui->arraySpinBox->value(), (char)0);
|
|
QByteArray input = ui->inputLineEdit->text().toLatin1();
|
|
QByteArray::const_iterator last_textIterator;
|
|
QByteArray::const_iterator inputIterator = input.constBegin();
|
|
|
|
QByteArray::const_iterator textIterator;
|
|
int loopCounter = 0;
|
|
for (textIterator = text.constBegin(); textIterator != text.constEnd() && exit == false; ++textIterator) {
|
|
|
|
switch (*textIterator) {
|
|
case '>':
|
|
++ptr;
|
|
if (ptr >= ui->arraySpinBox->value()) {
|
|
ptr = 0;
|
|
}
|
|
if(maxPtr < ptr) {
|
|
maxPtr = ptr;
|
|
}
|
|
break;
|
|
case '<':
|
|
--ptr;
|
|
if (ptr < 0) {
|
|
ptr = ui->arraySpinBox->value()-1;
|
|
maxPtr = ptr;
|
|
}
|
|
break;
|
|
case '+':
|
|
array[ptr] = array.at(ptr) + 1;
|
|
break;
|
|
case '-':
|
|
array[ptr] = array.at(ptr) - 1;
|
|
break;
|
|
case '.':
|
|
ui->textTextEdit->insertPlainText(QString(array.at(ptr)));
|
|
printMemory(array, maxPtr, ptr, "OUTPUT: " + QString(array.at(ptr)));
|
|
break;
|
|
case ',':
|
|
array[ptr] = *inputIterator;
|
|
++inputIterator;
|
|
printMemory(array, maxPtr, ptr, "INPUT: " + QString(array.at(ptr)));
|
|
break;
|
|
case '[':
|
|
last_textIterator = textIterator;
|
|
loopCounter = 0;
|
|
printMemory(array, maxPtr, ptr, "LOOP BEG. ");
|
|
break;
|
|
case ']':
|
|
if(array.at(ptr)!=0) {
|
|
textIterator = last_textIterator;
|
|
++loopCounter;
|
|
|
|
if (loopCounter >= ui->loopSpinBox->value()) {
|
|
QMessageBox::critical(this, "QBrainfuck", "Error: Loop too long");
|
|
exit = true;
|
|
}
|
|
printMemory(array, maxPtr, ptr, "LOOP ");
|
|
} else {
|
|
printMemory(array, maxPtr, ptr, "LOOP END ");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void QBrainfuck::on_motifButton_clicked()
|
|
{
|
|
QString motif = ui->motifTextEdit->document()->toPlainText();
|
|
QByteArray program = ui->programTextEdit->document()->toPlainText().toLatin1();
|
|
|
|
if (motif.contains(QRegExp(">|<|\\+|-|\\.|,|\\[|\\]"))) {
|
|
QMessageBox::critical(this, "QBrainfuck", "Error: Motif contains Brainfuck characters");
|
|
return;
|
|
}
|
|
|
|
QByteArray::const_iterator programIterator;
|
|
for (programIterator = program.constBegin(); programIterator != program.constEnd(); ++programIterator) {
|
|
switch (*programIterator) {
|
|
case '>':
|
|
case '<':
|
|
case '+':
|
|
case '-':
|
|
case '.':
|
|
case ',':
|
|
case '[':
|
|
case ']':
|
|
int index = motif.indexOf(QRegExp(ui->regexLineEdit->text()));
|
|
if (index==-1) {
|
|
motif += *programIterator;
|
|
} else {
|
|
motif.replace(index, 1, *programIterator);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
ui->resultTextEdit->setPlainText(motif);
|
|
}
|
|
|
|
void QBrainfuck::on_textTextEdit_textChanged()
|
|
{
|
|
ui->textLabel->setText("Text length: " + QString().setNum(ui->textTextEdit->document()->toPlainText().length()));
|
|
}
|
|
|
|
void QBrainfuck::on_programTextEdit_textChanged()
|
|
{
|
|
ui->programLabel->setText("Program length: " + QString().setNum(ui->programTextEdit->document()->toPlainText().count(QRegExp(">|<|\\+|-|\\.|,|\\[|\\]"))));
|
|
}
|
|
|
|
void QBrainfuck::on_motifTextEdit_textChanged()
|
|
{
|
|
ui->motifLabel->setText("Motif length: " + QString().setNum(ui->motifTextEdit->document()->toPlainText().count(QRegExp(ui->regexLineEdit->text()))));
|
|
}
|
|
|
|
void QBrainfuck::on_regexLineEdit_textChanged(const QString &arg1)
|
|
{
|
|
on_motifTextEdit_textChanged();
|
|
}
|
|
|
|
void QBrainfuck::on_saveButton_clicked()
|
|
{
|
|
QFileDialog dialog(this);
|
|
dialog.setFileMode(QFileDialog::AnyFile);
|
|
dialog.setNameFilter("Json Files (*.json);;Txt Files (*.txt)");
|
|
dialog.setDefaultSuffix("json");
|
|
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
|
|
|
if (dialog.exec()) {
|
|
QFile saveFile(dialog.selectedFiles().first());
|
|
|
|
if (!saveFile.open(QIODevice::WriteOnly)) {
|
|
return;
|
|
}
|
|
|
|
if(dialog.selectedNameFilter() == "Json Files (*.json)") {
|
|
QJsonObject jsonObject;
|
|
|
|
jsonObject["text"] = ui->textTextEdit->document()->toPlainText();
|
|
jsonObject["program"] = ui->programTextEdit->document()->toPlainText();
|
|
jsonObject["motif"] = ui->motifTextEdit->document()->toPlainText();
|
|
jsonObject["result"] = ui->resultTextEdit->document()->toPlainText();
|
|
|
|
QJsonDocument jsonDoc(jsonObject);
|
|
saveFile.write(jsonDoc.toJson());
|
|
} else {
|
|
saveFile.write(ui->textTextEdit->document()->toPlainText().toUtf8() + "\n\n");
|
|
saveFile.write(ui->programTextEdit->document()->toPlainText().toUtf8() + "\n\n");
|
|
saveFile.write(ui->motifTextEdit->document()->toPlainText().toUtf8() + "\n\n");
|
|
saveFile.write(ui->resultTextEdit->document()->toPlainText().toUtf8() + "\n\n");
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void QBrainfuck::on_loadButton_clicked()
|
|
{
|
|
QFileDialog dialog(this);
|
|
dialog.setFileMode(QFileDialog::AnyFile);
|
|
dialog.setNameFilter("Json Files (*.json)");
|
|
dialog.setDefaultSuffix("json");
|
|
dialog.setAcceptMode(QFileDialog::AcceptOpen);
|
|
|
|
if (dialog.exec()) {
|
|
QFile loadFile(dialog.selectedFiles().first());
|
|
|
|
if (!loadFile.open(QIODevice::ReadOnly)) {
|
|
return;
|
|
}
|
|
|
|
QByteArray saveData = loadFile.readAll();
|
|
|
|
QJsonDocument jsonDoc(QJsonDocument::fromJson(saveData));
|
|
QJsonObject jsonObject = jsonDoc.object();
|
|
|
|
ui->textTextEdit->setPlainText(jsonObject["text"].toString());
|
|
ui->programTextEdit->setPlainText(jsonObject["program"].toString());
|
|
ui->motifTextEdit->setPlainText(jsonObject["motif"].toString());
|
|
ui->resultTextEdit->setPlainText(jsonObject["result"].toString());
|
|
}
|
|
}
|
|
|
|
QString QBrainfuck::formatNumber(int number)
|
|
{
|
|
if(number < 10) {
|
|
return " " + QString().setNum(number);
|
|
} else if (number < 100) {
|
|
return " " + QString().setNum(number);
|
|
} else {
|
|
return " " + QString().setNum(number);
|
|
}
|
|
}
|
|
|
|
void QBrainfuck::printMemory(QByteArray array, int maxPtr, int ptr, QString text)
|
|
{
|
|
QString str;
|
|
for(int i = 0; i <= maxPtr; ++i) {
|
|
if(i == ptr) {
|
|
str += "<b>" + formatNumber(array[i]) + "</b>";
|
|
} else {
|
|
str += formatNumber(array[i]);
|
|
}
|
|
}
|
|
ui->debugTextEdit->insertHtml(text + str + "<br />");
|
|
}
|
|
|
|
void QBrainfuck::printMemory(QList<char> array, int maxPtr, int ptr, QString text)
|
|
{
|
|
QString str;
|
|
for(int i = 0; i < maxPtr; ++i) {
|
|
if(i == ptr) {
|
|
str += "<b>" + formatNumber(array[i]) + "</b>";
|
|
} else {
|
|
str += formatNumber(array[i]);
|
|
}
|
|
}
|
|
ui->debugTextEdit->insertHtml(text + str + "<br />");
|
|
}
|