PDA

View Full Version : Glitch on my game



smexhy
06-04-2012, 10:19 PM
Hello, i'm a beginner in the pascal language, knowing only the basics. I don't know any other language. I made this text based game some days ago and i was working on my code until i got a error to it... You can get the code here: http://pastebin.com/A5eQa7Hv . The problem is that the 'Continue or Menu?" phrase appears where it isnt supposed to be... i tried to check all the begin's and end's if they are at they'r place and i couldn't find any error... I just don't know why "Continue or Menu?" appears randomly and why it won't accept the input (small c or small m) due my key2 := upcase(key2) . If anyone doesnt mind compiling it and checking the error i'll be very thankful :). Thank You!

Ps: Don't mind the game for now, it's not finished, i'll fix the other "unfinished" parts of it but for now i need to get this fixed.

User137
07-04-2012, 12:19 AM
Fixed the indents, it was really difficult to read. Don't know yet what the problem place is.

program project1;

uses crt;

var
inc, rnd1 ,rnd2,jbc,sec, pris ,stats, bank, turn : integer;
key,key1,key2,key3:char;

procedure etc;
begin
writeln('Daily income: ',inc,' cash.');
writeln('Bank: ',bank);
writeln('--------------------------------------');
end;

procedure etc1;
begin
writeln('Starting day number ',turn,'.');
writeln('Bank: ',bank);
writeln('Prisoners: ',pris);
writeln('Daily income: ',inc);
writeln('Security level: ',sec);
end;

begin
repeat
sec := 0;
jbc := 7;
turn := 0;
bank := 0;
stats := 0;
pris := 2;
inc := 150;
writeln('Hello and welcome to the JailBreak game made by Sami.');
readln;
writeln('Instructions: ');
writeln('-Feed your prisoners day by day (if possible).');
writeln('-If the unsatisfied prisoners count gets over 3 your');
writeln('daily income will start to decrease.');
writeln('-You can buy a new prisoner from Menu(M) or increase');
writeln('the security system, thus decreasing canche of jailbreak');
writeln('If you get -300 cash you will lose the game.');
writeln('The goal of the game is to have 5 prisoners in less days.');
readln;
writeln('Ready to play?[press <ENTER> to start the first day.]');
readln;
{-Starting the routine-}
begin
repeat
randomize;
rnd1 := random(3);
rnd2 := random(jbc);

if (rnd1 = 1) then begin
clrscr;
turn := turn + 1;
etc1;
repeat
write(pris,' prisoners are hungry. Feed them? (Y/N): ');
readln(key);
key := upcase(key);
until (key = 'Y') or (key = 'N');

if (key = 'N') then begin
stats := stats - 2;
writeln('--------------------------------------');
writeln('The prisoners are not satisfied for today!');
writeln('Unsatisfied prisoners count: ',stats);
end;

if (key = 'Y') then begin
stats := stats + 2;
writeln('--------------------------------------');
writeln('Good job! the prisoners are fullfiled for today!');
bank := bank - 150;
writeln('-150 cash');
writeln('Satisfied prisoners count: ',stats);
bank := bank + inc;
etc;
end;
end;

if (rnd1 = 2) then begin
turn := turn + 1;
clrscr;
etc1;
repeat
write(pris-1,' prisoner is hungry. Feed him? (Y/N): ');
readln(key);
key := upcase(key);
until (key = 'Y') or (key = 'N');

if (key = 'N') then begin
stats := stats - 1;
writeln('--------------------------------------');
writeln('The prisoner is not satisfied for today!');
writeln('Unsatisfied prisoners count: ',stats);
end;

if (key = 'Y') then begin
stats := stats + 1;
writeln('--------------------------------------');
writeln('Good job! the prisoners are fullfiled for today!');
bank := bank - 100;
writeln('-100 cash');
writeln('Satisfied prisoners count: ',stats);
bank := bank + inc;
etc;
end;
end;

if (rnd1 = 3) then begin
turn := turn + 1;
clrscr;
etc1;
writeln('--------------------------------------');
write('No prisoner is hungry today, you are lucky!');
bank := bank + inc;
etc;
end;
{-Ending the routine-}

{--------------------}

{-Deciding either -inc or staying the same-}
if (stats < -3) then begin
writeln('The prisoners are very unsatisfied , income - 25');
inc := inc - 25;
end;

if (stats > -3) then begin
inc := 150;
end;
{ending -inc routine}

{-----------------------}

{starting final question before next day}
begin
repeat
key2 := ' ';
key3 := ' ';
writeln('Continue(C) or Menu(M)? : ');
readln(key2);
key2 := upcase(key2);
until (key2 = 'C') or (key2 = 'M');

{choice to continue or menu}

if (key2 = 'M') then begin
repeat
writeln('You entered the Menu, what you wish to do?');
writeln('--------------------------');
writeln('(B)uy new prisoner (-300 cash);');
writeln('(I)ncrease security (- 200 cash);');
writeln('(C)ontinue ( = cash);');
readln(key3);
key3 := upcase(key3);
until (key3 = 'B') or (key3 = 'I') or (key3 = 'C');
end;
end;
{ending menu choice}

{starting custom choice}
if (key3 = 'B') then begin
writeln('You have bought a new prisoner!');
writeln('-300 cash');
writeln('Income : + 50');
inc := inc + 50;
bank := bank - 300;
readln;
end;

if (key3 = 'I') then begin
writeln('Security system upgraded, canche of escape decreased');
writeln('-200 cash');
bank := bank - 200;
jbc := jbc + 2;
sec := sec + 1;
readln;
end;
{ending custom choice}
{end day}

{chance of escape at night}
if (rnd2 = 1) then begin
writeln('Bad Luck!One of your prisoner escaped!');
pris := pris - 1;
inc := inc - 50;
readln;
end;
{end canche}

until (pris = 5) or (bank < -300) or (pris = 0);

if pris = 0 then begin
writeln('You have no more prisoners, sorry, you lost the game!');
end;
if pris = 5 then begin
writeln('Congratulations! You won the game in ',turn,' days with 5 prisoners!');
end;
if bank < -300 then
writeln('Sorry, you lost the game (< -300 cash)');

end;

repeat
writeln('Play again? (Y/N): ');
readln(key1);
key1 := upcase(key1);
until (key = 'Y') or (key = 'N');
until (key = 'N');
end.
And.. yes, it compiles with Lazarus :)

And small sidenote that you shouldn't name variable "inc". There is a function inc() in system unit that is used to add number (default 1) to integer variable.

WILL
07-04-2012, 04:20 AM
Yeah, I'd just like to add that it's always best practice to avoid reusing ANY keywords or common language functions or you could end up having some crazy logic issues and errors in your programs. I try to think of nice alternatives myself.

For example lets say you have a record that stores what "type" of object they are, well what do you call that variable to hold that value? Type would be terrible and would most likely cause an error preventing it from compiling. Instead I would try using "kind" (real life example!) as it does not conflict with the keyword type used to define different variable types.

Oh and feel free to use the code button to post your code right in your post. :) It should work as long as it's not too long (long as in reallllllly long) User137's post is a good example of posting code of a decent size length.

Carver413
07-04-2012, 05:20 AM
Oh and feel free to use the code button to post your code right in your post. :)

What code button ? I alway's have to type all the bb codes in manually on this forum :(

smexhy
07-04-2012, 06:43 AM
Thanks User137 and Will for your time :), and i knew there was the function inc() but forgot bout it D:

WILL
07-04-2012, 07:48 AM
What code button ? I alway's have to type all the bb codes in manually on this forum :(

Ah then you never followed the directions for existing members who were migrated to the current vBulletin version of the site. :P

Click here (http://www.pascalgamedevelopment.com/faq.php?faq=vb3_user_profile#faq_vb3_other_setting s) and see how you can turn on the WYSIWYG Editor for posting here on PGD! You are interested in what is under "Miscellaneous Options".


Thanks User137 and Will for your time http://www.pascalgamedevelopment.com/images/pgdsmilies/happy.gif, and i knew there was the function inc() but forgot bout it D:

Not a problem. Starting out can seem a little daunting, but if you stick with it and don't always take the easy route you'll get all the ins and outs eventually. Taking a Computer Science class in your school will help greatly! It should cover most of the basic concepts of programming and should allow you to write code for just about any solution that can be thought up, save for the really advanced stuff.

SilverWarior
07-04-2012, 08:19 AM
After changing Inc in your code to Income the game seems to work for me. I belive there is a bug in your game thou. Everytime I increased my security one of the prisoners escaped. I tried tracking this bug but had no luck. The reason for this is that your code is badly organized. Or atleast it sems to me likeway.
So here are some recomendations for beter code organization.
1. When creatung procedures, functions etc. try to use selfexplanatory names and not etc and etc1.
2. Try to avoid writing same code in multiple parts of your program. You can do this by moving parts of code wich repeat several times into procedures. This wil make your code more readable and wil save you some time for not needint to type same code multiple types.
3. When using if conditional clauses you can check for multiple parameters if needed. Below is part of your code where you are checking the value for rnd1 and if it is either 1 or 2 you then cal virtualy the same code.

if (rnd1 = 1) then
begin
clrscr;
turn := turn + 1;
etc1;
repeat
write(pris,
' prisoners are hungry. Feed them? (Y/N): ');
readln(key);
key := upcase(key);
until (key = 'Y') or (key = 'N'); if (key = 'N') then
begin
stats := stats - 2;
writeln('--------------------------------------');
writeln('The prisoners are not satisfied for today!');
writeln('Unsatisfied prisoners count: ', stats);
end;
if (key = 'Y') then
begin
stats := stats + 2;
writeln('--------------------------------------');
writeln('Good job! the prisoners are fullfiled for today!');
bank := bank - 150;
writeln('-150 cash');
writeln('Satisfied prisoners count: ', stats);
bank := bank + income;
etc;
end;
end;
if (rnd1 = 2) then
begin
turn := turn + 1;
clrscr;
etc1;
repeat
write(pris - 1,
' prisoner is hungry. Feed him? (Y/N): ');
readln(key);
key := upcase(key);
until (key = 'Y') or (key = 'N');
if (key = 'N') then
begin
stats := stats - 1;
writeln('--------------------------------------');
writeln('The prisoner is not satisfied for today!');
writeln('Unsatisfied prisoners count: ', stats);
end;
if (key = 'Y') then
begin
stats := stats + 1;
writeln('--------------------------------------');
writeln('Good job! the prisoners are fullfiled for today!');
bank := bank - 100;
writeln('-100 cash');
writeln('Satisfied prisoners count: ', stats);
bank := bank + income;
etc;
end;
end;

This could be fixed by using one if clause and checking for two parameters like this:

if (rnd1 = 1) or (rnd1 = 2) then
begin
clrscr;
turn := turn + 1;
etc1;
repeat
write(pris,
' prisoners are hungry. Feed them? (Y/N): ');
readln(key);
key := upcase(key);
until (key = 'Y') or (key = 'N');
if (key = 'N') then
begin
stats := stats - 2;
writeln('--------------------------------------');
writeln('The prisoners are not satisfied for today!');
writeln('Unsatisfied prisoners count: ', stats);
end;
if (key = 'Y') then
begin
stats := stats + 2;
writeln('--------------------------------------');
writeln('Good job! the prisoners are fullfiled for today!');
bank := bank - 150;
writeln('-150 cash');
writeln('Satisfied prisoners count: ', stats);
bank := bank + income;
etc;
end;
end;


EDIT:
@Will
The code button is only available in Advanced mode for posting reply and not for quick reply mode. Could this be changed?

@smexhy
You can acces advanced post mode first by clicking reply inder the post and then on Go Advanced button below the text box.

WILL
07-04-2012, 06:38 PM
The code button is only available in Advanced mode for posting reply and not for quick reply mode. Could this be changed?

Sadly no, but then again, I think that was the point of the difference between quick reply and advanced. at least all you need to do is square bracket the word "code". :)

It may be possible to set yuorself to always Go Advanced. I can't be sure unless I look it up myself though.

SilverWarior
07-04-2012, 07:39 PM
After searching a bit I found a thread that say it is posible to add aditional buttons to quick reply. So since this is a programer forum I think having CODE button would be useful.
The lik to a thread: https://www.vbulletin.com/forum/showthread.php/398967-Open-quot-reply-with-quote-quot-in-Advanced-Posting?highlight=quick

smexhy
08-04-2012, 09:31 AM
Thanks Silver and everyone for your time! luckily i fixed all the bugs by myself :).
I have a question about programming in general:
So i have this readln(key) .
and it := 'F' for example.
and if i say
if (key = 'F') and (variable > 0) then begin
-syntax-
end;
it wont work like this... it will just jump to the other task even if i tell it
else if (variable > 0) then begin
writeln('You don have the enough variable');
how is this a fix?
If you don't understand me ill just post the code and you guys will see about what im talking ;\

AthenaOfDelphi
08-04-2012, 10:03 AM
Hi smexhy,

My first question... are you sure Key is equal to 'F'? (i.e. upper case F). Unless you've got caps lock on or are holding down the shift, key will be equal to 'f' (i.e. lower case F) when you press the F key.

I'm not sure there is anything else wrong with your code, but without the full context it's a bit difficult to tell.


Hope this helps

smexhy
08-04-2012, 01:37 PM
Uhh... i always do key := upcase(key) so that is not a problem. ill post in some minutes the full code and ill show you what im talking :)
PS: is there any other way to backup a program other than saving to another folder?

User137
08-04-2012, 02:33 PM
Well, you used this sort of structure a few times:

repeat
...
readln(key);
key := upcase(key);
until (key = 'Y') or (key = 'N');
if (key = 'N') then begin
...
end;
if (key = 'Y') then begin
...
end;

Whereas it should be written:

if (key = 'N') then begin
...
end
else if (key = 'Y') then begin
...
end;
Because then it will only check the first IF and ignore the other condition entirely (if 'N' was entered). In the first code it checks both codes which is extra work for CPU, and a possible cause for logic errors in program.

PS. Tested the WYSIWYG style but had to take it off because i don't know how to use it. If you start writing with code tags, how do you put cursor behind it and continue in normal font?

smexhy
08-04-2012, 03:54 PM
Well, you used this sort of structure a few times:

repeat
...
readln(key);
key := upcase(key);
until (key = 'Y') or (key = 'N');
if (key = 'N') then begin
...
end;
if (key = 'Y') then begin
...
end;

Whereas it should be written:

if (key = 'N') then begin
...
end
else if (key = 'Y') then begin
...
end;
Because then it will only check the first IF and ignore the other condition entirely (if 'N' was entered). In the first code it checks both codes which is extra work for CPU, and a possible cause for logic errors in program.

Thanks for the tip! I didnt knew about this :). Well nevermind... i fixed the whole thing by myself again D: Thank you everyone!

deathshadow
13-06-2012, 03:23 PM
Ok, got a slew of advice for you here...

With your user input checks, it is correct to use else, however on a few of those take a moment to think...



until (key = 'Y') or (key = 'N');
if (key = 'N') then begin
...
end;
if (key = 'Y') then begin
...
end;

If the until will only ever pass Y or N, and you already checked for N... you don't have to check for Y. When possible, avoid checking unneccessary values!



until (key = 'Y') or (key = 'N');
if (key = 'N') then begin
...
end else begin
{ isn't N, must be Y! }
...
end;


Also, when checking multiple values of a single variable is needed, you are better off using the CASE statement.



case key of
'N':begin
...
end;
'Y':begin
...
end;
end;


Executes faster, usually results in cleaner code.

You are storing values that are only really used once in variables... your multiple if statements for rnd1 for example could be removed and simply done as a single case statement.



case random(3) of
0:begin
{ do your feed 2, 150 }
end;
1:begin
{ do your feed 1, 100 }
end;
2:begin
{ do your no prisoner hungry }
end;
end;


Oh, and random starts at zero and does NOT include the number you declare -- since you didn'add 1 to the random(3), this:



if (rnd1 = 3) then begin


Would never run. Random(3) returns 0..2, not 1..3

As mentioned your two feed sections both basically do the same thing, just with different values, I'd put those into proceedures passing those different values.

I HIGHLY suggest not using such vague and cryptic variable names, the handful of time you save not typing as much is wasted the moment you try to debug, or ask for help... or come back to this in a year from now when you've forgotten what "jbc" even means. Since you're just starting out, I like to link beginners to an article on IBM's linux developer site:

http://www.ibm.com/developerworks/linux/library/l-clear-code/

While meant for C programmers, I believe people writing code in any language can come away with meaningful lessons from that... I'm particularly fond of the "Oh, now we're done?" part. It's a good read.

You use hyphen-lines as horizontal rules enough that I'd consider putting them into a constant, so you always have the same number.

Under the hood it's often faster to test for zero, so I'd make the game start at 300 in the bank, then have the lose condition be less than zero. Likewise I'd make the 'menu' not show options they can't afford.

Because you poll the keyboard so often and so many times, I'd suggest making a procedure to handle that. readln is cute, but it would be nicer to handle it as single keypresses and only pass when valid. A routine I've used for years takes a string of valid keypresses, and returns which one is hit, ignoring all others.



function keyPoll(values:string):char;
var
ch:char;
t:word;
begin
while keypressed do ch:=readkey; { flushes key buffer }
repeat
ch:=upcase(readkey);
for t:=1 to length(values) do begin
if ch=values[t] then begin
keyPoll:=ch;
exit;
end;
end;
until false;
end; { function keyPoll }


I always like to flush the keybuffer first so any extra presses made since the last input check are disposed of... it then just goes down the string comparing until it finds a match, returning that match. If we were to turn your 'feeding' code into it's own procedure using the above function, it ends up thus:



procedure feed(statAdjust,cost:integer);
begin
write(prisoners,' prisoners are hungry. Feed them? (Y)es or (N)o');
if keyPoll('YN')='Y' then begin
stats:=stats+statAdjust;
writeln(hrule);
writeln('Good job! the prisoners are fullfiled for today!');
dec(bank,cost);
writeln('-',cost,' cash');
writeln('Satisfied prisoners count: ',stats);
end else begin
dec(stats,statAdjust);
writeln(hrule);
writeln('The prisoners are not satisfied for today!');
writeln('Unsatisfied prisoners count: ',stats);
end;
end; { procedure feed }


As I mentioned above, we only need to check for yes, since the routine is only passing yes or no... if it's not yes...

The 'menu' could be similarly optimized. you could build a string 'compare' thus:

compare:='E';

then, you could



compare:='E';
if bank>=200 then begin
if bank>=300 then begin
writeln(' (B)uy new prisoner -300 cash');
compare:=compare+'B';
end;
writeln(' (I)ncrease security -200 cash');
compare:=compare+'I';
end else begin
writeln('You have insufficient funds to perform any actions!');
end;
writeln(' (E)xit Menu');
ch:=keyPoll(compare);
case ch of
'B':begin

etc, etc...

I took a few moments to do a quick rewrite for you, to show you what I mean.



program warden;

uses
crt;

var
income,
jailBreakChance,
security,
prisoners,
stats,
bank,
turn:integer;
key:char;

const
hRule=#13+'--------------------------------------';

function keyPoll(values:string):char;
var
ch:char;
t:word;
begin
while keypressed do ch:=readkey; { flushes key buffer }
repeat
ch:=upcase(readkey);
for t:=1 to length(values) do begin
if ch=values[t] then begin
keyPoll:=ch;
exit;
end;
end;
until false;
end; { function keyPoll }

procedure fullStats;
begin
writeln('Day number ',turn,'.');
writeln('Bank: ',bank);
writeln('Prisoners: ',prisoners);
writeln('Daily income: ',income);
writeln('Security level: ',security);
end; { procedure fullStats }

procedure feed(statAdjust,cost:integer);
begin
write(prisoners,' prisoners are hungry. Feed them? (Y)es or (N)o');
if keyPoll('YN')='Y' then begin
stats:=stats+statAdjust;
writeln(hrule);
writeln('Good job! the prisoners are fullfiled for today!');
dec(bank,cost);
writeln('-',cost,' cash');
writeln('Satisfied prisoners count: ',stats);
end else begin
dec(stats,statAdjust);
writeln(hrule);
writeln('The prisoners are not satisfied for today!');
writeln('Unsatisfied prisoners count: ',stats);
end;
end; { procedure feed }

procedure menu;
var
ch:char;
compare:string;
begin
repeat
clrscr;
writeln('Purchasing Menu');
writeln(hrule);
fullStats;
writeln(hrule);
compare:='E';
if bank>=200 then begin
if bank>=300 then begin
writeln(' (B)uy new prisoner -300 cash');
compare:=compare+'B';
end;
writeln(' (I)ncrease security -200 cash');
compare:=compare+'I';
end else begin
writeln('You have insufficient funds to perform any actions!');
end;
writeln(' (E)xit Menu');
ch:=keyPoll(compare);
case ch of
'B':begin
writeln('You have bought a new prisoner!');
writeln('-300 cash');
inc(bank,300);
writeln('+50 Income');
inc(income,50);
end;
'I':begin
writeln('Security system upgraded, chance of escape decreased');
writeln('-200 cash');
inc(bank,200);
dec(jailBreakChance,2);
inc(security);
end;
end;
until ch='E';
end; { procedure menu }

begin
repeat
security:=0;
jailBreakChance:=7;
turn:=0;
bank:=300;
stats:=0;
prisoners:=2;
income:=150;
randomize;

writeln('Hello and welcome to the JailBreak game made by Sami.');
writeln;
writeln('Instructions: ');
writeln(' 1) Feed your prisoners day by day (if possible).');
writeln(' 2) If the unsatisfied prisoners count gets over 3 your');
writeln(' daily income will start to decrease.');
writeln(' 3) You can buy a new prisoner from Menu(M) or increase');
writeln(' the security system, thus decreasing canche of jailbreak');
writeln(' 4) If you get -300 cash you will lose the game.');
writeln(' 5) The goal of the game is to have 5 prisoners in less days.');
writeln;
write('Ready to play? (Y)es or (N)o');

key:=keyPoll('YN');

if key='Y' then begin

repeat
inc(turn);
clrscr;
write('Starting ');
fullStats;

case random(3) of
0:feed(2,150);
1:feed(1,100);
2:begin
writeln(hrule);
write('No prisoner is hungry today, you are lucky!');
end;
end;

inc(bank,income);

if (stats<-3) then begin
writeln('The prisoners are very unsatisfied , income -25');
dec(income,25);
end else begin
income:=150;
end;

if random(jailBreakChance)=0 then begin
writeln('Bad Luck! One of your prisoner escaped!');
dec(prisoners);
inc(income,50);
end;

writeln(hrule);

repeat
write('(M)enu, (C)ontinue or (E)xit?');
key:=keyPoll('MCE');
if key='M' then menu;
until (key='C') or (key='E');
writeln;

until (prisoners>=5) or (prisoners<=0) or (bank<=0) or (key='E');

writeln(hrule);

if prisoners<=0 then begin
writeln('You have no more prisoners, sorry, you lost the game!');
end else if prisoners>=5 then begin
writeln('Congratulations! You won the game in ',turn,' days with 5 prisoners!');
end else if bank<=0 then begin
writeln('Sorry, you went bankrupt!');
end else begin
writeln('Aborting Game');
end;

writeln;
write('Play again? (Y)es or (N)o');
key:=keyPoll('YN');

end;

until key='N';

writeln;
writeln('Exiting game');

end.


I'll also attach it as a download... annoying though that this site's not set up to recognize .pas, .pp or .dpr :D