Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements and alternative display mode #2

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.o
tm
21 changes: 11 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
CC=g++
CFLAGS=-c
CXX=g++
CXXFLAGS=

all: tm
SRC=main.cpp turing_machine.cpp
OBJ=${SRC:.cpp=.o}
OUTPUT=tm

tm: main.o turing_machine.o
$(CC) main.o turing_machine.o -o tm
all: ${OUTPUT}

main.o: main.cpp
$(CC) $(CFLAGS) main.cpp
tm: ${OBJ}
${LINK.cpp} main.o turing_machine.o -o ${OUTPUT}

turing_machine.o: turing_machine.cpp
$(CC) $(CFLAGS) turing_machine.cpp
%.o: %.c
${COMPILE.cpp} -c $+ -o $@

clean:
rm -rf *.o tm
rm -rf ${OBJ} ${OUTPUT}
4 changes: 2 additions & 2 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ int main(int argc, char const *argv[]){
for (int i = 1; i < argc; ++i){
std::cout << argv[i] << ":\n";
TuringMachine t(argv[i]);
t.parseFile();
if(t.parseFile()){ continue; }
t.makeTransitionTables();
t.turingSimulator();
std::cout << "\n\n";
}
return 0;
}
}
9 changes: 9 additions & 0 deletions sample/even_zeros
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
s01010011
q0 s s r e
e 0 0 r o
o 0 0 r e
e 1 1 r e
o 1 1 r o
e _ _ - n
o _ _ - n
accept n
153 changes: 140 additions & 13 deletions turing_machine.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,140 @@
#include "turing_machine.h"

#define COUT_N(times, input){ \
for(int i_ = 0; i_ < times; i_++){ \
std::cout << input; \
} \
}

#define COUT_CENTERED(N, input, len){ \
const int padding = ((N - len) / 2); \
COUT_N(padding, ' '); \
std::cout << input; \
COUT_N((len % 2 ? padding : padding+1), ' '); \
}

std::string TuringMachine::state_id_to_name(const int &id){
for(const auto& i : state_id){
if(i.second == id){
return i.first;
}
}
return "";
}

char TuringMachine::char_id_to_symbol(const int &id){
for(const auto& i : alph_id){
if(i.second == id){
return i.first;
}
}
return '?';
}

char dir_int_to_char(const int &d){
switch(d){
case -1:
return '<';
case 0:
return '-';
case 1:
return '>';
}
return '?';
}

void TuringMachine::displayTape() {
std::cout << "\r" << tape.substr(0, ptr); // display tape contents before the pointer head
std::cout << "[" << tape[ptr] << "]"; // display tape content under the pointer head
std::cout << tape.substr(ptr + 1); // display tape contents after the pointer head
std::cout << std::flush;
usleep(200000);
switch(tape_display_mode){
case TapeDisplayMode::SINGLE_LINE:
std::cout << "\r" << tape.substr(0, ptr); // display tape contents before the pointer head
std::cout << "[" << tape[ptr] << "]"; // display tape content under the pointer head
std::cout << tape.substr(ptr + 1); // display tape contents after the pointer head
std::cout << std::flush;
usleep(200000);
break;
case TapeDisplayMode::DRAW:
// machine body
constexpr int ASSUMED_MAX_STATE_NAME_WIDTH = 13;
constexpr int MARGIN = 2;
constexpr char MACHINE_NAME[] = "TM";
constexpr int MACHINE_NAME_PADDING = (ASSUMED_MAX_STATE_NAME_WIDTH - (sizeof(MACHINE_NAME)-1) + 1) / 2;
constexpr int PIN_PADDING = (ASSUMED_MAX_STATE_NAME_WIDTH+(MARGIN*2-(2*1)))/2;
constexpr int PIN_POSITION = (ASSUMED_MAX_STATE_NAME_WIDTH+(MARGIN*2-(2*1)))/2 + MARGIN;
const int ARROW_PADDING = 2+(4*ptr);
// top
std::cout << "┏";
COUT_N(ASSUMED_MAX_STATE_NAME_WIDTH+(MARGIN*2-(2*1)), "━");
std::cout << "┓" << std::endl;
// body
std::cout << "┃ ";
COUT_CENTERED(ASSUMED_MAX_STATE_NAME_WIDTH, MACHINE_NAME, (sizeof(MACHINE_NAME)-1));
std::cout << " ┃" << std::endl;
// state
std::cout << "┃ ";
std::string state_name = state_id_to_name(present_state_id);
COUT_CENTERED(ASSUMED_MAX_STATE_NAME_WIDTH, state_name, state_name.size());
std::cout << " ┃" << std::endl;
// bottom
std::cout << "┗";
COUT_N(PIN_PADDING, "━");
std::cout << "┰";
COUT_N(PIN_PADDING, "━");
std::cout << "┛" << std::endl;
// arrow
COUT_N(PIN_POSITION - 1, ' ');
std::cout << "│" << std::endl;
if(ARROW_PADDING < PIN_POSITION){
COUT_N(ARROW_PADDING, ' ');
std::cout << "┌";
COUT_N(PIN_POSITION-ARROW_PADDING-2, "─");
std::cout << "┘" << std::endl;
}else if(ARROW_PADDING > PIN_POSITION){
COUT_N(PIN_POSITION-1, ' ');
std::cout << "└";
COUT_N(ARROW_PADDING-PIN_POSITION, "─");
std::cout << "┐" << std::endl;
}else{
COUT_N(ARROW_PADDING, ' ');
std::cout << "│" << std::endl;
}
COUT_N(ARROW_PADDING, ' ');
std::cout << "│" << std::endl;
COUT_N(ARROW_PADDING, ' ');
std::cout << "V" << std::endl;
// tape
std::cout << '+';
COUT_N(tape.size(), "---+");
std::cout << std::endl;
std::cout << '|';
COUT_N(tape.size(), ' ' << tape[i_] << " |");
std::cout << std::endl;
std::cout << '+';
COUT_N(tape.size(), "---+");
std::cout << std::endl;
// rules
for(const auto &i : state_id){
state_name = i.first;
for(int h = 0; h < state_table[i.second].size(); h++){
if(state_id_to_name(state_table[i.second][h]) == ""){ continue; }
std::cout << "δ("
<< state_name << ", "
<< char_id_to_symbol(h)
<< ") := ("
<< state_id_to_name(state_table[i.second][h]) << ", "
<< write_table[i.second][h] << ", "
<< dir_int_to_char(dir_table[i.second][h])
<< ")";
if(present_state_id == i.second && tape[ptr] == char_id_to_symbol(h)){
std::cout << "\t<";
}
std::cout << std::endl << std::endl;
}
}
// separator
COUT_N(5, std::endl);
std::cout << std::flush;
break;
}
}

int TuringMachine::parseFile() {
Expand Down Expand Up @@ -53,7 +182,7 @@ int TuringMachine::parseFile() {
void TuringMachine::makeTransitionTables(){
std::string line, present_state, next_state, tape;
char read_char, write_char, direction;
int present_state_id, next_state_id, read_char_id, dir_id;
int current_state_id, next_state_id, read_char_id, dir_id;

std::ifstream ifs;
ifs.open(file_name, std::ios:: in);
Expand All @@ -68,7 +197,7 @@ void TuringMachine::makeTransitionTables(){
iss >> read_char >> write_char >> direction >> next_state;

// find respective unique id's
present_state_id = state_id.find(present_state)->second;
current_state_id = state_id.find(present_state)->second;
next_state_id = state_id.find(next_state)->second;
read_char_id = alph_id.find(read_char)->second;
if(direction == 'l')
Expand All @@ -79,16 +208,14 @@ void TuringMachine::makeTransitionTables(){
dir_id = 0;

// populate transition tables with unique id's
state_table[present_state_id][read_char_id] = next_state_id;
write_table[present_state_id][read_char_id] = write_char;
dir_table[present_state_id][read_char_id] = dir_id;
state_table[current_state_id][read_char_id] = next_state_id;
write_table[current_state_id][read_char_id] = write_char;
dir_table[current_state_id][read_char_id] = dir_id;
}
ifs.close();
}

void TuringMachine::turingSimulator(){
int present_state_id = 0, read_char_id, dir_id = 0;

displayTape();
while(true){
read_char_id = alph_id.find(tape[ptr])->second;
Expand Down Expand Up @@ -118,4 +245,4 @@ void TuringMachine::turingSimulator(){
tape = tape + "_";
displayTape();
}
}
}
18 changes: 14 additions & 4 deletions turing_machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,26 @@ class TuringMachine {
tape; // input tape on which turing machine works
int num_states, // number of states
num_alphs, // number of alphabets
ptr; // location of pointer head of turing machine
ptr, // location of pointer head of turing machine
present_state_id = 0,
read_char_id = 0,
dir_id = 0;
std::map<std::string, int> state_id; // maps each state to a unique key
std::map<char, int> alph_id; // maps each alphabet to a unique key
std::vector<int> accept_state;
std::vector<std::vector<int>> state_table; // transition table storing next state
// for a given (present state, input char) pair
// for a given (state, input char) pair
std::vector<std::vector<int>> dir_table; // transition table storing next direction
// for a given (state, char) pair
// for a given (state, input char) pair
std::vector<std::vector<char>> write_table; // transition table storing next write char
// for a given (state, char) pair
// for a given (state, input char) pair
enum class TapeDisplayMode {
SINGLE_LINE,
DRAW
} tape_display_mode = TapeDisplayMode::SINGLE_LINE;

std::string state_id_to_name(const int &id);
char char_id_to_symbol(const int &id);
public:
TuringMachine(std::string _file_name):
file_name(_file_name),
Expand Down