Using Composite Pattern to make game menu - c++

I'm making a game menu using a composite pattern. I want to achieve a tree structure game menu, where some leaves are pushing new state on the top of my state machine and another in options should show for example slider to change the volume without making new state and another (exit) should close the game by running sfml method.
Can someone give me a better idea than returning string or enum by operation() method to menu state to run expected action by using value in if/switch?

Here is an example of a menu state table using a struct:
typedef void (*Function_Pointer)(); // Declares a synonym for Function_Pointer
struct Table_Entry
{
char expected_selection;
char * prompt;
Function_Ptr processing_function;
};
// Forward declarations
void Turn_On_Lights();
void Turn_Right();
void Open_Treasure();
// State table
static const Table_Entry menu1[] =
{
{'1', "Turn on lights", Turn_On_Lights},
{'2', "Turn right (pivot)", Turn_Right},
{'3', "Open Treasure", Open_Treasure},
};
static size_t menu_entry_quantity =
sizeof(menu1) / sizeof(menu1[0]);
void Display_Menu()
{
for (unsigned int i = 0, i < menu_entry_quantity; ++i)
{
std::cout << menu1[i].expected_selection
<< ". "
<< menu1[i].prompt
<< "\n";
}
std::cout << "Enter selection: ";
}
void Execute_Menu_Selection(char selection)
{
for (unsigned int i = 0, i < menu_entry_quantity; ++i)
{
if (selection == menu1[i].expected_selection)
{
(*menu1[i].processing_function)();
break;
}
}
}
The above code allows you to change the quantity of entries or the entry content, without having to retest the functions. (Nice)
Since the data is static constant, it can be accessed directly and doesn't need to be initialized before the program starts.
You can expand this by using a "transition" column or member. For example, list the next states (or menus) to transition to when given a transition ID.

Related

How to reset number of instances of a class to 1 on every loop iteration?

I have a player class where I am storing the player's current position, the number of players in the game and a static variable to store the total number of players like so:
#ifndef PLAYER_H
#define PLAYER_H
#include <ctime>
#include <random>
#include <iostream>
using std::time;
using std::cout;
class Player
{
private:
int m_Player_currentPosition, m_Player_number;
static int m_Player_numberOfPlayers;
public:
Player::Player():m_Player_currentPosition(1) {
m_Player_number = m_Player_numberOfPlayers;
++m_Player_numberOfPlayers;
}
void m_Player_SetPosition();
int m_Player_GetPosition();
int m_Player_GetPlayerNumber() { return m_Player_number; }
void m_Player_SetNumberOfPlayers() { m_Player_numberOfPlayers = 1; }
~Player() { --m_Player_numberOfPlayers; }
};
int Player::m_Player_numberOfPlayers = 1;
#endif
I also have a game class that creates a certain number of player instances using a vector. In my game class, the plan is to create players depending on user input (between 2-4 number of players) using m_Game_SetPlayers() member function and also printing the details of the players using the m_Game_PrintPlayers() member function.
#ifndef GAME_H
#define GAME_H
#include <iostream>
#include "Board.h"
#include "Player.h"
using std::cout;
using std::cin;
using std::vector;
class Game {
private:
bool m_Game_quit;
int m_Game_choice;
Board board;
vector<Player> m_Game_players;
public:
Game();
const bool &m_Game_GetQuit() const;
void m_Game_SetPlayers()
{
int numberOfPlayers = 2;
cout << "How many players (2-4)? ";
cin >> numberOfPlayers;
if (numberOfPlayers < 2 || numberOfPlayers > 4) {
numberOfPlayers = 2;
}
m_Game_players.resize(numberOfPlayers);
}
void m_Game_PrintMenu();
void m_Game_PrintInstructions();
void m_Game_GetChoice();
void m_Game_PrintPlayers()
{
cout << '\n';
vector<Player>::iterator iter;
for (iter = m_Game_players.begin(); iter != m_Game_players.end(); ++ iter) {
cout << "Player " << iter->m_Player_GetPlayerNumber() << "'s position: " << iter-
>m_Player_GetPosition() << '\n';
}
}
void Update();
};
#endif // !GAME_H
However, in my main class, I am calling the Game class's update function under a while loop. Here is my game update member function declared in a separate implementation file that decides the control flow of the game.
void Game::Update()
{
m_Game_GetChoice();
switch (m_Game_choice) {
case 0: cout << "---Bye---\n";
m_Game_quit = true;
break;
case 1:
system("cls");
m_Game_PrintInstructions();
break;
case 2:
system("cls");
m_Game_SetPlayers();
system("cls");
board.m_Board_PrintBoard();
m_Game_PrintPlayers();
m_Game_players[0].m_Player_SetNumberOfPlayers();
break;
default:
cout << "--Invalid Option---\n";
break;
}
}
Here is my while loop in the main function:
#include "Game.h"
int main() {
Game game;
while (!game.m_Game_GetQuit()) {
system("cls");
game.m_Game_PrintMenu();
game.Update();
system("pause");
}
}
When I ran this program the first time, it worked as expected. However, imagine if I choose the play option from the menu and I enter 2 players, it creates 2 instances of the player class. On the next while loop iteration, I increase the size to 4 players which also works perfectly sometimes. Then, when I reduce the size and then again increase the size, the player number does not match. Here are the following images to help understand the problem:
Input 1: https://i.stack.imgur.com/reHjE.png
Output 1: https://i.stack.imgur.com/Dt68V.png
Input 2: https://i.stack.imgur.com/Xo83c.png
Output 2: https://i.stack.imgur.com/2Qso6.png
The expected output is:
Player's position 1: 1
Player's position 2: 1
Player's position 3: 1
So, I thought that I need to delete my instances, but since I cannot delete instances on a stack memory as long as I am in a while loop (How do I manually delete an instance of a class?, http://www.cplusplus.com/forum/beginner/107822/). I thought that I will resize the vector. It did resize the vector, but then it does not delete the instances of the player class but instead created a new instance of that class. Is there a way to destroy all the instances of the class on a stack memory even when it is inside the scope? If not, how do I solve this problem?
I may/may not have provided the code needed to debug this problem. So, I have attached my entire code on https://github.com/F3INTH34RTED/Cpp/tree/master/Beginner/16SnakesAndLadder if need be.
When you increase the size of the vector, say from 2 to 3, it only needs to create one new instance of Player, so it will create a single player with the next number.
The line
m_Game_players[0].m_Player_SetNumberOfPlayers();
on the previous loop iteration sets the global counter to 1. So this single new player gets number 1, not number 3 like you expect. You should be able to remove the above line and things will work as expected.
On a design note, it would probably be wiser to recreate the vector entirely when the number of players is changed and explicitly give each player a number via the constructor, like this:
void m_Game_SetPlayers()
{
int numberOfPlayers = 2;
cout << "How many players (2-4)? ";
cin >> numberOfPlayers;
if (numberOfPlayers < 2 || numberOfPlayers > 4) {
numberOfPlayers = 2;
}
m_Game_players.clear();
for (int i = 1; i < numberOfPlayers; i++) {
m_Game_players.push_back(Player(i));
}
}
Updating the Player constructor to match, of course.
Your issue is that std::vector::push_back will do copy/move when it needs to resize internal buffer, and your (auto generated default) copy/move constructors doesn't handle that, you might do for example:
class Player
{
private:
int m_currentPosition;
std::optional<int> m_number;
static int m_numberOfPlayers;
public:
Player() : m_currentPosition(1), m_number(++m_numberOfPlayer) {}
Player(const Player&) = delete;
Player(Player&& rhs) : m_currentPosition(rhs.m_currentPosition), m_number(rhs.m_number) { rhs.m_number = std::nullopt; }
Player& operator = (const Player&) = delete;
Player& operator = (Player&& rhs) { std::swap(m_currentPosition, rhs.m_currentPosition); std::swap(m_number, rhs.m_number); }
int GetPlayerNumber() const { return *m_number; }
~Player() { if (m_number) --m_numberOfPlayers; }
};

Pointers with cout in C++

I am in the process of learning C++ and SDL, and when I tried to print the content of an array I ran into some confusion. I have an array with two values in it, 2 and 3. When I want to print the values like this:
int* test = myApp.countDivisions(5);
std::cout << "Horizontal: " << *test<< std::endl;
std::cout << "Vertical: " << *(test+1) << std::endl;
I get:
Horizontal: -858993460
Vertical: -858993460
But when I write:
int* test = countDivisions(5);
int foo = *(test);
int boo = *(test+1);
std::cout << "Horizontal: " << foo << std::endl;
std::cout << "Vertical: " << boo << std::endl;
I get:
Horizontal: 2
Vertical: 3
I am confused as to why this happens. If anyone could explain why this behaviour happens, it would be great! I am aware that I should not be using C arrays in C++, but I am still interested in understanding what is happenning here!.
Edit: I modified a typo in the first example.
Also I got asked what my countDivisions(int) function does so here is the entire code:
#include <iostream>
#include <SDL.h>
class SDLApplication {
private:
//This is the window of the application:
SDL_Window* AppWindow;
//This is the surface displayed by the window:
SDL_Surface* WindowSurface;
SDL_Renderer* Renderer;
//This is the name of the App:
std::string AppName;
//These are the dimensions of the window displaying the App
int WindowWidth;
int WindowHeight;
public:
SDLApplication(std::string name) {
AppWindow = NULL;
WindowSurface = NULL;
AppName = name;
WindowHeight = 0;
WindowWidth = 0;
Renderer = NULL;
}
int* countDivisions(int divisions) {
//This helper functions takes as input the number of divisions on the screen and returns an array that tells
//us how many horizontal and vertical divisions we have, assuming we divide linearly starting from the right corner.
int horizontal = 0;
int vertical = 0;
int i = 0;
int divTemp = pow(2,i);
int divCount = divTemp;
int temp;
while (divCount < divisions) {
if (i % 2 == 0) {
//Our power of two is pair, so we are adding horizontal divisions
horizontal += divTemp;
}
else {
//Our power of two is odd, so we are adding vertical divisions
vertical += divTemp;
}
++i;
divTemp = pow(2,i);
temp = divCount + divTemp;
if ( temp> divisions) {
if (i % 2 == 0) {
//Our power of two is pair, so we are adding horizontal divisions
horizontal += divisions-divCount;
}
else {
//Our power of two is odd, so we are adding vertical divisions
vertical += divisions-divCount;
}
}
divCount =temp;
}
int result[] = { horizontal, vertical };
return result;
}
}
int main(int argc, char* argv[])
{
SDLApplication myApp("SDL_Test");
int* test = myApp.countDivisions(5);
std::cout << "Horizontal: " << *test << std::endl;
std::cout << "Vertical: " << *(test + 1) << std::endl;
return 0;
}
I think printing *int is undefined behaviour - it is kind of meaningless. This expression is a type. Its a bit like saying "where is human" rather then "where is the human called bob" (ok, bit of a rubbish analogy), a type does not have an address on its own.
Your second example int* test is a variable named test which has a type of int* (pointer to an integer). You set the value of the pointer test to something (whatever myApp.countDivisions(5); returns - you should tell us what that returns).
Then:
int foo = *(test);
int boo = *(test+1);
foo is an integer variable that you set to the value of what test points to - and not the address itself. boo is set to the contents of the next address (address of test + 1).
If you want to print the address of the pointers you should do:
std::cout << "Horizontal: " << test << std::endl;
If you want to print the value of what the pointer is pointing to you should do:
std::cout << "Horizontal: " << *test << std::endl;
This is called dereferencing. See this little example: https://godbolt.org/z/CzHbq6
update: updated as per question update
You are returning a pointer to a local variable called result. That variable is destroyed at the end of your countDevisions() function, which will lead to undefined behaviour (which you are seeing) meaning anything can happen!. See here for an example of that with the warnings printed out: https://godbolt.org/z/gW2XS4
"A" fix for that is to change the scope of result by making its lifetime the entire life of the program, this can be done by making it static. Note I do this for demonstration only - this is not a good solution, but see it here working: https://godbolt.org/z/goQJzx
Perhaps a better solution would be to return a container from the standard template library (STL) like std::vector (something like an array): https://godbolt.org/z/3DOyhq
Or perhaps (after reading your code properly) you don't really even want an array, it seems you just want two values: vertical and horizontal. So you could define your own struct and use that - this seems more optimal: https://godbolt.org/z/RmUM39. This also makes more sense to the user of your function by being able to reference horizontal/vertical by name and not by some array index.
TLDR: "turn on warnings" and search for "c++ return multiple values"
You need to include iostream and define three classes, and fix two additional typos.
#include <iostream>
typedef int SDL_Window;
typedef int SDL_Surface;
typedef int SDL_Renderer;
This results in code that gives a useful warning message, which tells you that SDLApplication::countDivisions returns the address of a local variable or temporary. As you later attempt to use that temporary object which has gone out of scope, the result is, not surprisingly, undefined behavior.
Your function returns multiple values. You could have created an std::tuple object, but I would just define a struct so you can return one value, with named members.
struct Divisions {
int horizontal;
int vertical;
};
class SDLApplication {
...
Divisions countDivisions(int divisions) {
...
return Divisions{ horizontal, vertical };
}
};
see also
Return multiple values to a method caller
Returning multiple values from a C++ function

How to invoke a method across instances in C++

I have two instances of a class Robot. When I run some method (say, go()) I want every instance to go if it is on a correct frequency. Example (for simplicity everything is in one file):
class Robot {
int freqency_from;
int freqency_to;
bool is_going = false;
bool isOnFrequency(int frequency) {
return (frequency >= frequency_from && frequency <= frequency_to);
}
public:
Robot(int _freqency_from , int _freqency_to) {
freqency_from = _freqency_from;
freqency_to = _freqency_to;
}
void go(int frequency) {
if (isOnFrequency(frequency)) {
is_going = true;
}
}
bool isGoing() {
return is_going;
}
};
int main() {
Robot robot1 = Robot(1, 3);
Robot robot2 = Robot(3, 5);
cout << robot1.isGoing(); // false
cout << robot2.isGoing(); // false
Robot::go(1); // should be run for each and every instance of the Robot class
cout << robot1.isGoing(); // true
cout << robot2.isGoing(); // false
return 0;
}
How to make this pseudo-code work? Is it even possible without making a vector of all instances of Robot and mapping over it?
What about a regular old loop? Just store your robots in a container and iterate over it.
vector<Robot> robots;
robots.emplace_back(1, 3);
robots.emplace_back(3, 5);
for (auto& robot : robots)
{
cout << robot.isGoing();
robot.go(1);
cout << robot.isGoing();
}
Robot::go(1);
should be run for each and every instance of the Robot class
not really, go is not a static method...
you need an instance like robot1 or robot2 in order to command that robot,
if you want to do that all the robots react to the go function then declare then
consider defining that method static

C++ Struct defined data passing. Simple answer im sure

I am sure this is a very simple fix and I feel dumb asking it but here it goes.
I need help with a struct and passing info from a gather function to a save or set function, and then passing it again to another function for further use.
Basically, it looks like this to start. I'll just add short snips of the code. All can be provided if you would like to see it.
I right now am just looking for the proper way to pass struct defined data from get.... to set.... functions.
struct printype
{
char dots[8][15];
int unknown15; // can have values of 0..127
string serial11_14; // 8 characters 00000000...99999999
int year8; // without century, 0..99
int month7; // 1..12
int day6; // 1..31
int hour5; // 0..23
int minute2; // 0..59
};
int getunknown15(); // prototypes
int setunknown15(int);
then we have a simple main.
int main()
{
printype pt;
pt.unknown15=getunknown15();
pt.unknown15=setunknown15(12);
pt.serial11_14=getserial11_14();
pt.serial11_14=setserial11_14("12345678");
pt.year8=getyear8();
pt.year8=setyear8(44);
pt.month7=getmonth7();
pt.month7=setmonth7(11);
pt.day6=getday6();
pt.day6=setday6(12);
pt.hour5=gethour5();
pt.hour5=sethour5(12);
pt.minute2=getminute2();
pt.minute2=setminute2(23);
cout <<"-----------------------------------------------------"<<endl;
cout <<" Let's Get Started"<<endl;
cout <<"-----------------------------------------------------"<<endl;
setup(pt.dots); // sets up the array
dpinfo(pt); // prints out the final array
ftarray(pt);
spar(pt.dots);
darray(pt.dots);
}
and finally the get and set array functions.
int getunknown15()
{
printype tem;
cout <<"-----------------------------------------------------"<<endl;
cout <<" Enter the Unkown Variable (0-127): ";
cin >>tem.unknown15;
cout <<"-----------------------------------------------------"<<endl;
return tem.unknown15;
}
next is
int setunknown15(int tem)
{
printype pp;
if (tem>127||tem<0)
{
cout << "Error" << endl;
return 0;
}
else
{
pp.unknown15 = tem;
return pp.unknown15;
}
}
I hope this isn't too much to read and understand
Anyway, I know this has a really simple answer but my brain just isn't working right now.
Edit: As StilesCrisis stated, Send struct as parameter is quiet stupid in this case. better use a const reference.
Well, I am not sure if I understand your question correctly. You can simply send struct to another function as parameter, or as a pointer.
like:
void SetStruct(const printype& var);
printype GetStruct();
Is it what you are looking for?
Please use the following access to the your fields, (by reference):
struct printype *myPtr = new printype;
myPtr->day6 = 43;
When use pointer instead of a normal variable, you should use -> instead . to access your fields.
I know this is kind of old but I thought I should give it a shot, since you are using C++ and it looks like you are trying to use some OO practices (I think), you don't need to start with a struct, even though OO principles can be applied using them as well though not as elegantly.
you can define your class header file as such.
#ifndef PRINTYPE_H
#define PRINTYPE_H
#include <string>
using namespace std;
class printype
{
private: // we always want to declare our member fields private for safety/managements reasons, no one will be able to access them outside.
char dots[8][15];
int unknown15; // can have values of 0..127
string serial11_14; // 8 characters 00000000...99999999
int year8; // without century, 0..99
int month7; // 1..12
int day6; // 1..31
int hour5; // 0..23
int minute2; // 0..59
void init(); // This is the method we use to initialize our starting state.
public: // This is our public methods, how people deal with/get/set our state.
printype(); // This is our default constructor
printype(const printype& print_type); // This our copy constructor
virtual ~printype(); // This is our destructor, its virtual, making safer for inheritance.
// This is our setters/getters
void setUnknown(int unknown);
int getUnknown();
void setYear(int year);
int getYear();
void setMonth(int mont);
int getMonth();
// and well you get the idea, you can add more methods.
};
#endif
and the accompanying class source file with your functions implementation
printype::printype()
{
this->init(); // Initialize all your vatiables, safer to just define a function to this.
}
printype::printype(const printype& orig) // copy constructor
{
this->setUknown(orig.getUnknown());
this->setDay(orig.getDay());
this->setDots(orig.getDots());
// you get the idea ...
}
printype::~printype()
{
// Have anything you need to do before destroying the object.
}
void printype::init()
{
this->setUnknwon(0);
this->setyear(0);
this->setMonth(1);
char dots[8][15] = {'\0'};
this->setDots(dots);
// you get the idea, you want to initialize all your variables since, for the most part they initially hold garbage.
}
void printype::setUnknown(int unknown)
{
if (unknown >= 0 && unknown < 127)
this->unknown15 = unknown;
else
error("Expecting unknown to be between 0 and 127"); // error should probably print the error and/or exit(-1) up to u
}
int printype::setYear(int year)
{
if (year >= 1 && year <= 99)
this->year8 = year;
else
error("Expecting year between 0 and 99"); // you may want to implement an error function!
}
int printype::getYear()
{
return this->year8;
}
void printype::setDots(char dots[8][15])
{
// you may want to do some verifications
memcpy(this->dots, dots, sizeof(dots));
}
void printype::setDots(char **dots) // this is a bit unsafe, use at your own risk.
{
if (dots)
{
unsigned int index = 0;
for (index = 0; index < 8; index++)
if (dots[index])
memcpy(this->dots[index], dots[index], 15);
else
error("dots required pointer ...");
}
else
error("dots required pointer ...");
}
char **getDots() // We will be returning a copy, we don't want the internal state to be affected, from outside, by using reference or pointers.
{
char **dots = new char*[8];
unsigned int index = 0;
for (index = 0; index < 8; index++)
{
dots[index] = new char[15];
memcpy(dots[index], this->dots[index], 15);
}
return dots;
}
// and well you get the idea ...
to use your class
printype *print_type_p = new print_type();
// or
printype pront_type_p();
// use the different public method to update the internal state.
print_type_p->setYear(3);
// or
print_type.setYear(3);
print_type_p->getYear();
// and so on.

How to efficiently structure a terminal application with multiple menus?

I'm writing a console based program for my coursework, and am wondering how best to structure it so that it is both stable and efficient. I currently have
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
int choice;
do
{
cout << "\E[H\E[2J" // Clear the console
<< "Main menu" << endl << endl
<< "Please select one of the following options by entering it's "
<< "number in the prompt below and pressing [ENTER]. "
<< endl << endl
<< "1. Pay my bill as a guest" << endl
<< "3. Log in" << endl
<< "2. Create an account" << endl
<< "4. Quit program" << endl;
cin >> choice;
switch (choice)
{
case 1: // Pay the bill as a guest to the system
case 2: // Log in to the system
case 3: // Create an account with the system
case 4: // Quit the program
default: // Prompt the user to choose again
}
} while !(default);
// Await user input to terminate the program
cout << "Please press [ENTER] to continue...";
cin.get();
return 0;
}
The purpose of the above code is to provide a list of options for the user to choose from, with the do-while loop working alongside the default statement in the switch to catch any unexpected input. Each case would call a function that presented another menu with it's own list of options, which would be structured using the same do-while, switch method. My concern is that as my program grows, the number of function calls being nested within other functions is going to increase, so that I would eventually end up with a function being called from within a function being called from within a function and so on. This would obviously have severe implications for the maintainability of the program, with the function calls moving further and further away from main(), and the output of these functions weaving a tangled path about the program.
Is it possible to structure my program in such a way as to return execution to main() as often as possible, or is the problem described above simply a consequence of this kind of programming?
NB: I ask this question in the understanding that user-defined functions are supposed to be ancillary to main(), and that they should perform a task before returning control to main() as the earliest possible convenience. I've only been at this a couple of months now so please bear with my ignorance/misunderstanding. Also, ignore any potential compiler errors in the code, I've not tested it yet and it's only provided as an aide to my conceptual question.
I would apply some OO-design and create a menu-class which basically stores items/sub-menus in a vector. This would make it easy to extemd to hierarchical menus
There is nothing particularly wrong with what you've done.
I don't see why it harms maintainability to have functions called from functions and so on. If anything it AIDS maintainability as you can move common code operations into seperate functions. This way you make a fix in one place and instantly fix the rest of the places its used as well.
Well, you can implement your menu structure as a state-machine, so you will be almost always in your main loop. But this can bring your code to the lower level, because you will be effectively programming not in C++ but in your state-machine processor-near code. If your state machine will be good enough, this is not a problem.
Or you can a simple menu-runner class, which will output as a result a request for submenu, so you will just exchange (perhaps using a stack) the description of the currently running menu.
By the way, I don't see any problems in deep nesting of the functions.
Another possible approach is to make a class defined as a list of (menu_option, function) pairs and the know-how to turn them into menus. Then the function can be a call to another class instance's menu or it can do some operation on your database. That lets you keep your data organized away from the business "how to display this menu" logic and add menus and menu items easily.
Don't worry about that or your current approach spending too much time away from main though. As you've structured it, your program won't automatically turn itself into a horrible mess just because you're calling functions from functions. More functions will tend to add to maintainability, as long as you keep them focused.
Think of it this way: a function does one thing, but at a higher level of abstraction than its body. So main() runs your program. create_account() will create an account, which is part of running the program. create_account itself calls several other things that do the building blocks necessary for creating an account. Is determining the new account's name one thing? It goes in its own function. Determining the index of the new account in the database? Too low-level. Put it in the "stuff it in the database" function.
The complexity of the code will correlate to the functionality offered by the program. I would not worry about this right now, revisit refactoring once you have two or three hundred lines.
for use this code you must add:
st_menues[cnt].pos = cnt;
st_menues[cnt].function_pointer = tmp_func;
strcpy_s(st_menues[cnt].menu_string, "kharid");
memcpy(st_menues[cnt++].layer, "100000", sizeof(st_menues[cnt].layer));
this block code for insert menu item .
for change item to subitem you must change:
"100000"
to
"010000"
for do a difference work per every item you must define multiple:
void tmp_func(char* str)
void tmp_func1(char* str)
void tmp_func2(char* str)
...
and insert in
st_menues[cnt].function_pointer = tmp_func1;
...
st_menues[cnt].function_pointer = tmp_func2;
...
and insert your source code in these functions.
this source can compile in vc++.
i didn't test its in linux . but perhups works.
#include <iostream>
#include <stdio.h>
#include <conio.h>
#include<stdlib.h>
char title_str[20] = " main menu \n";
void print_this(bool with_title,const char* str, ...)
{
if(with_title)printf(title_str);
printf(str);
}
void clear()
{
#ifdef _WIN32
system("cls");
#else
std::cout << "\033[2J\033[1;1H";
#endif
print_this(true,"");
}
struct def_struct_menu
{
void (*function_pointer)(char*);
char menu_string[24];
char layer[7];
int pos;
};
void set_title(char* str)
{
sprintf(title_str," %s \n",str);
}
void tmp_func(char* str)
{
clear();
set_title(str);
printf("calc okokok");
_getch();
}
def_struct_menu st_menues[100] = { 0 };
def_struct_menu st_cur_menues[100] = { 0 };
void back_to_main_menu(int& highlight_line, int& cur_layer, int& start)
{
highlight_line = 0;
cur_layer = 0;
start = 0;
set_title((char*)"main menu");
}
int main()
{
int cnt = 0;
st_menues[cnt].pos = cnt;
st_menues[cnt].function_pointer = tmp_func;
strcpy_s(st_menues[cnt].menu_string, "kharid");
memcpy(st_menues[cnt++].layer, "100000", sizeof(st_menues[cnt].layer));
{
st_menues[cnt].pos = cnt;
st_menues[cnt].function_pointer = tmp_func;
strcpy_s(st_menues[cnt].menu_string, "asan");
memcpy(st_menues[cnt++].layer, "010000", sizeof(st_menues[cnt].layer));
st_menues[cnt].pos = cnt;
st_menues[cnt].function_pointer = tmp_func;
strcpy_s(st_menues[cnt].menu_string, "shenase");
memcpy(st_menues[cnt++].layer, "010000", sizeof(st_menues[cnt].layer));
}
st_menues[cnt].pos = cnt;
st_menues[cnt].function_pointer = tmp_func;
strcpy_s(st_menues[cnt].menu_string, "sharj");
memcpy(st_menues[cnt++].layer, "100000", sizeof(st_menues[cnt].layer));
{
st_menues[cnt].pos = cnt;
st_menues[cnt].function_pointer = tmp_func;
strcpy_s(st_menues[cnt].menu_string, "ramz");
memcpy(st_menues[cnt++].layer, "010000", sizeof(st_menues[cnt].layer));
{
st_menues[cnt].pos = cnt;
st_menues[cnt].function_pointer = tmp_func;
strcpy_s(st_menues[cnt].menu_string, "yekbarmasraf");
memcpy(st_menues[cnt++].layer, "001000", sizeof(st_menues[cnt].layer));
st_menues[cnt].pos = cnt;
st_menues[cnt].function_pointer = tmp_func;
strcpy_s(st_menues[cnt].menu_string, "qrcode");
memcpy(st_menues[cnt++].layer, "001000", sizeof(st_menues[cnt].layer));
}
st_menues[cnt].pos = cnt;
st_menues[cnt].function_pointer = tmp_func;
strcpy_s(st_menues[cnt].menu_string, "mostaghim");
memcpy(st_menues[cnt++].layer, "010000", sizeof(st_menues[cnt].layer));
}
const int ST_SIZE = cnt;
int input = 0;
int highlight_line = 0;
int cur_layer = 0;
int start = 0;
while (input != -1)
{
int size = 0;
memset(st_cur_menues, 0, sizeof(def_struct_menu) * ST_SIZE);
for (int i = start; i < ST_SIZE; i++)
{
if (cur_layer > 0)
{
if (st_menues[i].layer[cur_layer - 1] == '1')
{
break;
}
}
if (st_menues[i].layer[cur_layer] == '1')
{
memcpy(&st_cur_menues[size++], &st_menues[i], sizeof(def_struct_menu));
}
}
clear();
if (size == 0)
{
back_to_main_menu(highlight_line, cur_layer, start);
}
for (int i = 0; i < size; i++)
{
if (highlight_line == i)
print_this(false,"*");
else
print_this(false," ");
print_this(false,st_cur_menues[i].menu_string);
print_this(false,"\n");
}
//print_this("enter number\n");
input = _getch();
switch (input)
{
case 'x':
{
exit(0);
}
case 27://escape button
{
back_to_main_menu(highlight_line, cur_layer, start);
break;
}
case 13://enter button
{
if (size == 0)
{
back_to_main_menu(highlight_line, cur_layer, start);
break;
}
st_cur_menues[highlight_line].function_pointer(st_cur_menues[highlight_line].menu_string);
start = st_cur_menues[highlight_line].pos + 1;
cur_layer++;
highlight_line = 0;
}
break;
case 72://up arrow key
{
if (highlight_line == 0)
highlight_line = (size - 1);
else
highlight_line--;
}
break;
case 80://down arrow key
{
if (highlight_line == (size - 1))
highlight_line = 0;
else
highlight_line++;
}
break;
default:
break;
}
}
return 0;
}
tnx