commit 19e609e3b0dc2a9abe7de4888eaaf74683c9c121 Author: Wroclaw Date: Sat Nov 26 05:03:22 2022 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..e6fe5d1 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,13 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${workspaceFolder}/**" + ], + "cppStandard": "c++17", + "cStandard": "c17" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/example1.cpp b/example1.cpp new file mode 100644 index 0000000..4a8013b --- /dev/null +++ b/example1.cpp @@ -0,0 +1,53 @@ +#include +#include + +#include "turing.cpp" +#include "utils/operators.cpp" +#include "utils/print.cpp" + +int main() { + auto def = new Turing::Definition { + .defaultState = '0', + .defaultValue = '#', + .instructions = { + // Palindrome checker + // if the last state is R or 0, then it is a palindrome + // otherwise it is not + "00a0r"_i, + "01b1r"_i, + + "a0a0r"_i, + "a1a1r"_i, + "b0b0r"_i, + "b1b1r"_i, + + "a#A#l"_i, + "b#B#l"_i, + + "A0r#l"_i, + "B1r#l"_i, + + "r0r0l"_i, + "r1r1l"_i, + "r#R#r"_i, + + "R00#r"_i, + "R10#r"_i, + }, + }; + + auto turing = new Turing::Machine(def); + turing->setTape("0010110100"_v); + + print(turing); + + int i = 0; + while (i++ < 100) { + if (!turing->tick()) break; + print(turing); + } + + print(turing); + + return 0; +} \ No newline at end of file diff --git a/example2.cpp b/example2.cpp new file mode 100644 index 0000000..fa8f7b3 --- /dev/null +++ b/example2.cpp @@ -0,0 +1,44 @@ +#include + +#include "turing.cpp" +#include "utils/print.cpp" + +enum values { + yes = 1, + no = 0, + blank = 6, +}; + +int main() { + auto def = new Turing::Definition { + .defaultState = 'a', + .defaultValue = values::blank, + .instructions = { + // multiply binary represented number by 2 + Turing::Instruction('a', values::yes, 'a', values::yes, Turing::Movement::right), + Turing::Instruction('a', values::no, 'a', values::no, Turing::Movement::right), + Turing::Instruction('a', values::blank, 'b', values::no, Turing::Movement::right), + } + }; + + auto turing = new Turing::Machine(def); + + turing->setTape({ + values::no, + values::no, + values::yes, + values::no, + values::yes, + values::no, + values::yes, + values::no + }); + + print(turing); + std::cout << '\n'; + + while(turing->tick()); + + print(turing); + return 0; +} diff --git a/turing.cpp b/turing.cpp new file mode 100644 index 0000000..540763f --- /dev/null +++ b/turing.cpp @@ -0,0 +1,185 @@ +#include + +#pragma once + +namespace Turing { + +// Available movements on the turing machine +enum Movement { + left = false, + right = true, +}; + +// Turing instruction +template +struct Instruction { + S currentState; + V currentValue; + S nextState; + V nextValue; + Movement tapeMovement; + + constexpr Instruction(const S cS, const V cV, const S nS, const V nV, Movement tM) { + this->currentState = cS; + this->currentValue = cV; + this->nextState = nS; + this->nextValue = nV; + this->tapeMovement = tM; + } + + Instruction() = default; +}; + +// Configuration of the Turing machine +template +struct Definition { + S defaultState; + V defaultValue; + std::vector> instructions; +}; + +// The Turing Machine +template +class Machine +{ + +const Definition* definition; + +int position = 0; // current position +S state; // current state +std::vector memory; // aka tape +int memoryStart = 0; // the position of the beginning of the saved memory + +V& value() { + this->ensure(position); + return this->memory[position - memoryStart]; +} + +public: + +unsigned int runCount = 0; + +S getState() { return this->state; } + +int getPosition() {return this->position; } + +auto getMemory() { return std::vector(this->memory); } + +// returns position of the behind last saved element in the saved memory +int getMemoryEnd() { return this->memoryStart + this->memory.size(); } + +int getMemoryStart() { return this->memoryStart; } + +Machine(const Definition* definition) { + this->definition = definition; + this->state = definition->defaultState; +} + +/** + * @brief Ensures that provided position is saved in memory and avaliable. + * + * @param pos the position + * @return true if changes were made, false otherwise + */ +bool ensure(const int pos) { + if (pos >= this->memoryStart && pos < this->getMemoryEnd()) return false; + + // if ensuring pos is after memory ending + if (pos >= this->getMemoryEnd()) { + this->memory.insert( + this->memory.end(), + this->getMemoryEnd() - pos + 1, + this->definition->defaultValue + ); + } + + // if ensuring pos is before memory ending + if (pos < this->memoryStart) { + this->memory.insert( + this->memory.begin(), + this->memoryStart - pos, + this->definition->defaultValue + ); + this->memoryStart = pos; + } + + return true; +} + +/** + * @brief Ensures that current position is saved in memory and available + * + * @return true if changes were made, false otherwise + */ +bool ensure() { return this->ensure(this->position); } + +/** + * @brief sets the value at given position + */ +void set(const V& value, int pos) { + this->ensure(pos); + this->memory[pos - this->memoryStart] = value; +} + +/** + * @brief Gets state from the memory + * + * @param pos from which position get the value from + */ +V& at(int pos) { + this->ensure(pos); + return this->memory[pos - this->memoryStart]; +} + +/** + * @brief Set the saved memory by copying values from the provided vector + * + * @param newTape vector of new memory values + * @param position the position of the head after loading the memory, default 0 (the beginning) + */ +void setTape(const std::vector& newTape, int position = 0) { + this->memoryStart = 0; + this->memory = newTape; + this->position = position; +} + +/** + * @brief do tick() for n times + * + * @return the ammount of remaining ticks after halting + */ +unsigned int tickFor(const unsigned int times) { + unsigned int i = times; + while (i > 0 && this->tick()) i--; + return i; +} + +/** + * @brief evaluate what happens in the machine after one tick and check if the machine is halted + * + * @return false if halted, true if work has been done + */ +bool tick() { + V& value = this->value(); + Turing::Instruction* thatInstruction = nullptr; + for(auto i : this->definition->instructions) { + if (value == i.currentValue & this->state == i.currentState) { + thatInstruction = &i; + break; + } + } + + if (thatInstruction == nullptr) return false; + + this->set(thatInstruction->nextValue, this->position); + this->state = thatInstruction->nextState; + + thatInstruction->tapeMovement == Movement::right ? this->position++ : this->position--; + this->runCount++; + + return true; +} + +}; // class Machine + +} // namespace Turing diff --git a/utils/operators.cpp b/utils/operators.cpp new file mode 100644 index 0000000..0873c3d --- /dev/null +++ b/utils/operators.cpp @@ -0,0 +1,25 @@ +#include + +#include "../turing.cpp" + +/** + * @brief Replaces provided string with appriopriate Turing::Instruction + * it takes 'l' character as a left move + */ +constexpr Turing::Instruction operator ""_i (const char* txt, const size_t len) { + char cS = *txt++; + char cV = *txt++; + char nS = *txt++; + char nV = *txt++; + Turing::Movement mv = *txt++ == 'l' ? Turing::Movement::left : Turing::Movement::right; + return Turing::Instruction(cS, cV, nS, nV, mv); +}; + +// Replaces provided string with aprriopriate vector +const std::vector operator ""_v (const char* txt, const size_t len) { + auto rvalue = std::vector(len); + for (int i = 0; i < len; i++) { + rvalue[i] = *txt++; + } + return rvalue; +} diff --git a/utils/print.cpp b/utils/print.cpp new file mode 100644 index 0000000..3f7cb9f --- /dev/null +++ b/utils/print.cpp @@ -0,0 +1,18 @@ +#include + +#include "../turing.cpp" + +/** + * @brief Prints debug-like information about provided machine + */ +template +void print(Turing::Machine* machine) { + machine->ensure(); + std::cout << "rc:" << machine->runCount << ", st:" << machine->getState() << '\n'; + for (int i = machine->getMemoryStart(); i < machine->getMemoryEnd(); i++) + std::cout << (machine->at(i)); + std::cout << '\n'; + for (int i = machine->getMemoryStart(); i < machine->getPosition(); i++) + std::cout << ' '; + std::cout << "^\n\n"; +} \ No newline at end of file