QBrainfuck/qbrainfuck.cpp

359 lines
11 KiB
C++
Raw Normal View History

2014-08-12 10:50:10 +00:00
#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();
2014-08-13 15:58:49 +00:00
ui->programTextEdit->setPlainText("");
ui->debugTextEdit->setHtml("");
2014-08-12 10:50:10 +00:00
// First pass : find decades/steps
2014-08-13 20:53:13 +00:00
QList<unsigned char> decades; // Store the decades for initial loop
2014-08-12 10:50:10 +00:00
decades.append(0);
2014-08-13 20:53:13 +00:00
QList<unsigned char> memory; // Store the program's memory
memory.append(0);
QList<unsigned char> steps; // Store the steps to construct the program
2014-08-12 10:50:10 +00:00
2014-08-13 15:58:49 +00:00
QString debugNumbers;
QString debugChars;
2014-08-12 10:50:10 +00:00
QByteArray::const_iterator textIterator;
for (textIterator = text.constBegin(); textIterator != text.constEnd(); ++textIterator) {
int max_diff = ui->maxSignsSpinBox->value()+1;
2014-08-13 20:53:13 +00:00
QList<unsigned char>::iterator index;
2014-08-12 10:50:10 +00:00
// Find nearest memory's case and store it
2014-08-13 20:53:13 +00:00
QList<unsigned char>::iterator memoryIterator;
for (memoryIterator = memory.begin(); memoryIterator != memory.end(); ++memoryIterator) {
if (qAbs(*memoryIterator-*textIterator) < max_diff) {
max_diff = qAbs(*memoryIterator-*textIterator);
index = memoryIterator;
2014-08-12 10:50:10 +00:00
}
}
2014-08-13 20:53:13 +00:00
// Add step and insert current value in the memory, else add a decade if we don't find a case nearer than max_diff
2014-08-12 10:50:10 +00:00
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());
2014-08-13 20:53:13 +00:00
memory.append(*textIterator);
2014-08-12 10:50:10 +00:00
}
2014-08-13 15:58:49 +00:00
// Add current char to debug (with corresponding ASCII value)
debugNumbers += formatNumber(*textIterator);
debugChars += "&nbsp;&nbsp;&nbsp;" + QString(*textIterator);
2014-08-12 10:50:10 +00:00
}
2014-08-13 15:58:49 +00:00
2014-08-12 10:50:10 +00:00
qSort(decades);
// Second pass : write program
QString program = "";
2014-08-13 15:58:49 +00:00
ui->debugTextEdit->insertHtml("# The message<br /><br />" + QString(text) + "<br /><br /># In ASCII<br /><br />" + debugNumbers + "<br />" + debugChars + "<br /><br /># The memory<br /><br />");
2014-08-13 20:53:13 +00:00
for (int i = 0; i < ui->decadesSpinBox->value(); ++i) {
2014-08-12 10:50:10 +00:00
program += "+";
}
program += "\[";
2014-08-13 20:53:13 +00:00
QList<unsigned char>::iterator decadesIterator;
2014-08-12 10:50:10 +00:00
for (decadesIterator = decades.begin()+1; decadesIterator != decades.end(); ++decadesIterator) {
program += ">";
2014-08-13 20:53:13 +00:00
for (int i = 0; i < *decadesIterator; i+=ui->decadesSpinBox->value()) {
2014-08-12 10:50:10 +00:00
program += "+";
}
}
2014-08-13 20:53:13 +00:00
for (int i = 0; i < decades.size()-1; ++i) {
2014-08-12 10:50:10 +00:00
program += "<";
}
program += "-]";
2014-08-13 15:58:49 +00:00
// Print initial loop to debug
QString debugText;
2014-08-13 20:53:13 +00:00
for (int multiplier = 0; multiplier <= ui->decadesSpinBox->value(); ++multiplier) {
2014-08-13 15:58:49 +00:00
debugText += "&nbsp;&nbsp;<b>" + formatNumber(ui->decadesSpinBox->value()-multiplier) + "</b>";
2014-08-13 20:53:13 +00:00
for (int i = 1; i < decades.length(); ++i) {
2014-08-13 15:58:49 +00:00
debugText += formatNumber(decades[i]/ui->decadesSpinBox->value()*multiplier);
}
debugText += "<br />";
}
debugText += "<br />";
ui->debugTextEdit->insertHtml(debugText);
2014-08-12 10:50:10 +00:00
int prev_ptr = 0;
2014-08-13 20:53:13 +00:00
QList<unsigned char>::const_iterator stepsIterator;
2014-08-12 10:50:10 +00:00
textIterator = text.constBegin();
for (stepsIterator = steps.constBegin(); stepsIterator != steps.constEnd(); ++stepsIterator) {
int next_ptr = decades.indexOf(*stepsIterator);
2014-08-13 20:53:13 +00:00
if (next_ptr > prev_ptr) {
for (int i = 0; i < next_ptr-prev_ptr; ++i) {
2014-08-12 10:50:10 +00:00
program += ">";
}
} else {
2014-08-13 20:53:13 +00:00
for (int i = 0; i < prev_ptr-next_ptr; ++i) {
2014-08-12 10:50:10 +00:00
program += "<";
}
}
2014-08-13 20:53:13 +00:00
if (*textIterator > *stepsIterator) {
for (int i = 0; i < *textIterator-*stepsIterator; ++i) {
2014-08-12 10:50:10 +00:00
program += "+";
}
} else {
2014-08-13 20:53:13 +00:00
for (int i = 0; i < *stepsIterator-*textIterator; ++i) {
2014-08-12 10:50:10 +00:00
program += "-";
}
}
program += ".";
prev_ptr = next_ptr;
decades[next_ptr] = *textIterator;
2014-08-13 15:58:49 +00:00
// Print current memory and current letter
2014-08-13 20:53:13 +00:00
printMemory(decades, next_ptr, "&nbsp;" + QString(*textIterator));
2014-08-13 15:58:49 +00:00
2014-08-12 10:50:10 +00:00
++textIterator;
}
ui->programTextEdit->setPlainText(program);
2014-08-13 15:58:49 +00:00
ui->debugTextEdit->insertHtml("<br /><br /># The program<br /><br />" + program);
2014-08-12 10:50:10 +00:00
}
void QBrainfuck::on_decodeButton_clicked()
{
ui->textTextEdit->setPlainText("");
2014-08-13 15:58:49 +00:00
ui->debugTextEdit->setHtml("");
2014-08-12 10:50:10 +00:00
int ptr = 0;
2014-08-13 20:53:13 +00:00
QByteArray program = ui->programTextEdit->document()->toPlainText().toLatin1();
2014-08-12 10:50:10 +00:00
QByteArray input = ui->inputLineEdit->text().toLatin1();
QByteArray::const_iterator inputIterator = input.constBegin();
2014-08-13 20:53:13 +00:00
QList<unsigned char> memory;
QMap<int,int> correspondingBraces;
QStack<int> loopStack;
memory.append(0);
2014-08-12 10:50:10 +00:00
2014-08-13 20:53:13 +00:00
for (int i = 0; i < program.size(); ++i) {
switch (program.at(i)) {
case '[':
loopStack.push(i);
break;
case ']':
if(loopStack.isEmpty()) {
QMessageBox::critical(this, "QBrainfuck error", "Error: Unmatched end of loop");
return;
}
int old_i = loopStack.pop();
correspondingBraces.insert(i, old_i);
correspondingBraces.insert(old_i, i);
break;
}
}
if(!loopStack.isEmpty()) {
QMessageBox::critical(this, "QBrainfuck error", "Error: Unmatched begin of loop");
return;
}
for (int i = 0; i < program.size(); ++i) {
switch (program.at(i)) {
2014-08-12 10:50:10 +00:00
case '>':
2014-08-13 15:58:49 +00:00
++ptr;
2014-08-13 20:53:13 +00:00
if(ptr == memory.size()) {
memory.append(0);
2014-08-12 10:50:10 +00:00
}
break;
case '<':
2014-08-13 15:58:49 +00:00
--ptr;
2014-08-12 10:50:10 +00:00
if (ptr < 0) {
2014-08-13 20:53:13 +00:00
QMessageBox::critical(this, "QBrainfuck error", "Error: Pointer went under 0");
return;
2014-08-12 10:50:10 +00:00
}
break;
case '+':
2014-08-13 20:53:13 +00:00
++memory[ptr];
2014-08-12 10:50:10 +00:00
break;
case '-':
2014-08-13 20:53:13 +00:00
--memory[ptr];
2014-08-12 10:50:10 +00:00
break;
case '.':
2014-08-13 20:53:13 +00:00
ui->textTextEdit->insertPlainText(QString(memory.at(ptr)));
2014-08-12 10:50:10 +00:00
break;
case ',':
2014-08-13 20:53:13 +00:00
memory[ptr] = *inputIterator;
2014-08-13 15:58:49 +00:00
++inputIterator;
2014-08-12 10:50:10 +00:00
break;
case '[':
2014-08-13 20:53:13 +00:00
if (memory.at(ptr) == 0) {
i = correspondingBraces.value(i);
}
2014-08-12 10:50:10 +00:00
break;
case ']':
2014-08-13 20:53:13 +00:00
if (memory.at(ptr) != 0) {
i = correspondingBraces.value(i);
2014-08-12 10:50:10 +00:00
}
break;
}
}
}
void QBrainfuck::on_motifButton_clicked()
{
QString motif = ui->motifTextEdit->document()->toPlainText();
QByteArray program = ui->programTextEdit->document()->toPlainText().toLatin1();
if (motif.contains(QRegExp(">|<|\\+|-|\\.|,|\\[|\\]"))) {
2014-08-13 20:53:13 +00:00
QMessageBox::critical(this, "QBrainfuck error", "Error: Motif contains Brainfuck characters");
2014-08-12 10:50:10 +00:00
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;
}
2014-08-13 20:53:13 +00:00
if (dialog.selectedNameFilter() == "Json Files (*.json)") {
2014-08-12 10:50:10 +00:00
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");
}
2014-08-13 15:58:49 +00:00
2014-08-12 10:50:10 +00:00
}
}
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());
}
}
2014-08-13 15:58:49 +00:00
QString QBrainfuck::formatNumber(int number)
{
2014-08-13 20:53:13 +00:00
if (number < 10) {
2014-08-13 15:58:49 +00:00
return "&nbsp;&nbsp;&nbsp;" + QString().setNum(number);
} else if (number < 100) {
return "&nbsp;&nbsp;" + QString().setNum(number);
} else {
return "&nbsp;" + QString().setNum(number);
}
}
2014-08-13 20:53:13 +00:00
void QBrainfuck::printMemory(QList<unsigned char> memory, int ptr, QString text)
2014-08-13 15:58:49 +00:00
{
QString str;
2014-08-13 20:53:13 +00:00
for (int i = 0; i < memory.size(); ++i) {
if (i == ptr) {
str += "<b>" + formatNumber(memory[i]) + "</b>";
2014-08-13 15:58:49 +00:00
} else {
2014-08-13 20:53:13 +00:00
str += formatNumber(memory[i]);
2014-08-13 15:58:49 +00:00
}
}
ui->debugTextEdit->insertHtml(text + str + "<br />");
}