0

I am making a simple text game in pascal (a real beginner one). There is a general routine, that is repeated several times (the cycles variable, representing the levels). In the beginning of the routine there is a part where character`s name is asked. If the general repeat loop is complete or aborted at some level(1-4), the game goes back to the first sort of menu. I want the name to be asked only the first time, but, of course, I get the "variable "cycles" does not seem to be initialized" warning. Is there a way to restructure the code to avoid it? Thanks.

The code excerpt (unnecessary details left behind):

program rpg_text_game;

var
game_action:char;
name:string;
cycles:1..5;

begin
repeat
  writeln('Welcome to the game.');
  writeln('To continue press "g",'); 
  writeln('to read the license of this game press "i",');
  writeln('and to quit press "q" and "enter": ');
  readln(game_action);
   case game_action of 
   'i', 'I':
   {shows license}
  'g', 'G':
  {game begins}
  if not (cycles in [2,3,4,5]) then
  begin
    writeln('Please enter your name: ');
    readln(name);
  end;
  repeat
  cycles:=1; //is initialized here
  {actual game process - score is calculated based on *cycles* amount, that adds +1 with each tick ("if success then cycles:=cycles+1")}
  {cycles - 1,2,3,4,5}
  writeln('Do you want to try again, y/n?');
  readln(game_action);
  until(game_action='n') or (game_action='N');
until (game_action='q') or (game_action='Q');
writeln();
writeln('Press enter to quit');
readln();
end.

So, how to initialize/change the cycles variable (or even any other) to avoid that message and not to cheat by turning off the compiler hint option?

Anvbis
  • 43
  • 1
  • 8
  • 2
    Questions like this appear v. frequently on SO and the thing that they have in common is that there is a large monolithic block of code, which makes it very hard for inexperienced programmers to see how to impose any control over the flow of execution. The first thing to do is to structure the code properly by splitting it up into subroutines (read, procedures) which each perform a single function. If you were to spend 30 minutes doing that here, I think you would find it trivial to exercise the flow control you need. Try it. – MartynA Jun 01 '17 at 22:44
  • name:string=''; – Sertac Akyuz Jun 01 '17 at 23:01
  • @SertacAkyuz: That should not be necessary. I think FreePascal also intializes strings to nil (or `''`), and most Pascals "zero-out" *global* variables anyway. – Rudy Velthuis Jun 01 '17 at 23:23
  • @Rudy - Ok, then voted to close for missing [mcve]. – Sertac Akyuz Jun 01 '17 at 23:40
  • @SertacAkyuz: Why? The code is not an exact [MCVE], but close enough. – Rudy Velthuis Jun 01 '17 at 23:49
  • @Rudy because then the compiler shouldn't complain of an uninitialized global variable, but post claims it does. – Sertac Akyuz Jun 02 '17 at 03:57
  • I notice you advice what you told me to be unnecessary in your answer. I'm confused.. – Sertac Akyuz Jun 02 '17 at 04:00
  • @MartynA are not procedures used only when it is necessary to call them repeatedly and functions when you have to get a certain value? Because there are some procedures in the game (for example, exception handlers for y/Y / n/N questions, appropriate name length, and so on) and a couple of functions, mostly in the main "game process" block. I may be wrong, but why have too much division ie for a function that consists of just a single line? Won`t it bloat the code? – Anvbis Jun 02 '17 at 04:26
  • @SertacAkyuz The compiler indeed does not complain, if it did there would be an _error_ message shown and the compilation aborted. – Anvbis Jun 02 '17 at 04:30
  • 1
    Is this documented? Does fpc have documentation? Does that documentation cover declaration of globals? Would it be worthwhile you reading the documentation? Answer is the same to all four questions. – David Heffernan Jun 02 '17 at 04:54
  • "are not procedures used only when it is necessary to call them repeatedly and functions when you have to get a certain value?" Absolutely not. It's thinking like that which leads to so much of the bad code that's posted here. I often have single-line routines, e.g. to avoid repeated messes like `(game_action='n') or (game_action='N')` cluttering it up. Structure your code and apply the DRY principle. – MartynA Jun 02 '17 at 05:07
  • @MartynA Ok. Are there any general criteria of division into subroutines besides those that Rudy mentioned in the answer? Can you point me to a quality entry-level book on that subject? – Anvbis Jun 02 '17 at 07:58
  • General criteria? Single task is the main one. Reusability. Common sense. Any of Marco Cantu's books on Delphi (and his one on Object Pascal) is worth reading - and for looking at the code - it looks nothing like the code you posted in your q. – MartynA Jun 02 '17 at 08:13
  • Btw, try holding some code just far enough away that you can't read the individual lines, With well-structured code, you should find you are still able to *see* its structure and flow. Then try doing that with what you posted ... – MartynA Jun 02 '17 at 08:33
  • @MartynA Well, I guess for the first non-helloworld piece of code in my life it`s not _that_ bad, but thanks for advice anyway. – Anvbis Jun 02 '17 at 08:36
  • @Anvbis - A warning is a compiler complaining, no compiler halts compilation because of an uninitialized variable. – Sertac Akyuz Jun 02 '17 at 11:53
  • @Anvbis You do see the irrationality of your title, don't you? :) – tonypdmtr Jun 02 '17 at 16:14

2 Answers2

3

If cycles is a global variable, like in your example code, then simply do, in the main block of the program, before you start anything:

begin
  cycles := 1;
  game_action := Chr(0);
  { etc... }
  ...
end.

That is how you generally initialize global variables: in the main begin/end. block. Some versions of Pascal also allow (for global variables):

var
  cycles: 1..5 = 1;
  { etc... }

but others don't. I don't know if your Pascal allows it. If it does, you won't have to initialize in the main block anymore. But note that that probably doesn't work for local variables of a function or procedure. There, you will probably have to use the (outer) begin/end; block of the function or procedure.


FWIW, the main block of a program can usually be found at the very end of the program, after all the const, type, var, procedure and function declarations and it ends with a dot (.).

Also note that the comment is right: split your program into separate functions and procedures, each with their own single task, and pass any information necessary to them. Do not write monolithic blocks of code. That is hard to read and hard to maintain. For instance, for each (or most) of your case items, create a separate procedure with the necessary parameters and call those from your case statement. That makes your code much easier to read, also for you.

Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
  • Easy to find out the info that you don't know. FPC has documentation that is readily located. – David Heffernan Jun 02 '17 at 04:57
  • @David: did you mean me? I know where to find FPC info if I need it. But it is much easier to try, and one can learn from trying. – Rudy Velthuis Jun 02 '17 at 07:30
  • @David: trial and error is a valid way if there is a boolean choice (i.e. the language supports this feature or not) and you can't break anything. Usually much easier than trying to find something in the docs. If I play with a new language, I don't first read the docs. I see what I can do and what not. I think one can learn much more from hands-on errors than from reading (boring) docs. Only if things don't work out the way I like it, I will start reading the docs. And that point will come. – Rudy Velthuis Jun 02 '17 at 07:46
  • 1
    Thats just silly. Your knowledge will be incomplete. – David Heffernan Jun 02 '17 at 07:47
  • Yes, my knowledge will be incomplete when I start with a topic, like a new language, or a new technology, or some such. I think it is silly to first read the docs. But I will eventually read the docs, but only when I need it and have some idea what they are actually talking about. When I started with BigIntegers, I could more or less guess how to add and how to multiply and how to implement ToString, etc, so I just started. I started reading a lot of papers only when I got stuck. I would never have started if I had seen all these (extremely dry and boring, sometimes) papers first. – Rudy Velthuis Jun 02 '17 at 07:58
  • 1
    FWIW, knowledge is incomplete if you start somethig new. But it is, IMO, much more fun and also much more instructive to learn by doing (and by failing, sometimes) than to first study the docs. As they say, you don't learn from success, you learn from failing. Or do you also read the manual before you step into a, say, rented car? – Rudy Velthuis Jun 02 '17 at 08:03
  • I think you and @DavidHeffernan are both right, but the fact is, quite a large percentage of SO qs display a complete lack of debugging skills and/or knowledge of what's in the documentation. – MartynA Jun 02 '17 at 08:28
  • @MartynA: sure, and that is quite different, But I don't know everything about FPC or other Pascals, and I don't really want to either, because Delphi is my favourite, but I know enough to get around and I know where to find help (docs) when I get stuck. That seems to be the problem with many beginners, though: they don't know how to help themselves, i.e. how to debug or how to find help. – Rudy Velthuis Jun 02 '17 at 08:44
2

In the first iteration of the loop in the code as is, cycles is read (by the IF NOT (cycles in [])) before being initialized. The compiler rightfully emits a warning for that.

The solution is simple, initialize it before the first REPEAT, or if you go more object pascal style, like Rudy says.

Marco van de Voort
  • 25,628
  • 5
  • 56
  • 89