IGNORED

# Checking if a number is odd or even in Extended Basic

## Recommended Posts

Hello,

I have been writing little programs to become more familiar with extended basic. The following program draws a checker board on the screen and then uses a sprite to jump from each black square in a loop. I needed to determine if a column was an even or an odd column but I couldn't find a modulus function or operator so a used the code in lines 121 and 125 as a work around. Is there a better way to determine if a number is odd or even using extended basic?

100 CALL CLEAR

120 FOR R=1 TO 20

121 X=R/2

125 IF INT(X) = X THEN S=2 ELSE S=1

130 FOR C=S TO 24 STEP 2

135 CALL CHAR(91,"FFFFFFFFFFFFFFFF")

140 CALL HCHAR(R,C,91)

150 NEXT C

160 NEXT R

220 FOR R=1 TO 20

221 X=R/2

225 IF INT(X) = X THEN S=2 ELSE S=1

230 FOR C=S TO 24 STEP 2

235 CALL CHAR(91,"FFFFFFFFFFFFFFFF")

240 CALL SPRITE(#1,91,4,R*8-7,C*8-7)

250 NEXT C

260 NEXT R

270 GOTO 220

Also, feel free to leave any comments or pointers on how I could better implement this program in extended basic.

Thanks!

##### Share on other sites

Bit twiddling is so much better

Edited by sometimes99er
##### Share on other sites

In XB, if you are treating your numbers as integers, you can also use bit-twiddling to isolate the LSb (least significant bit) in the number. The LSb will always be 0 for even numbers and 1 for odd numbers.

Test for even: if (num AND 1) = 0 then print "even"

Test for odd: if (num AND 1) = 1 then print "odd"

```100 FOR I=1 TO 10
110 PRINT I;"IS ";
120 IF (I AND 1)=1 THEN PRINT "ODD" ELSE PRINT "EVEN"
130 NEXT I
```

##### Share on other sites

In XB, if you are treating your numbers as integers, you can also use bit-twiddling to isolate the LSb (least significant bit) in the number. The LSb will always be 0 for even numbers and 1 for odd numbers.

Test for even: if (num AND 1) = 0 then print "even"

Test for odd: if (num AND 1) = 1 then print "odd"

```100 FOR I=1 TO 10
110 PRINT I;"IS ";
120 IF (I AND 1)=1 THEN PRINT "ODD" ELSE PRINT "EVEN"
130 NEXT I
```

Oh...I had know idea you could AND the binary value from within XB! That is pretty handy. Thanks for your input.

Edited by idflyfish
##### Share on other sites

IIRC the Miller's Graphics book on Sprite Programming (or maybe it was Night Mission) has a really good section on optimizing XB (with tricks like this)

##### Share on other sites

IIRC the Miller's Graphics book on Sprite Programming (or maybe it was Night Mission) has a really good section on optimizing XB (with tricks like this)

Excellent...ill have a look..thanks

##### Share on other sites

Should do much the same as yours - and a lot faster.

```100 CALL CLEAR::CALL CHAR(91,RPT\$("F",16)):\$=RPT\$("[ ",12)
110 FOR R=1 TO 20::DISPLAY AT(R,2-(R AND 1))\$::NEXT R
120 CALL SPRITE(#1,91,4,1,17)
130 FOR R=1 TO 20::FOR C=1 TO 12
140 CALL LOCATE(#1,R*8-7,C*16+9-8*(R AND 1))
150 NEXT C::NEXT R::GOTO 130
```

Edited by sometimes99er
##### Share on other sites

Should do much the same as yours - and a lot faster.

```100 CALL CLEAR::CALL CHAR(91,RPT\$("F",16)):\$=RPT\$("[ ",12)
110 FOR R=1 TO 20::DISPLAY AT(R,2-(R AND 1))\$::NEXT R
120 CALL SPRITE(#1,91,4,1,17)
130 FOR R=1 TO 20::FOR C=1 TO 12
140 CALL LOCATE(#1,R*8-7,C*16+9-8*(R AND 1))
150 NEXT C::NEXT R::GOTO 130
```

Heck ya it is...shorter too

This will give me something to chew on...thanks for the input

##### Share on other sites

If you make a storage table of where the location of the black squares are you could use CALL MOTION on the SPRITE and a CALL COINC. The SPRITE movement would be smooth not jumpy, unless that is intended.

Edited by RXB
##### Share on other sites

If you make a storage table of where the location of the black squares are you could use CALL MOTION on the SPRITE and a CALL COINC. The SPRITE movement would be smooth not jumpy, unless that is intended.

That sounds interesting. How do you suggest we make the storage table ?

##### Share on other sites

Try this and see what you think.

100 CALL CLEAR

110 RA=8192

120 FOR R=1 TO 20

130 X=R/2

140 IF INT(X)=X THEN S=2 ELSE S=1

150 FOR C=S TO 24 STEP 2

160 CALL CHAR(91,"FFFFFFFFFFFFFFFF")

170 CALL HCHAR(R,C,91)

180 NEXT C

190 NEXT R

200 FOR R=1 TO 20

210 X=R/2

220 IF INT(X)=X THEN S=2 ELSE S=1

230 FOR C=S TO 24 STEP 2

240 CALL CHAR(91,"FFFFFFFFFFFFFFFF")

250 CALL SPRITE(#1,91,4,R*8-7,C*8-7)

270 NEXT C

280 NEXT R

290 FOR RA=8670 TO 8192 STEP-2

300 CALL PEEK(RA,R,C)

310 CALL SPRITE(#1,91,4,R,C)

320 NEXT RA

330 FOR RA=8192 TO 8670 STEP 24

340 CALL PEEK(RA,R,C)

350 CALL SPRITE(#1,91,4,R,C)

360 NEXT RA

370 FOR RA=8192 TO 8670 STEP 2

380 CALL PEEK(RA,R,C)

390 CALL SPRITE(#1,91,4,R,C)

400 NEXT RA

410 GOTO 290

##### Share on other sites

Try this and see what you think.

100 CALL CLEAR

110 RA=8192

120 FOR R=1 TO 20

130 X=R/2

140 IF INT(X)=X THEN S=2 ELSE S=1

150 FOR C=S TO 24 STEP 2

160 CALL CHAR(91,"FFFFFFFFFFFFFFFF")

170 CALL HCHAR(R,C,91)

180 NEXT C

190 NEXT R

200 FOR R=1 TO 20

210 X=R/2

220 IF INT(X)=X THEN S=2 ELSE S=1

230 FOR C=S TO 24 STEP 2

240 CALL CHAR(91,"FFFFFFFFFFFFFFFF")

250 CALL SPRITE(#1,91,4,R*8-7,C*8-7)

270 NEXT C

280 NEXT R

290 FOR RA=8670 TO 8192 STEP-2

300 CALL PEEK(RA,R,C)

310 CALL SPRITE(#1,91,4,R,C)

320 NEXT RA

330 FOR RA=8192 TO 8670 STEP 24

340 CALL PEEK(RA,R,C)

350 CALL SPRITE(#1,91,4,R,C)

360 NEXT RA

370 FOR RA=8192 TO 8670 STEP 2

380 CALL PEEK(RA,R,C)

390 CALL SPRITE(#1,91,4,R,C)

400 NEXT RA

410 GOTO 290

Well, I get a

* SYNTAX ERROR IN 260

I guess you're trying to implement the "storage table" using LOAD and PEEK ?

I don't know how complete your example is, but didn't you suggest the use of CALL MOTION and CALL COINC ?

##### Share on other sites

The CALL LOAD and CALL PEEK use the lower 8K of the 32K. So I guess you do not have 32K?

Bare bones a TI like that uses only 16K VDP memory so all program line table, variables, and the program are all crammed that slower memory VDP.

Programs running from VDP run much slower then from RAM in the 32K.

Here is the problem:

Row and Column storage is 968 values at 2 bytes each is 1936 bytes plus tokens for each value means 2904 bytes just to store the tables.

Now to access those values in memory you need an array of RA(22,22) but each access will make a copy in memory to work with this slows the program down as you are running from VDP, why RAM is better.

Ok instead of your CALL SPRITE(#1,96,4,R,C) you could do CALL SPRITE(#1,96,4,R,C,0,62) :: CALL MOTION(#1,-62,62) :: CALL MOTION(#1,0,62) :: CALL MOTION(#1,62,62) :: C=C+1 :: CALL SPRITE(#1,96,4,R,C)

From normal XB almost everything sucks, that is why I wrote RXB. By adding a comma in GMOTION from above is CALL SPRITE(#1,96,4,R,C,0,62) :: CALL MOTION(#1,-62,62,#1,0,62,#1,62,62) :: C=C+1 :: CALL SPRINT(#1,96,4,R,C)

(Much less memory used and runs faster as the :: really slows XB down the more you have, even slower is line numbers, the less the better and faster the program runs.)

A solution in RXB is

CALL SPRITE(#1,96,4,R,C,0,62,#2,32,R+1,C) :: CALL GMOTION(#1,X,Y)

FOR X=-62 TO 62 :: CALL MOTION(#1,X,Y) :: CALL DISTANCE(#1,#2,D) :: IF D<8 THEN C=C+1 :: CALL SPRITE(#1,96,4,R,C)

NEXT X

I am working on a upgrade of RXB so can not spend a lot on time on this, but was just making a suggestion. If you are using no 32K your approach avenues are very limited. Lack of memory means lack of tools to attack the problem.

Edited by RXB
##### Share on other sites

Try this and see what you think.

100 CALL CLEAR

110 RA=8192

120 FOR R=1 TO 20

130 X=R/2

140 IF INT(X)=X THEN S=2 ELSE S=1

150 FOR C=S TO 24 STEP 2

160 CALL CHAR(91,"FFFFFFFFFFFFFFFF")

170 CALL HCHAR(R,C,91)

180 NEXT C

190 NEXT R

200 FOR R=1 TO 20

210 X=R/2

220 IF INT(X)=X THEN S=2 ELSE S=1

230 FOR C=S TO 24 STEP 2

240 CALL CHAR(91,"FFFFFFFFFFFFFFFF")

250 CALL SPRITE(#1,91,4,R*8-7,C*8-7)

270 NEXT C

280 NEXT R

290 FOR RA=8670 TO 8192 STEP-2

300 CALL PEEK(RA,R,C)

310 CALL SPRITE(#1,91,4,R,C)

320 NEXT RA

330 FOR RA=8192 TO 8670 STEP 24

340 CALL PEEK(RA,R,C)

350 CALL SPRITE(#1,91,4,R,C)

360 NEXT RA

370 FOR RA=8192 TO 8670 STEP 2

380 CALL PEEK(RA,R,C)

390 CALL SPRITE(#1,91,4,R,C)

400 NEXT RA

410 GOTO 290

Well, I get a

* SYNTAX ERROR IN 260

I guess you're trying to implement the "storage table" using LOAD and PEEK ?

I don't know how complete your example is, but didn't you suggest the use of CALL MOTION and CALL COINC ?

Unless I am mistaken, do you not need a "CALL INIT" prior to using a "CALL LOAD"?

##### Share on other sites

Yes, sorry I use only RXB and it does not need a CALL INIT first, RXB checks to see if CALL INIT is called when CALL LOAD or CALL PEEK is used, if CALL INIT is not used yet it just ignores the CALL LOAD("DSK#.PROGRAM") but still works. This is a XB bug I fixed in RXB.

In the last post I used DISTANCE, but you could just use COINC(#1,#2,4.CC) :: IF CC=-1 THEN C=C+1 :: CALL SPRITE(#1,96,4,R,C,0,62)

I could post a working video of it later when I get time to do that, but it does work fine.

##### Share on other sites

I'm sorry, but I think we use XB. Tried CALL INIT, but it still fails.

##### Share on other sites

Ok you guys got me curious and I dropped off RXB writing to investigate this. Turns out this is a bug in XB. XB has a bad habit of making a SYNTAX errors out of code that has no syntax error and in the CALL LOAD this is one of them.

I fixed this in RXB when I first moved the INIT code in RXB to a different GROM and fixed the bugs I found way back in RXB version 1001 (I do not have the source code earlier then 2001 now)

You will notice in this video that it gets to the sixth column of working fine when it crashes. If a real syntax error existed then it should have crashed the first time it ran the code, not the sixth time as XB does not re-write itself while running.

The original code I posted and said "Try this:" is the same except I added 90 CALL INIT to make the Normal XB program run correctly. (RXB does not require this, that is another bug) Anyway enjoy the show....

##### Share on other sites

Talking about "call motion" and smooth sprite movement, here's a little something ...

```100 CALL CLEAR::CALL CHAR(91,RPT\$("F",16)):\$=RPT\$("[ ",12)
110 FOR R=1 TO 20::DISPLAY AT(R,2-(R AND 1))\$::NEXT R
120 R1=1::C1=17::CALL SPRITE(#1,91,13,R1,C1)
130 R2=INT(RND*20)::C2=INT(RND*12)*16+17+(R2 AND 1)*8::R2=R2*8+1
140 CALL SPRITE(#2,91,7,R2,C2)::CALL MOTION(#1,(R2-R1)/8,(C2-C1)/8)
150 CALL POSITION(#1,R,C)::IF ABS(R-R2)>2 OR ABS(C-C2)>2 THEN 150
160 CALL MOTION(#1,0,0)::CALL LOCATE(#1,R2,C2)::R1=R2::C1=C2::GOTO 130```

##### Share on other sites

Just for kicks, I thought you might be interested to see the code to produce a checker board in TF

```: CHECKER
1 GMODE   \ select 32 column mode
0         \ seed for display/dont display
19 FOR    \ 20 rows (starts from 0)
23 FOR  \ 24 columns (starts from 0)
1 XOR \ toggle the seed (1-->0 / 0-->1)
DUP IF J I 42 1 HCHAR THEN \ display if seed >0
NEXT    \ next column
1 XOR   \ toggle the seed again
NEXT      \ next row
DROP      \ drop the seed
;
```

Or, horizontally, in the more traditional Forth style:

```: CHECKER
1 GMODE
0  19 FOR  23 FOR  1 XOR DUP IF J I 42 1 HCHAR THEN  NEXT  1 XOR  NEXT DROP ;
```

Takes just under 1 second (including setting the graphics mode and clearing the screen, which is done by GMODE), which is quite slow I suppose, but I wanted to use the same technique as the original poster. For speed, you'd want to use a similar approach to Sometimes (Sometimes is the master coder ):

```: 1LINE  ." * * * * * * * * * *" CR ;
: CHECKER
1 GMODE  0  19 FOR DUP IF SPACE THEN 1LINE 1 XOR NEXT DROP ;
```

Flies! About a quarter of a second, again, that includes setting the VDP mode, and doing a screen clear, before it even begins to run your program

Just thought i'd share. Sorry to hijack the thread

Edited by Willsy

## 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.

×   Pasted as rich text.   Paste as plain text instead

Only 75 emoji are allowed.