Author Topic: Here's a good game:  (Read 3510 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Here's a good game:
« on: June 21, 2019, 04:24:12 pm »
What's wrong with this code?

Code: QB64: [Select]
  1. $LET TOGGLE = FALSE
  2.  
  3.  
  4.  
  5. 'DEFLNG A-Z
  6. SCREEN _NEWIMAGE(640, 480, 32) 'A default screen, the size specified.
  7.  
  8. P = _PIXELSIZE: IF P = 0 THEN P = 2 '0 is a designation for text screens, which use 2 bytes per character for memory storage
  9. ScreenSize = _WIDTH * _HEIGHT * P
  10. Frames = 48 'In our animation
  11. UncompressedStringSize = Frames * ScreenSize 'the total size needed to store all the animation images, uncompressed (Should be about 48 MB)
  12. UncompressedString$ = SPACE$(UncompressedStringSize) 'a placeholder for the whole animation, uncompressed.
  13. SingleScreen$ = SPACE$(ScreenSize) 'a placeholder for a single screen worth of info
  14.  
  15. f = _LOADFONT("OLDENGL.TTF", 32)
  16.  
  17. m = _MEMIMAGE(0)
  18.  
  19.  
  20. $IF TOGGLE = TRUE THEN
  21.     UncompressedString$ = ""
  22.  
  23. FOR i = 1 TO 48 'let's draw a cheesy animation demo
  24.     LOCATE 1, 400 - i * 8
  25.     PRINT "Steve is Awesome."
  26.     _MEMGET m, m.OFFSET, SingleScreen$ 'Get one screen of information
  27.     $IF TOGGLE = TRUE THEN
  28.         UncompressedString$ = UncompressedString$ + SingleScreen$
  29.     $ELSE
  30.         MID$(UncompressedString$, (i - 1) * ScreenSize + 1, ScreenSize) = SingleScreen$ 'And put it in the proper place for storage
  31.     $END IF
  32.     _LIMIT 10
  33.  
  34.  
  35. PRINT "Press <ANY KEY> to view the cheesy animation."
  36.  
  37. SLEEP 'and now a pause so we can restore our animation
  38.  
  39. FOR i = 0 TO 47
  40.     temp$ = ""
  41.     temp$ = MID$(UncompressedString$, i * ScreenSize + 1, ScreenSize)
  42.     _MEMPUT m, m.OFFSET, temp$
  43.     _LIMIT 10
  44.  

Cobalt was wanting some advice on how to compress and store an animation in a single string over here: https://www.qb64.org/forum/index.php?topic=1444.msg106409#new

Working up a demo for him wasn't that much work, using the zlib libraries as the compression tool, but it did end up giving me one odd glitch which I can't explain at all.  Take a look at the code above and see if you can figure out what the BLEEP breaks it.

First, run it as is, and you'll see that it works as intended.  We capture the screen info 48 times, and save it into a single string, which we later use to help reproduce our cheesy animation.

Then, change the TOGGLE value to TRUE (first line of code), and run it again.  Notice how the results are completely different after the lucky 13th frame.

Now, what the BLEEP is broken???

****************************

When TOGGLE is FALSE (works), we preallocate the memory for the whole string and replace each screen of information manually.

When TOGGLE is TRUE (bugged), we start with a blank string and then simply add each new screen's data to that string.

The end result should end up with both methods generating the exact same string, but obviously something is different once we get around frame 14, or so.

So here's the game -- See if you can figure out WTH is wrong with the second method, and explain it to us.  First one to solve the mystery gets bragging rights and a highlighted "Best Answer" on this topic! 

Play now, and YOU can be a big wiener!!
« Last Edit: June 21, 2019, 04:54:33 pm by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Here's a good game:
« Reply #1 on: June 21, 2019, 05:18:59 pm »
What's wrong with this code?

Code: QB64: [Select]
  1. $LET TOGGLE = FALSE
  2.  
  3.  
  4.  
  5. 'DEFLNG A-Z
  6. SCREEN _NEWIMAGE(640, 480, 32) 'A default screen, the size specified.
  7.  
  8. P = _PIXELSIZE: IF P = 0 THEN P = 2 '0 is a designation for text screens, which use 2 bytes per character for memory storage
  9. ScreenSize = _WIDTH * _HEIGHT * P
  10. Frames = 48 'In our animation
  11. UncompressedStringSize = Frames * ScreenSize 'the total size needed to store all the animation images, uncompressed (Should be about 48 MB)
  12. UncompressedString$ = SPACE$(UncompressedStringSize) 'a placeholder for the whole animation, uncompressed.
  13. SingleScreen$ = SPACE$(ScreenSize) 'a placeholder for a single screen worth of info
  14.  
  15. f = _LOADFONT("OLDENGL.TTF", 32)
  16.  
  17. m = _MEMIMAGE(0)
  18.  
  19.  
  20. $IF TOGGLE = TRUE THEN
  21.     UncompressedString$ = ""
  22.  
  23. FOR i = 1 TO 48 'let's draw a cheesy animation demo
  24.     LOCATE 1, 400 - i * 8
  25.     PRINT "Steve is Awesome."
  26.     _MEMGET m, m.OFFSET, SingleScreen$ 'Get one screen of information
  27.     $IF TOGGLE = TRUE THEN
  28.         UncompressedString$ = UncompressedString$ + SingleScreen$
  29.     $ELSE
  30.         MID$(UncompressedString$, (i - 1) * ScreenSize + 1, ScreenSize) = SingleScreen$ 'And put it in the proper place for storage
  31.     $END IF
  32.     _LIMIT 10
  33.  
  34.  
  35. PRINT "Press <ANY KEY> to view the cheesy animation."
  36.  
  37. SLEEP 'and now a pause so we can restore our animation
  38.  
  39. FOR i = 0 TO 47
  40.     temp$ = ""
  41.     temp$ = MID$(UncompressedString$, i * ScreenSize + 1, ScreenSize)
  42.     _MEMPUT m, m.OFFSET, temp$
  43.     _LIMIT 10
  44.  

Cobalt was wanting some advice on how to compress and store an animation in a single string over here: https://www.qb64.org/forum/index.php?topic=1444.msg106409#new

Working up a demo for him wasn't that much work, using the zlib libraries as the compression tool, but it did end up giving me one odd glitch which I can't explain at all.  Take a look at the code above and see if you can figure out what the BLEEP breaks it.

First, run it as is, and you'll see that it works as intended.  We capture the screen info 48 times, and save it into a single string, which we later use to help reproduce our cheesy animation.

Then, change the TOGGLE value to TRUE (first line of code), and run it again.  Notice how the results are completely different after the lucky 13th frame.

Now, what the BLEEP is broken???

****************************

When TOGGLE is FALSE (works), we preallocate the memory for the whole string and replace each screen of information manually.

When TOGGLE is TRUE (bugged), we start with a blank string and then simply add each new screen's data to that string.

The end result should end up with both methods generating the exact same string, but obviously something is different once we get around frame 14, or so.

So here's the game -- See if you can figure out WTH is wrong with the second method, and explain it to us.  First one to solve the mystery gets bragging rights and a highlighted "Best Answer" on this topic! 

Play now, and YOU can be a big wiener!!

I get a change of color when TRUE  i = 15

Now fixed by uncommenting DEFLNG A-Z, also added i display and commented out CLS and fixed a print line :D
TRUE works now same as FALSE
Code: QB64: [Select]
  1. $LET TOGGLE = TRUE
  2.  
  3.  
  4.  
  5. DEFLNG A-Z
  6. SCREEN _NEWIMAGE(640, 480, 32) 'A default screen, the size specified.
  7.  
  8. P = _PIXELSIZE: IF P = 0 THEN P = 2 '0 is a designation for text screens, which use 2 bytes per character for memory storage
  9. ScreenSize = _WIDTH * _HEIGHT * P
  10. Frames = 48 'In our animation
  11. UncompressedStringSize = Frames * ScreenSize 'the total size needed to store all the animation images, uncompressed (Should be about 48 MB)
  12. UncompressedString$ = SPACE$(UncompressedStringSize) 'a placeholder for the whole animation, uncompressed.
  13. SingleScreen$ = SPACE$(ScreenSize) 'a placeholder for a single screen worth of info
  14.  
  15. f = _LOADFONT("OLDENGL.TTF", 32)
  16.  
  17. m = _MEMIMAGE(0)
  18.  
  19.  
  20. $IF TOGGLE = TRUE THEN
  21.     UncompressedString$ = ""
  22.  
  23. FOR i = 1 TO 48 'let's draw a cheesy animation demo
  24.  
  25.     LOCATE 1, 400 - i * 8
  26.     PRINT "Mark is Awesome."
  27.     _MEMGET m, m.OFFSET, SingleScreen$ 'Get one screen of information
  28.     $IF TOGGLE = TRUE THEN
  29.         UncompressedString$ = UncompressedString$ + SingleScreen$
  30.     $ELSE
  31.         MID$(UncompressedString$, (i - 1) * ScreenSize + 1, ScreenSize) = SingleScreen$ 'And put it in the proper place for storage
  32.     $END IF
  33.     _LIMIT 10
  34.  
  35.  
  36. PRINT "Press <ANY KEY> to view the cheesy animation."
  37.  
  38. SLEEP 'and now a pause so we can restore our animation
  39.  
  40. 'CLS  < doesn't make a difference
  41. FOR i = 0 TO 47
  42.     LOCATE 5, 1: PRINT i: _DELAY .3
  43.     temp$ = ""
  44.     temp$ = MID$(UncompressedString$, i * ScreenSize + 1, ScreenSize)
  45.     _MEMPUT m, m.OFFSET, temp$
  46.     _LIMIT 10
  47.  

« Last Edit: June 21, 2019, 05:23:16 pm by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Here's a good game:
« Reply #2 on: June 21, 2019, 05:36:20 pm »
Now fixed by uncommenting DEFLNG A-Z, also added i display and commented out CLS and fixed a print line :D

I noticed that using a DEFLNG made a difference (which is why I left it in there, remarked out as I did).  The question is, WHY the heck does it make a difference??

One method simply adds information to a string as we go along, the other simply modifies segments of a massive pre-allocated string as it does its stuff.

Why should a DEFLNG affect anything?  What's the glitch and why isn't my poor brain sorting this issue out for me??  :P
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Here's a good game:
« Reply #3 on: June 21, 2019, 05:53:47 pm »
Here's the glitch -- it's some sort of issue with the math giving different results.

Code: QB64: [Select]
  1. ScreenSize& = 640 * 480 * 4
  2. ScreenSize = 640 * 480 * 4
  3.  
  4. i& = 0: i = 0
  5. DO UNTIL i& = 48
  6.     value1&& = i& * ScreenSize& + 1
  7.     value2&& = i * ScreenSize + 1
  8.     PRINT i&; ")", value1&&, value2&&
  9.     i& = i& + 1: i = i + 1
  10.     IF i = 14 THEN BEEP
  11.     SLEEP
  12.  

An integer times an integer plus one gives different results than a single times a single plus one -- even though all the values are integers and there's no overflow occurring anywhere!

/sigh

This is the type of glitch that a programmer spends FOREVER trying to track down and sort out, only to later realize -- much to their frustration -- that it's not something they're responsible for.  Math should be math, but sometimes apparently it's not! 
« Last Edit: June 21, 2019, 05:57:19 pm by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Here's a good game:
« Reply #4 on: June 21, 2019, 06:02:10 pm »
Remember the default is Single Precision and any math done with that leaves rounding errors specially division. So don't have nice clean integers that I suppose Memory Functions would expect. So .99999999999 becomes 0 if something is expecting an integer.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Here's a good game:
« Reply #5 on: June 21, 2019, 06:35:27 pm »
Remember the default is Single Precision and any math done with that leaves rounding errors specially division. So don't have nice clean integers that I suppose Memory Functions would expect. So .99999999999 becomes 0 if something is expecting an integer.

I don’t think, in this case, that it’s a rounding error.  I think we’ve just exceeded the lower precision limits of a SINGLE here. 

After all, SINGLE, by its very nature, has inherent limitations.

1.2E+98 is a valid single number, but adding 1 to it an infinite number of times will never change it to become 1.3E+98.  We just simply don’t have the precision to track that minute increment with that size exponent — and I think that’s what the glitch is with the code above.  We’ve simply exceeded the precision limits of a single, so that +1 is lost and that throws the _MEM address off by that byte.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Here's a good game:
« Reply #6 on: June 22, 2019, 08:49:07 am »
OK your precision theory seems to be confirmed with this test:
Code: QB64: [Select]
  1. $LET TOGGLE = TRUE
  2.  
  3. _DEFINE A-Z AS DOUBLE  '<<< has more precision than single
  4.  
  5. 'DEFLNG A-Z
  6. SCREEN _NEWIMAGE(640, 480, 32) 'A default screen, the size specified.
  7.  
  8. P = _PIXELSIZE: IF P = 0 THEN P = 2 '0 is a designation for text screens, which use 2 bytes per character for memory storage
  9. ScreenSize = _WIDTH * _HEIGHT * P
  10. Frames = 48 'In our animation
  11. UncompressedStringSize = Frames * ScreenSize 'the total size needed to store all the animation images, uncompressed (Should be about 48 MB)
  12. UncompressedString$ = SPACE$(UncompressedStringSize) 'a placeholder for the whole animation, uncompressed.
  13. SingleScreen$ = SPACE$(ScreenSize) 'a placeholder for a single screen worth of info
  14.  
  15. f = _LOADFONT("OLDENGL.TTF", 32)
  16.  
  17. m = _MEMIMAGE(0)
  18.  
  19.  
  20. $IF TOGGLE = TRUE THEN
  21.     UncompressedString$ = ""
  22.  
  23. FOR i = 1 TO 48 'let's draw a cheesy animation demo
  24.     LOCATE 1, 400 - i * 8
  25.     PRINT "Steve is Awesome."
  26.     _MEMGET m, m.OFFSET, SingleScreen$ 'Get one screen of information
  27.     $IF TOGGLE = TRUE THEN
  28.         UncompressedString$ = UncompressedString$ + SingleScreen$
  29.     $ELSE
  30.         MID$(UncompressedString$, (i - 1) * ScreenSize + 1, ScreenSize) = SingleScreen$ 'And put it in the proper place for storage
  31.     $END IF
  32.     _LIMIT 10
  33.  
  34.  
  35. PRINT "Press <ANY KEY> to view the cheesy animation."
  36.  
  37. SLEEP 'and now a pause so we can restore our animation
  38.  
  39. FOR i = 0 TO 47
  40.     temp$ = ""
  41.     temp$ = MID$(UncompressedString$, i * ScreenSize + 1, ScreenSize)
  42.     _MEMPUT m, m.OFFSET, temp$
  43.     _LIMIT 10
  44.  

If it were an Integer versus Float problem it would still not work.

Quote
...and YOU can be a big wiener!!
  :D


Actually this is good lesson, that increments of 1 can be distinguished only to a certain point with Single type because of it's precision though it's range is so much greater.
Code: QB64: [Select]
  1. WHILE i <> i + 1
  2.     i = i + 1
  3.     PRINT i
  4. PRINT "Nope this is NOT an infinite loop! See where it stopped:"
  5. print using "###,###,###.0000" ;i
  6.  
« Last Edit: June 22, 2019, 09:11:26 am by bplus »

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Here's a good game:
« Reply #7 on: June 22, 2019, 11:32:13 am »
Yes
I can affirm AWESOME!
Yes Steve is Awesome, but only if I change from OLDENGL.TTF to LUCON.TTF.

Programming isn't difficult, only it's  consuming time and coffee

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Here's a good game:
« Reply #8 on: June 22, 2019, 11:35:11 am »
Bplus your mod has an error
now Mark is AWESOME and
OLDENGL.TTF doesn't work  in PC where it isn't.
Programming isn't difficult, only it's  consuming time and coffee

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Here's a good game:
« Reply #9 on: June 22, 2019, 11:52:23 am »
I find more visible this:
Code: QB64: [Select]
  1. PRINT "Nope this is NOT an infinite loop! See where it stopped:"
  2. WHILE i <> i + 1
  3.     i = i + 1
  4.     PRINT i
  5. PRINT USING "###,###,###.0000"; i
  6.  
  7.  
but about the issue
Single vs Long Integer , is the foundation  in the QB64 code (definition of type of data) or in C/C++ basis (definition of correspondent type of data in C/C++)?
Programming isn't difficult, only it's  consuming time and coffee