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