Jump to content
IGNORED

A long list of ifs.


Recommended Posts

I know about on...goto and on...gosub, but I doubt they'd be of much help for what I'm trying to do here. What I want is a simpler way of making a coin twirl on the screen. Here's the code for what I have now:

 

    if cointwirltimer=120 then cointwirltimer=0
    if cointwirltimer=0 then print at 29 color $2206, "\313"
    if cointwirltimer=10 then print at 29 color $2206, "\314"
    if cointwirltimer=20 then print at 29 color $2206, "\315"
    if cointwirltimer=30 then print at 29 color $2206, "\316"
    if cointwirltimer=40 then print at 29 color $2206, "\315"
    if cointwirltimer=50 then print at 29 color $2206, "\314"
    if cointwirltimer=60 then print at 29 color $2206, "\313"
    if cointwirltimer=70 then print at 29 color $2206, "\314"    
    if cointwirltimer=80 then print at 29 color $2206, "\317"    
    if cointwirltimer=90 then print at 29 color $2206, "\318"    
    if cointwirltimer=100 then print at 29 color $2206, "\317"        
    if cointwirltimer=110 then print at 29 color $2206, "\314"  

 

Looks ugly and long, doesn't it? Is there a way to simplify this?

Link to comment
Share on other sites

The problem with that pattern of code is that every condition will be tested, every time. That is, if the cointwirltimer is 110, it'll perform all the tests above it until it encounters the last one that succeeds. Even if the cointwirltimer is 120 and it succeeds on the first test, it'll still do all the other tests and fail them.

 

What you want is a way to say escape the conditionals as soon as a particular test succeeds, and ideally, you would want to test those conditions which are more likely to occur first, so as to improve the chances of skipping a bunch of useless tests.

 

The "ON ... GOTO" or "ON ... GOSUB" statements achieve this but at a linear scale; that is, the values tested against an ordinal sequential set, starting from zero, then one, two, three, etc.

 

You could induce this sort of statement to test your conditions by adjusting your cointwirltimer values to fit in that list. From what I see, the values are increments of 10, so if you divide the value by 10, you'll get a nice ordinal list, like this:

  ON (cointwirltimer / 10) GOSUB Do0, Do10, Do20, Do30, Do40, Do50, Do60, Do70, Do80, Do90, Do100, Do110, Do120



  ' ... rest of your code ...



Do0: Procedure
     print at 29 color $2206, "\313"
     End

Do1: Procedure
     print at 29 color $2206, "\314"
     End

' ...

Another, and perhaps cheaper, alternative is to use ELSIF. This follows the same pattern as you had, but with the added advantage that it will break out of the conditional tree as soon as it finds a match:

    if cointwirltimer=120 then cointwirltimer=0
    elsif cointwirltimer=0 then print at 29 color $2206, "\313"
    elsif cointwirltimer=10 then print at 29 color $2206, "\314"
    elsif cointwirltimer=20 then print at 29 color $2206, "\315"
    elsif cointwirltimer=30 then print at 29 color $2206, "\316"
    elsif cointwirltimer=40 then print at 29 color $2206, "\315"
    elsif cointwirltimer=50 then print at 29 color $2206, "\314"
    elsif cointwirltimer=60 then print at 29 color $2206, "\313"
    elsif cointwirltimer=70 then print at 29 color $2206, "\314"    
    elsif cointwirltimer=80 then print at 29 color $2206, "\317"    
    elsif cointwirltimer=90 then print at 29 color $2206, "\318"    
    elsif cointwirltimer=100 then print at 29 color $2206, "\317"        
    else  cointwirltimer=110 then print at 29 color $2206, "\314"
    end if

It doesn't look any prettier than what you had, but it works a lot faster on every case except the worse one (when the cointwirltimer is 110).

 

One more alternative is to compute the special output code from the cointwirltimer itself and just use a single PRINT statement to display it. However, this is not always possible since the output code may not be directly derived from the input timer, as is your case.

 

In any case, if you had a means to compute the output code from the cointwirltimer, you could define that in a function and use it like this:

DEF FN CoinOutput(timer) = {put your translation function here}

PRINT AT 29 COLOR $2206, (GRAM + (CoinOutput(cointwirltimer) * )

There aren't many other options, except by getting really clever with your code, like using a "DO ... LOOP" and things like that, which may obscure the logic itself and obfuscate your code.

 

-dZ.

  • Like 2
Link to comment
Share on other sites

Sorry, im not familiar with intellivision programming, but as a general rule, couldnt you just use variables with a counter?

 

Something like:

print at 29 color $2206, <"\" 313+(cointwirltimer/10)>

 

I know thats not correct syntax, but you should get the point. If you can just do a calculation as straightforward as that, its just one line.

Link to comment
Share on other sites

Sorry, im not familiar with intellivision programming, but as a general rule, couldnt you just use variables with a counter?

 

Something like:

print at 29 color $2206, <"\" 313+(cointwirltimer/10)>

 

I know thats not correct syntax, but you should get the point. If you can just do a calculation as straightforward as that, its just one line.

 

That's actually my third suggestion above, but as I noticed when I was typing it, the translation between the timer and the output code is not linear. If it can be made linear, then that's what I suggest, although it would be more like:

PRINT AT 29 COLOR $2260, GRAM + ((cointwirltimer / 10) * 

That formula computes a source GRAM card by shifting the code three bits to the left to position it in its proper field within the background table word, and sets the GRAM bit on.

 

To make it simpler, you then wrap it in a user-defined function and use it as a macro.

 

-dZ.

Link to comment
Share on other sites

And yet another alternative which takes that last one into consideration is to use a translation table. You create a table with the ordered set of codes, and convert the cointwirltimer into an index into that table, i.e., by dividing it by 10. Then look it up in the PRINT statement:

' Macro to convert a value into a formatted BACKTAB character code
DEF FN BGCODE(value) = (GRAM + (value * )

' Test for the special case first
IF (cointwirltimer = 120) THEN
  cointwirltimer = 0
ELSE
  ' Print the character code
  PRINT AT 29 COLOR $2206, ScreenCodes(cointwirltimer / 10)
END IF


  ' ...


' We're using the user-defined macro BGCODE to convert the number
' into an actual BACKTAB character code.
ScreenCodes:
  DATA BGCODE(313), BGCODE(314), BGCODE(315), BGCODE(316)
  DATA BGCODE(315), BGCODE(314), BGCODE(313), BGCODE(314)
  DATA BGCODE(317), BGCODE(318), BGCODE(317), BGCODE(314)

Note that you still need to test for when the timer is 120, since that has a special case that does not print anything.

 

-dZ.

Edited by DZ-Jay
  • Like 1
Link to comment
Share on other sites

The last one doesn't work for me. It prints for me a constant "<".

 

My bad. Remove the "GRAM +" from the macro. The values "313" and above already have it. All they need is to be shifted. So it'll be:

DEF FN BGCODE(value) = (value * 
Link to comment
Share on other sites

Now it's giving me a constant equal sign. Where do I put the macro? Inside the loop?

 

Outside your code, at the very top. Or else, remove it completely, and make all the data statements the same value you where printing before, but multiplied by 8:. For example:

DATA 2504   ' \313 * 8
Link to comment
Share on other sites

I want to use this code since it reduces the size of the code considerably, but I can't seem to get it working correctly. It gives me different constant results depending on where I put the ScreenCodes data. In this code I'm attaching, it's at the very end and it gives me a black square.

 

cranberry3.bas

Link to comment
Share on other sites

I want to use this code since it reduces the size of the code considerably, but I can't seem to get it working correctly. It gives me different constant results depending on where I put the ScreenCodes data. In this code I'm attaching, it's at the very end and it gives me a black square.

 

 

I'll take a look.

Link to comment
Share on other sites

OK, first thing I see is that your timer does not increment by 10, which I should have known, so it will try to print even when it's not a power of 10. Then I see that the codes were not composed correctly. Attached is the fixed version.

 

Here are all the fixes:

 

1. First, we compute the full BACKTAB character code from the GRAM card index.

DEF FN BGCODE(value) = GRAM + (value * 

2. Then we need to only print when the counter is a multiple of 10, so we add a conditional:

	IF (cointwirltimer = 120) THEN
		cointwirltimer = 0
	ELSEIF (cointwirltimer % 10 = 0) THEN

3. Then we read the code from the table using the timer computation as an index:

		' Print the character code
		PRINT AT 29, ScreenCodes(cointwirltimer / 10) + CS_YELLOW
	END IF

4. And finally, the data table includes the GRAM card index computed by the macro for each card in the animation.

ScreenCodes:
	DATA BGCODE(57), BGCODE(58), BGCODE(59), BGCODE(60)
	DATA BGCODE(59), BGCODE(58), BGCODE(57), BGCODE(58)
	DATA BGCODE(61), BGCODE(62), BGCODE(61), BGCODE(58)

I've tested it and it looks good, although the animation (as you had it) repeats a frame at the end, which seems weird.

 

-dZ.

 

 

cranberry3.bas

  • Like 1
Link to comment
Share on other sites

What I am not happy about is that we are dividing the timer twice: the Modulo (%) operator divides by 10 and keeps the remainder, discarding the output; and the division in the PRINT statement does the opposite, keeping the output and discarding the remainder.

 

Ideally, we would divide only once, but there doesn't seem to be a direct way in IntyBASIC to get the remainder and output of the division at once with one operation. We could do this in Assembly Language easily, but that would disqualify your program from the next contest. ;)

 

-dZ.

Link to comment
Share on other sites

I got it working. I guess I was using an outdated version of jzINTV. But I don't know why the coin pauses while spinning for a frame.

 

It's easy: after the last frame in the sequence, it advances 10 iterations later to reach 120, but doesn't print a different card, so it skips another 10 iterations before it starts again. That's my fault, for I mistranslated your IF/THEN block. In essence, it skips one frame.

 

You can change it like this:

        ' Only animate on every 10th frame
	IF (cointwirltimer % 10 = 0) THEN
                ' If we're past the end of the sequence, restart it
		IF (cointwirltimer >= 120) THEN cointwirltimer = 0

		' Print the character code
		PRINT AT 29, ScreenCodes(cointwirltimer / 10) + CS_YELLOW
	END IF

et voilà! :)

Edited by DZ-Jay
Link to comment
Share on other sites

Your fix is a lot better than mine. Thank you so much for helping me with this.

 

No worries. I've been helping someone else with IntyBASIC, which has made me learn how it works, and so I can provide a bit more targeted assistance than before. :)

 

The coin animation is pretty cool. What will the game do?

 

-dZ.

Link to comment
Share on other sites

I realize I'm late to the party, but since I'm also learning to code, I tried to do it as an exercise without looking at other answers.

For what is worth, here is what I came up with.attachicon.gifcoin.bas

That's very close to the solutioned offered. :thumbsup:

 

The main difference is that I used a macro and constants to avoid magic numbers, but it is the same approach.

 

dZ.

 

 

Sent from my iPad using Tapatalk Pro

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...