classes, functions, or ???

Pages: 123
3 of us have come up with more or less similar good faith and fairly comprehensive responses. My interest now is to see what @Peter87 has to offer seeing he knows more about what's on your mind than even you do. He's had his bitch about terminology so it's now wide open to let us all see his talents in action without further input from you.


technically speaking, you had the bitch about terminology first.

@georgep I will be doing just that, drawing a map. That's something I had planned on doing anyway, after I got a proof-of-concept down as I'm still learning.

And before I post this code, I will reiterate that I am still learning and already have a few ideas on how to improve things. What I still am trying to decide on is how best to store the dialog "trees" and trigger them, which hopefully y'all can offer some insight after seeing what I have.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include <iostream>
#include <chrono>
#include <thread>

// wait time in seconds between dialog lines. format is Wait(seconds);
void Wait(int WaitTime) {
    std::this_thread::sleep_for(std::chrono::seconds(WaitTime));}

int main(){

std::cout << "<>\\\\: There are a number of cores here.";
Wait(5);

std::cout << "\n<>\\\\: They are the same size thanks to standardization practices of the manufacturer,";
Wait(5);

std::cout << "\n<>\\\\: but I know for a fact that they may not be the same grade of power.";
Wait(5);

std::cout << "\n<>\\\\: If I put the wrong core into the wrong machine...";
Wait(5);

std::cout << "\n<>\\\\: ...I guess I don't know what will happen. Presumably some damage, or maybe nothing at all.";
Wait(5);

std::cout << "\n<>\\\\: I don't want to take that chance. I'm not a mechanic, but I think we can figure this out.";
Wait(5);

std::cout << "\n<>\\\\: Engineers are usually obsessed with manuals and charts... Where could they be on this ship...?" << std::endl;
std::cout << std::endl;
Wait(5);

std::cout << "1. <>//: There may be a nearby closet with books and manuals in it." << std::endl;
std::cout << "2. <>//: Isn't there a computer or something with information on this?" << std::endl;
std::cout << "3. <>//: Do the cores have anything written on them?" << std::endl;
std::cout << "4. <>//: Maybe try looking at each machine for clues..." << std::endl;

std::cout << std::endl;

std::cout << "<>//: "; //
int answer1{0};
std::cin >> answer1;

switch(answer1){

    case 1: // eventually will replace text execution with file or object execution
        std::cout << "<>//: There may be a nearby closet with books and manuals in it." << std::endl;
        Wait(5);
        std::cout << "<>\\\\: Books?" << std::endl;
        Wait(5); // following line will replace previous prompt
        std::cout << "<>//: My fault for asking. Isn't there a computer or something with information on this?" << std::endl;
        Wait(5);
        std::cout << "<>\\\\: It's a ship, of course there is." << std::endl;
        Wait(5);
        std::cout << "<>\\\\: The terminal in the hangar requires a credential, and I don't know it." << std::endl;
        break;

    case 2: // eventually will replace text execution with file or object execution
        std::cout << "<>//: Just try one and see what happens." << std::endl;
        Wait(5);
        std::cout << "<>\\\\: ... Okay. I'm not new to explosions," << std::endl;
        Wait(5);
        std::cout << "<>\\\\: but planning on possibly being in the middle of one is new to me." << std::endl;
        break; // random one in seven chance of death

    case 3: // eventually will replace text execution with file or object execution
        std::cout << "<>//: Do the cores have anything written on them?" << std::endl;
        Wait(5);
        std::cout << "<>\\\\: The capsules are devoid of any instructions," << std::endl;
        Wait(5);
        std::cout << "<>\\\\: except for what I think are model numbers or something..." << std::endl;
        break; // eventually: "execute associated branch"

    case 4: // eventually will replace text execution with file or object execution
        std::cout << "<>//: Maybe try looking at each machine for clues..." << std::endl;
        Wait(5);
        std::cout << "<>\\\\: I'll check out the Hyena." << std::endl;
        Wait(5);
        std::cout << "<>\\\\: The storage arm is still attached," << std::endl;
        Wait(5);
        std::cout << "<>\\\\: so give me a few minutes to climb up there." << std::endl;
        break;

    default:
        std::cout << "<>//: ";
        int answer1{};
        std::cin >> answer1;
        break;

    }

// functions of switch statement

std::cout << std::endl;
std::cout << "//To be continued//";

return 0;
}

// need some sort of branching mechanism. at each switch statement, result is to run a new section of code as a branch,
// and not individual statements or text. otherwise branching won't work I think. can use this mechanism to return to
// areas or replay code sections with new information, or some answers are dead ends. 


and all this being said, I'll also reiterate that I can make this work. I know a way to make the trees, I just don't know the best way or better ways, and I haven't found anything really related to this exact scenario. The only way I know how immediately to make the tree is to store the dialogs in functions in the main() or above the main() and call the functions through the main() as the story progresses. But I suspect that it's not the best way, which is why I'm here.

So to support my further understanding of coding, is it wise to store large amounts of information above or below the main() and use the main() to call that information, or should I only be using the main() to call information from other dedicated files?
Last edited on
Reminds me of the old Infocom interactive fiction games.

"Leather Goddesses of Phobos", "Deadline", "Zork I", "II" & "III" amongst others.

"Bureaucracy" was especially wickedly annoying and fun.

What you've written so far reminds me of "Planetfall."
never played them, but I know how text adventures work and I love creative writing, so what better way to learn some code along the way. fun so far.
Programming a game is a good way to learn C++. You have fun playing it at each stage of the process, and asking here you can learn different ways of doing your game mechanics.

I am by no means an expert, but I do remember all the pitfalls and problems I've run across mashing up some code.

Learning/using C++20 modules and std::format currently and it has been an especially "bang your head on the desk repeatedly" frustrating process.
Is there a reason why you don't use std::array or std::vector ?
They would make your code much easier.
pitfalls and problems I've run across


Yeah! I remember moving from printf() (and its variants) to streams. For fiddly formatting I still revert to printf() et al. Moving to std::format() is like revisiting an old friend who's just changed a bit over the years... Things that were dead easy in printf() suddenly took on a complexity worthy of Einstein!

PS Were any of the committee members involved in stream syntax related to Grace Hopper by any chance?


Last edited on
std::format is more powerful than printf - line bools are printed as strings by default, int can be printed as binary, output can be centered. Yo also can print your custom types...

Here's a quick overview by Marc Gregoire - author of "Professional C++"
https://www.youtube.com/watch?v=IdM0Z2a4fjU
std::format may be more powerful than printf, but currently it has one rather annoying defect that for is frustrating and cryptic.

A malformed format string doesn't cause compile-time warnings or errors. It fails at run-time, causing a crash if not using try/catch.

{:5} works, {5} goes *BOOM!*
And learning to work with modules was frustrating because with Visual Studio (2019 & 2022) there is a difference between an interface file (.cppm or .ixx) and an implementation file (.cpp). If VS compiles a .cpp implementation module file as an interface lots of errors up the wazoo.

The module file type default is interface.

The implementation file type has to be manually changed in the IDE to a "internal partition" file type to be properly compiled.

It took me several days (and lots of manual changes to a project's files) to figure this out.
Is there a reason why you don't use std::array or std::vector ?
They would make your code much easier.


More than likely because my understanding of the best methods is still elementary. But that’s why I’m here. In what way could I use those to make this easier, by assigning dialogs to array or vector locations and calling them that way?
@George P

Wow, I’m looking at std::format(). I wish I had learned this first. So the defect you mentioned, is that something being fixed eventually, or just a consequence of the way the tool is structured? I’d like to try my hand at using it, probably be banging my head against the wall as well.
This stuff is literally just a few months old, so betting the tools have a bug or 3 is not a bad guess.
If C++ is by committee design, it’s likely to take a while to solve as well. But looking forward to things to come is nice anyway.
Its not that. This is c++20 and long out of committee, and its been sort of out there in 'beta' for a while as well, but its still new and the compiler writers could have a few mistakes here and there, or there may be places where it performs poorly, etc. And as precise as they try to be, sometimes something is still misunderstood.
Last edited on
std::format is C++20, so it is still new-ish. There is a defect report submitted to make a malformed format string a compile-time error, so it will/should be fixed. Eventually.

https://en.cppreference.com/w/cpp/utility/format/format#Defect_reports

There is at least one subtle difference between printf and std::format, printing out a memory address. This difference is where I first learned about the run-time defect.

Using C's printf was easy, use the "%p" format specifier:
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <cstdio>

int main()
{
	// declare variables 
	int   a { };
	float b { };
	char  c { };

	printf("Address of a: %p\n", &a);
	printf("Address of b: %p\n", &b);
	printf("Address of c: %p\n", &c);
}
Address of a: 00DAFB7C
Address of b: 00DAFB70
Address of c: 00DAFB67

Using std::format:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import <iostream>;
import <format>;

int main()
{
	// declare variables 
	int   a { };
	float b { };
	char  c { };

	std::cout << std::format("Address of a: {:p}\n", (void*) &a);
	std::cout << std::format("Address of b: {:p}\n", (void*) &b);
	
	// note the lack of format specifier!  p is default!
	std::cout << std::format("Address of c: {}\n", (void*) &c);
}
Address of a: 0xeffec8
Address of b: 0xeffebc
Address of c: 0xeffeb3

Of course the addresses you see will be different, possibly different on each run.

There is a lot about C++ to learn. C++11 started the notion of "Modern C++" and continues on to for now C++20.
Learning to use modules was a major source of frustration, though the problems were compile-time. Not run-time as happens with std::format.

Converting old-style header/source files to custom modules isn't all that hard once I understood the peculiarities of using modules vs. header/source files was ironed out.
Looking at std::array and std::vector. I’ve gone through these before in a class and understand the concept, but I’m not understanding the application in this regard. As far as I know, you can’t go storing huge amounts of text in array or vector locations, but I could store function references, which contain the information I think. I could substitute my switch cases for an std::array, but I’m not sure how it would be more efficient.
Last edited on
I was thinking about sth. like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <array>
#include <chrono>
#include <thread>

// wait time in seconds between dialog lines. format is Wait(seconds);
void Wait(int WaitTime) 
{
  std::this_thread::sleep_for(std::chrono::seconds(WaitTime));
}
    
const std::array intro = 
{
  "<>\\\\: There are a number of cores here.",
  "\n<>\\\\: They are the same size thanks to standardization practices of the manufacturer,",
  "\n<>\\\\: but I know for a fact that they may not be the same grade of power.",
  "\n<>\\\\: If I put the wrong core into the wrong machine...",
  "\n<>\\\\: ...I guess I don't know what will happen. Presumably some damage, or maybe nothing at all.",
  "\n<>\\\\: I don't want to take that chance. I'm not a mechanic, but I think we can figure this out.",
  "\n<>\\\\: Engineers are usually obsessed with manuals and charts... Where could they be on this ship...?"
};

int main()
{
  for (const char *s : intro)
  {
    std::cout << s ;
    Wait(5);
  }
}
You can indeed store "lots" of text (or other data) in a std::array or std::vector, up to whatever memory your OS will allow.

One of the biggest benefits is memory management. std::vector stores its elements on the heap, AKA the free store, instead of the stack and does all the messy details of memory management for you. Using a regular array would require manual memory management that can be prone to memory leaks and other issues.

There are additional reasons why using a C++ container could have advantages over a regular array, one of them being iterators.

A std::array or std::vector can safely be passed to a function without decaying to a pointer, unlike a regular array.

A std::array is compile-time fixed size, and allocates elements on the stack. You can allocate on the free store if you want, though.

A std::vector is a dynamic container, you can resize on demand at run-time as needs for space change.

As your experience and understanding of C++ grows, understanding why using C++ constructs like std::array/std::vector can be more efficient though using them can require a radical new way of thinking.

Too much available information on the 'net and in books teaches old ways of doing things. Not that the old ways are necessarily inefficient, C++ changed and added features. std::format, for instance.

Using <random> instead of the C library to generate random numbers is another. Using srand/rand, though, is inefficient, and has serious distribution problems.

https://web.archive.org/web/20180123103235/http://cpp.indi.frih.net/blog/2014/12/the-bell-has-tolled-for-rand/
Pages: 123