Initial commit
This commit is contained in:
commit
19e609e3b0
7 changed files with 339 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
build
|
13
.vscode/c_cpp_properties.json
vendored
Normal file
13
.vscode/c_cpp_properties.json
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Win32",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/**"
|
||||||
|
],
|
||||||
|
"cppStandard": "c++17",
|
||||||
|
"cStandard": "c17"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
53
example1.cpp
Normal file
53
example1.cpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "turing.cpp"
|
||||||
|
#include "utils/operators.cpp"
|
||||||
|
#include "utils/print.cpp"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto def = new Turing::Definition<char, char> {
|
||||||
|
.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<char, char>(def);
|
||||||
|
turing->setTape("0010110100"_v);
|
||||||
|
|
||||||
|
print(turing);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (i++ < 100) {
|
||||||
|
if (!turing->tick()) break;
|
||||||
|
print(turing);
|
||||||
|
}
|
||||||
|
|
||||||
|
print(turing);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
44
example2.cpp
Normal file
44
example2.cpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "turing.cpp"
|
||||||
|
#include "utils/print.cpp"
|
||||||
|
|
||||||
|
enum values {
|
||||||
|
yes = 1,
|
||||||
|
no = 0,
|
||||||
|
blank = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto def = new Turing::Definition<char, values> {
|
||||||
|
.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;
|
||||||
|
}
|
185
turing.cpp
Normal file
185
turing.cpp
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Turing {
|
||||||
|
|
||||||
|
// Available movements on the turing machine
|
||||||
|
enum Movement {
|
||||||
|
left = false,
|
||||||
|
right = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Turing instruction
|
||||||
|
template <typename S, typename V>
|
||||||
|
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 <typename S, typename V>
|
||||||
|
struct Definition {
|
||||||
|
S defaultState;
|
||||||
|
V defaultValue;
|
||||||
|
std::vector<Instruction<S, V>> instructions;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The Turing Machine
|
||||||
|
template <typename S, typename V>
|
||||||
|
class Machine
|
||||||
|
{
|
||||||
|
|
||||||
|
const Definition<S, V>* definition;
|
||||||
|
|
||||||
|
int position = 0; // current position
|
||||||
|
S state; // current state
|
||||||
|
std::vector<V> 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<V>(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<S, V>* 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<V>& 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<S, V>* 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
|
25
utils/operators.cpp
Normal file
25
utils/operators.cpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include "../turing.cpp"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Replaces provided string with appriopriate Turing::Instruction<char, char>
|
||||||
|
* it takes 'l' character as a left move
|
||||||
|
*/
|
||||||
|
constexpr Turing::Instruction<char, char> 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<char, char>(cS, cV, nS, nV, mv);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Replaces provided string with aprriopriate vector<char>
|
||||||
|
const std::vector<char> operator ""_v (const char* txt, const size_t len) {
|
||||||
|
auto rvalue = std::vector<char>(len);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
rvalue[i] = *txt++;
|
||||||
|
}
|
||||||
|
return rvalue;
|
||||||
|
}
|
18
utils/print.cpp
Normal file
18
utils/print.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "../turing.cpp"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prints debug-like information about provided machine
|
||||||
|
*/
|
||||||
|
template <typename S, typename V>
|
||||||
|
void print(Turing::Machine<S, V>* 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";
|
||||||
|
}
|
Reference in a new issue