Showing posts with label timer. Show all posts
Showing posts with label timer. Show all posts

Friday, January 10, 2014

Petit Computer Journal #33


Quick Programs

There are many programs that can be done quickly. Suppose that you only have 15 minutes to write a computer program. What do you think you would write? Let's start a quick one. The quickest program that you can write would be a simple game. Coin flips. Heads or Tail. Or in this case, A/B buttons. The program simply checks whether or not you pushed the right buttons. It's a simple one-liner.


  1. ?"A/B?":WAIT 180:IF BUTTON(0)==16*RND(2) THEN "YOU WIN!" ELSE "YOU LOSE!"


Yes, it's that simple! There's nothing to it, is there? Let's take it a little more and do a simple Rock-Paper-Scissor game. Let's take a look at this table(A-B) (RPS=012):

B\A R P S
R 0 1 2
P -1 0 1
S -2 -1 0

Now, consider this: Looking at the diagonals, we see that the values are the same. zero means draw. one means win. two means lose. -1, -2 means lose, win. So, how about if we shift it up and set the range to modulus 3?


  1. O=(2+A-B)%3:'O=OUTCOME


The range then becomes 0-2, 0=Win,1=Lose,2=Draw, and everything is peachy! The program then clearly writes itself:


  1. CLS:CLEAR
  2. DIM T$(3)
  3. T$(0)="ROCK"
  4. T$(1)="PAPER"
  5. T$(2)="SCISSORS"
  6. ?"A=ROCK,B=PAPER,X=SCISSORS"
  7. WAIT 180
  8. B=BUTTON(0)
  9. A=0
  10. IF B AND 32 THEN A=1
  11. IF B AND 64 THEN A=2
  12. ?"YOU CHOSE ";T$(A)
  13. B=RND(3)
  14. ?"I CHOOSE ";T$(B)
  15. O=(2+A-B)%3
  16. IF O==0 THEN ?"YOU WIN" ELSE IF O==1 THEN ?"YOU LOSE" ELSE ?"DRAW"


That's all there is to it. Pretty quick to do and implement.

Let's keep moving on. How about random outcome? That's important in a game. However, there's something that you can do for a purely random device, such as dice. Here's a quick implementation of the Magic 8 Ball, although I don't bother putting in too many responses.


  1. CLS:CLEAR
  2. DIM T$(6)
  3. T$(0)="ABSOLUTELY YES"
  4. T$(1)="YES"
  5. T$(2)="MAYBE"
  6. T$(3)="NO"
  7. T$(4)="ABSOLUTELY NOT"
  8. T$(5)="NO WAY JOSE!"
  9. ?T$(RND(6))


If the example looks lean, that's because it is. The Magic 8 Ball is quite famous. Another example, using the same structure, would be Yoda's Wisdom. Quotes of Yoda from Star Wars, presented with pictures of him is a rather entertaining program. Another one would be Bingo, or lottery, or anything random. One of my stand by program is a dice roller for playing board games.

Some games requires you to roll so many dice, and they're not all six dice, either. Let's say that you want to roll 1-4 dice, ranging from D6,D10,D20. It's a simple process using the touch screen and do it. I'm doing it quick, so there's no text. You certainly want to dress it up for practical use.


  1. CLS:CLEAR
  2. DIM D(3)
  3. D[0]=6
  4. D[1]=10
  5. D[2]=20

  6. @MAIN
  7. VSYNC 1:TX=TCHX:TY=TCHY
  8. R=0
  9. FOR I=0 TO FLOOR(TX/64)
  10. R=R+RND(D[FLOOR(TY/64)])
  11. NEXT I
  12. IF TCHST THEN LOCATE 0,0:?"YOU ROLL ";R;"    "
  13. GOTO @MAIN


I actually implemented Snake and Ladder game in less than 10 minutes. One thing that is interesting about it, is that the program really doesn't require any user input other than rolling the dice. In that sense, all the activities that you do can be boiled down into rolling the dice. We can improve this further simply by letting the computer run it straight.


  1. CLS:CLEAR
  2. A=0:B=0
  3. @MAIN
  4. ?A,B
  5. A=A+RND(2):B=B+RND(2)
  6. IF A>100 OR B>100 THEN GOTO @END
  7. GOTO @MAIN

  8. @END
  9. IF A>100 THEN ?"A WINS!"
  10. IF B>100 THEN ?"B WINS!"
  11. IF A==B THEN ?"IT'S A DRAW!"


The program will resolve the race immediately. You may find it interesting to input some kind of delay in the output, so as to make it more readable as it goes.

All of these programs can be done really quick. In fact, I do these while waiting for something. Or maybe when I was in bed, trying to sleep. Most people would take a book to read in bed. I would take a Nintendo 3DS and write programs, instead.

One more quick example of the program, and this time it's useful when you're trying to do something regarding sleep: An alarm clock.


  1. CLS
  2. AH=6:'ALARM HOUR
  3. AM=0:'ALARM MINUTE
  4. LOCATE 0,2:?AH;":";AM
  5. @MAIN
  6. WAIT 60
  7. LOCATE 0,0:?TIME$
  8. CH=VAL(LEFT$(TIME$,2))
  9. CM=VAL(MID$(TIME$,3,2))
  10. IF AH==CH AND AM==CM THEN BEEP
  11. GOTO @MAIN



Oh, one more bonus program since not one hour has passed, yet. You know how timers have lap times? Usually, there's only one room for lap times. With this, you can have as many as you want. I'm going to limit it to just 20 for simplicity. You may modify to suit.


  1. CLS
  2. I=0:T=0
  3. @MAIN
  4. VSYNC 1:T=T+1
  5. IF BTRIG() THEN I=I+1
  6. J$=RIGHT$("00"+STR$(T%60),2)
  7. S$=RIGHT$("00"+STR$(FLOOR((T/60))%60),2)
  8. M$=RIGHT$("00"+STR$(FLOOR((T/3600))%60),2)
  9. LOCATE 0,I:?I,M$;":";S$;":";J$
  10. IF I>=20 THEN END
  11. GOTO @MAIN


These programs are rough, and really, for distribution, you may want to dress them up a little. However, for something that you can doodle in 10 minutes, while waiting for something, these are perfectly suited as a pleasant time waster. Did I just do 7 programs in one hour? I guess so.

Friday, November 1, 2013

Petit Computer Journal #23


6. Loop with Player input + multi-thread


This time, we're going to do something that is common in complex games: multi-threading.

Multi-threading is a rather sophisticated and complex way to have multiple process going on at the same time. It is also extremely difficult to get right, especially if different processes depends on other processes. What I'm going to do is to simplify the problem, so that there is no dependency to the process.

We're going to set up and do multiple timers. Except, we're not going to do it the simple way using sprites. We're going to do it the hard way using internal timers: MAINCNTL.

MAINCNTL is the counting of frames since the program launched. Since there is a limit in the numerical accuracy, it is only able to count up to 145 minutes at a time. After that, it rolls over. So, our program must be able to handle that scenario.

The standard way to handle it, is to check MAINCNTH. However, in order to simplify the program, I'm not going to do that. What I'm going to do, is to store the MAINCNTL value for each thread, and compare it to the current MAINCNTL value. Then increase the timer for the difference. Surely, that method will lose a few frames over time, but I'm not worried. When the timer has minute resolution, a few frames missing isn't going to be a big deal.



  1. CLS:CLEAR
  2. DIM N(20)
  3. DIM M(20)
  4. DIM C(20)
  5. DIM L(20)
  6. DIM A(20)
  7. DIM T$(20)


  8. @TMRDATA
  9. DATA 0,99,"MAXTIMER"
  10. DATA 1,1,"QUICK TIMER"
  11. DATA 2,2,"SLOW TIMER"
  12. DATA 3,3,"EGG TIMER"
  13. DATA 4,4,"SNOOZER"
  14. DATA -1,-1,"DONE"

  15. @INIT
  16. CLS
  17. LOCATE 0,22:?"A START  ","B PAUSE  ","X RESET"
  18. P=1:RESTORE @TMRDATA
  19. FOR I=0 TO 19
  20. A[I]=FALSE
  21. IF P THEN READ N[I]:'TIMER NUMBER
  22. IF P THEN READ M[I]:M[I]=M[I]*3600:'TIMER MINUTES
  23. IF P THEN READ T$[I]:'TIMER LABEL
  24. IF N[I]<0 THEN P=0:TC=I-1
  25. NEXT
  26. CS=0:'CURSOR
  27. TH=0:'THREAD


Timers will have these operations on them: (A)START, (B)PAUSE, (X)RESET. It will have these data on them: (N)Timer Number,(M)Max Tick,(C)Current Tick,(L)Last MAINCNTL,(A)Active Status,(T$)Timer Label. We will also have something to process (TC)Timer Count up to 20.



  1. @LOOP
  2. 'PROCESS INPUT
  3. VSYNC 1:B=BTRIG()
  4. IF (B AND 1) THEN CS=CS-1:IF CS<0 THEN CS=TC
  5. IF (B AND 2) THEN CS=CS+1:IF CS>TC THEN CS=0
  6. IF (B AND 16) THEN A[CS]=TRUE
  7. IF (B AND 32) THEN A[CS]=FALSE
  8. IF (B AND 64) THEN GOSUB @TRESET

  9. 'PROCESS THREAD
  10. TH=TH+1:IF TH>TC THEN TH=0
  11. IF A[TH]==FALSE GOTO @SHOW
  12. IF MAINCNTL>L[TH] THEN C[TH]=C[TH]+(MAINCNTL-L[TH])
  13. IF C[TH]>M[TH] THEN GOSUB @ALARM

  14. @SHOW
  15. IF C[TH]==M[TH] THEN COLOR 13 ELSE COLOR 0
  16. TM=FLOOR((M[TH]-C[TH])/3600)
  17. TS=FLOOR(((M[TH]-C[TH])%3600)/60)
  18. TM$=RIGHT$(("00"+STR$(TM)),2)
  19. TS$=RIGHT$(("00"+STR$(TS)),2)
  20. LOCATE 0,TH:?" "*31
  21. IF CS==TH THEN LOCATE 0,TH:?">";
  22. LOCATE 3,TH:?N[TH];
  23. LOCATE 6,TH:TM$;":";TS$,T$[I]
  24. L[TH]=MAINCNTL
  25. GOTO @LOOP

  26. @TRESET
  27. A[CS]=FALSE
  28. C[CS]=0
  29. BGMSTOP
  30. RETURN

  31. @ALARM
  32. BGMPLAY 6
  33. A[TH]=FALSE
  34. C[TH]=M[TH]
  35. RETURN


Friday, October 18, 2013

Petit Computer Journal #21


A Simple Timer

This here is a simplified version of the timer program. I put it here just to clarify that there are other ways to do this. The previous version was used to show LOOP construct, but this version is an optimized version of it. Notice that duplicate codes are collapsed into one, thus simplifying the whole structure.



  1. 'TIMER PROGRAM BY HARRY HARDJONO
  2. SPSET 1,156,0,0,0,0
  3. SPOFS 1,-50,-50
  4. SPANIM 1,4,15
  5. SPSCALE 1,200

  6. @INIT
  7. CLS
  8. SPOFS 1,0,96,0
  9. SPREAD(1),X,Y
  10. ?"HOW MANY SECONDS?"
  11. INPUT T
  12. IF 0>=T GOTO @END
  13. CLS
  14. ?"A STARTS TIMER"
  15. ?"B SETS NEW TIME"
  16. ?"X EXIT"
  17. ?"Y PAUSE"

  18. @LOOP
  19. VSYNC 1:B=BTRIG()
  20. IF (SPCHK(1) AND 1) THEN SPOFS 1,X,Y,0 
  21. IF (B AND 16) THEN SPOFS 1,224,96,FLOOR((224-X)*T/224)*60:GOTO @TICK
  22. IF (B AND 32) GOTO @INIT
  23. IF (B AND 64) GOTO @END
  24. GOTO @LOOP
  25. @TICK
  26. IF (BUTTON(0) AND 128) GOTO @LOOP
  27. LOCATE 0,8:SPREAD(1),X,Y:?"TIME LEFT: ";FLOOR((224-X)*T/224);"   "
  28. IF (SPCHK(1) AND 1) THEN BEEP 28:WAIT 60:GOTO @TICK
  29. ?"TIME'S UP!":SPOFS 1,0,96,0:X=0:BEEP 50:WAIT 120
  30. GOTO @LOOP

  31. @END
  32. ?"GOODBYE!"
  33. SPCLR 1:WAIT 300


Friday, October 11, 2013

Petit Computer Journal #20


IdleLoop


I'm going to do something different this time around. Usually I would make a new program, illustrating a new concept. However, this time, I won't be doing something new and exciting. I'll be doing something that is old and boring: idle loop.

What is idle loop? Well, you know the main loop on the program that goes like this:


  1. @MAINLOOP
  2. 'get player input
  3. 'process player input
  4. GOTO @MAINLOOP


That's it. Idle loop is so called because if the player has no input, it'll just wait around doing nothing. In other words, being idle.

So, you're probably wondering why I want to show that here. Shouldn't that process be known to everybody? Yes, it should. But not to everybody. Just like loop, there are various situations that you have to watch out for. For example, where would you want to put the @INIT function?

INIT function deals with initial state of the program. This is where default values come into play. Also, I like to put in @QUIT function, where the program does clean up when it exits. I don't put it in all my programs, especially simple ones, but for completeness, I want my programs to clean up after itself. It's just good programming practice.

So, the structure would be


  1. Global settings, DIM, and such
  2. INIT function
  3. MAIN function
  4. END/QUIT/CLEANUP function


There is a difference between Global Settings and INIT. In Global Settings, you allocate memory to the variables, and load any static resource needed. Fortunately, Petit Computer takes care most of it for you. Very little needed to be here. Some programming language requires you to load modules/libraries here as well.

INIT function deals with initializing the variables to start-up state. That means loading any custom screens if any. Backgrounds, Icons, and the like. This function gets called whenever the player quit to the title screen. It basically start fresh. If you have game states then you load that separately from this function. And yes, you want to have that special loading function, so you can override default graphics and provide the player with custom sprites and skin.

QUIT function basically says good-bye. There's not much here for Petit Computer. If you don't need anything, just leave it out, or just put out a good-bye message to the player.

The MAIN function will handle several types of cases:


  1. Infinite Loop
  2. Loop with Timer
  3. Loop with VSYNC
  4. Loop with Player input (wait)
  5. Loop with Player input (no wait)
  6. Loop with Player input + background process
  7. Loop with Player input + multi-thread


1. Infinite Loop


The first case is the simplest. You want the program to run forever, like in showing demo.


  1. @LOOP
  2. ?"Hello World"
  3. GOTO @LOOP


2. Loop with Timer


Sometimes, you want to have the program run for a certain length of time. Say, like a Timer. You can do it like this:


  1. 'TIMER PROGRAM BY HARRY HARDJONO
  2. SPSET 1,156,0,0,0,0
  3. SPOFS 1,-50,-50
  4. SPANIM 1,4,15
  5. SPSCALE 1,200

  6. @INIT
  7. CLS
  8. ?"HOW MANY SECONDS?"
  9. INPUT T
  10. IF 0>=T GOTO @END
  11. SPOFS 1,0,48,0
  12. SPOFS 1,224,48,T*60

  13. @LOOP
  14. IF (SPCHK(1) AND 1)==0 GOTO @END
  15. BEEP 28:WAIT 60
  16. GOTO @LOOP

  17. @END
  18. ?"TIME'S UP!"
  19. SPCLR 1
  20. BEEP 50
  21. WAIT 300


And that's it. The code before the INIT creates and sets the sprite. INIT is used to send the sprite across the screen, timed according to T variable. The loop then simply waits for the sprite to stop moving, and gave a "ding" sound when it's done. Also, sprite clean up is done at the END.


3. Loop with Player input (wait)


Let's modify the program a bit. We want to have a player input, and we want it to wait for each input. Let's say A to start the timer, B to set the timer, and X to end the program.


  1. @INIT
  2. CLS
  3. ?"HOW MANY SECONDS?"
  4. INPUT T
  5. IF 0>=T GOTO @END
  6. ?"A STARTS TIMER"
  7. ?"B SETS NEW TIME"
  8. ?"X EXIT"

  9. @LOOP
  10. VSYNC 1:B=BTRIG()
  11. IF (B AND 16) GOTO @TICK
  12. IF (B AND 32) GOTO @INIT
  13. IF (B AND 64) GOTO @END
  14. GOTO @LOOP
  15. @TICK
  16. SPOFS 1,0,48,0
  17. SPOFS 1,224,48,T*60
  18. @TOCK
  19. LOCATE 0,4:SPREAD(1),X,Y:?"TIME LEFT: ";FLOOR((224-X)*T/224);"   "
  20. IF (SPCHK(1) AND 1) THEN BEEP 28:WAIT 60:GOTO @TOCK
  21. ?"TIME'S UP!":SPOFS 1,-50,-50:BEEP 50
  22. GOTO @LOOP

  23. @END
  24. ?"GOODBYE!"
  25. SPCLR 1:WAIT 300


If you notice, there's TICK and TOCK. Normally, I would put these on separate subroutine, but since I'm showing you how to do LOOP while waiting for user input, I simply group it all at once. Does it look like spaghetti code to you?

4. Loop with Player input (no wait)


Let's do one more improvement, and this time, we're going to do player input without waiting. Let's implement a PAUSE button. The truth is, it's very simple. Petit Computer, by default, does not wait for user input.

Here, we simply check if the sprite is moving. If so, then we stop it. Else, we start it.


  1. 'TIMER PROGRAM BY HARRY HARDJONO
  2. SPSET 1,156,0,0,0,0
  3. SPOFS 1,-50,-50
  4. SPANIM 1,4,15
  5. SPSCALE 1,200

  6. @INIT
  7. CLS
  8. ?"HOW MANY SECONDS?"
  9. INPUT T
  10. IF 0>=T GOTO @END
  11. ?"A STARTS TIMER"
  12. ?"B SETS NEW TIME"
  13. ?"X EXIT"
  14. ?"Y PAUSE"

  15. @LOOP
  16. VSYNC 1:B=BTRIG()
  17. IF (B AND 16) GOTO @TICK
  18. IF (B AND 32) GOTO @INIT
  19. IF (B AND 64) GOTO @END
  20. GOTO @LOOP
  21. @TICK
  22. SPOFS 1,0,48,0
  23. SPOFS 1,224,48,T*60
  24. @TOCK
  25. LOCATE 0,8:SPREAD(1),X,Y:?"TIME LEFT: ";FLOOR((224-X)*T/224);"   "
  26. IF (BUTTON(0) AND 128) GOTO @PAUSE
  27. IF (SPCHK(1) AND 1) THEN BEEP 28:WAIT 60:GOTO @TOCK
  28. ?"TIME'S UP!":SPOFS 1,-50,-50:BEEP 50
  29. GOTO @LOOP

  30. @PAUSE
  31. IF (SPCHK(1) AND 1) THEN SPOFS 1,X,Y,0 
  32. IF (BUTTON(0) AND 16) THEN SPOFS 1,224,48,FLOOR((224-X)*T/224)*60:GOTO @TOCK
  33. IF (BUTTON(0) AND 32) GOTO @INIT
  34. IF (BUTTON(0) AND 64) GOTO @END
  35. GOTO @PAUSE

  36. @END
  37. ?"GOODBYE!"
  38. SPCLR 1:WAIT 300



Simple as that. We simply use the variable values from TIME LEFT to stop the sprite where it stands, and starts it in according to TIME LEFT. There's a trick here, that we use BUTTON(0) instead of BTRIG. We do that because of WAIT 60 that we have will cause BTRIG signal to get lost. BUTTON(0) will read the input continuously. Press A to restart the timer.

Petit Computer Programming can be so easy! Next, we'll examine loops with background processes.