Showing posts with label screen. Show all posts
Showing posts with label screen. Show all posts

Tuesday, February 25, 2014

Raspberry Pi Journal #51



Screen Capture



I'm using scrot as my screen capture program. Just real quick, to use scrot with 8 seconds delay:


  1. scrot -cd 8 filename.jpg


and to do screen capture only the window, use


  1. scrot -cud 8 filename.jpg


Then you get a jpeg picture of the filename.

Tuesday, January 21, 2014

Raspberry Pi Journal #46


Disable Screensaver

The last couple posts deals with pesky screensaver kept interfering with our display. We certainly want to have an easy way to disable the screen saver, and for that, we need to go to the source: X window session itself.

Most of the instructions I see on the internet specifies .xinitrc file modification. Although it should work, that makes the change permanent. If I can do it via user shell, I'd rather do it that way.

Fortunately, there is a set of xwindow utilities. The one we're interested in is called xset. Disabling DPMS (Energy Star) feature is as simple as

xset -dpms

Enabling it would be

xset +dpms

So, to disable screen blanking, we'd do this:


  1. xset s noblank   #Disable blanking
  2. xset s off       #Disable screensaver
  3. xset -dpms       #Disable Energy Saving


And to enable them, we can do this:


  1. xset s blank      #Enable blanking
  2. xset s on         #Enable screensaver
  3. xset +dpms        #Enable Energy Saving


So I created two scripts: unblank.sh and blank.sh respectively. Oh, I also put sudo command in front of them, just to make sure it takes.

Now, all I have to do in order to disable the screen saver is type

unblank.sh

on the command prompt. And to enable it, just type

blank.sh

And there you go. Note that xset does more than just dealing with screen savers. Check out its man page for details.

Tuesday, January 7, 2014

Raspberry Pi Journal #44


Raspi #44
Prevent screen from blanking

If you want to show picture slide shows for hours on end, you probably run into a "feature" that is quite annoying: screensavers. The gist is that the program will interrupt your display to save your screen. It is a prudent action in order to stop your monitor from burning static images. The issue isn't as common as before, but even with the latest LCD display, it is still present. Therefore, having an automatic screen saver feature is desirable.

The problem is when we want the screen to burn all the time, such as displaying photo slide show. How do we disable the screen saver? I'm sorry to say that the system is very complex and that there is no single way to disable the screen saver.

I suppose you can kill the process, but that's not a desirable solution in the long run.

The trick here, is to let the computer know that you want the screen is up all the time. So, press a key in the keyboard or jiggle that mouse. A robot that shakes the mouse all the time seems ideal. Alternatively, put the mouse in a shake box.

However, we can do better than that. Even if the solution is hackish, we should do it all in software. There is such a thing, and it is:

pygame.event.get()

That's a python script. So far, that pygame is for Python 2.7. So we'll use that. Write a python program that will poll the keyboard/mouse event. Let's call it: unblank.py


  1. import pygame
  2. pygame.init()
  3. pygame.event.get()


And when you run this program:

python unblank.py

The screen saver process should terminate and the timer will restart. All you have to do is call it periodically and problem solved!

I'll just stick that line in my wallpaper rotation script


  1. #!/bin/bash

  2. for ((walltick=100;$walltick;walltick=$walltick-1))
  3. do 
  4.   PIC=$(ls wallpaper/*.jpg | shuf -n1)
  5.   pcmanfm -w $PIC
  6.   *python unblank.py*
  7.   sleep 100 
  8. done
  9. pcmanfm -w saber.png
  10. sleep 5
  11. exit 0


The whole process takes a couple second because python is not an insignificant process. So this answer is hackish and not very good.

And what do you know? It doesn't work! I would think that pygame.event.get() will reset the input, but apparently not. So, back to square one. The problem is, there are so many things that can be wrong, and you never know which one. That's very frustrating.

So, let's open up a window and see if that works. Here's the modified python script


  1. import pygame
  2. from time import sleep

  3. pygame.init()
  4. window=pygame.display.set_mode((32,24))

  5. while True:
  6.     pygame.event.get()
  7.     window.fill(pygame.Color(255,255,255))
  8.     pygame.display.update()
  9.     sleep(100.0)


Notice that this is an infinite loop, which is something I try to avoid. The problem is that it opens up a window, so I can do something to it, and that's not good. So, now, I'm running the script in the background, minimizing the window.

Minimizing the window needs to be done manually, which is a terrible solution. Worse, when I kill the process, the window still stays up! There's no way to terminate the window that I can see. Therefore, this command is useless:


  1. python unblank.py & pid=$!
  2. kill $pid


Because python script is killed yet the window is still up, there's no longer any way to close the window. It's definitely broken. So, now, I pull another shell just to run the program, keeping it in the background. That's another window open.

Of course, the right solution is to provide a refresh command, that we can use to reset the screensaver timer. How is it that we do not have such command?

Friday, December 27, 2013

Petit Computer Journal #31



Digital Koto

A while back, I wrote a little piano program. It includes song player. It's just a little simple music player, so I used BEEP instead of MML command. However, I'm rather curious since most of the code is created for the interface. In other words, drawing the piano keys. So, I'm wondering whether or not it's simpler to just draw the keys straight. Well, what kind of musical instrument is like that? The answer is simple: Japanese Koto. In truth, different cultures have different ideas and names for what basically amounts to a bunch of strings mounted on a board.

Still, the idea of it is interesting, and it's simple enough for me to do. So, let' do it! There are several different parts, but generally speaking, once you touch the screen, you come up with a string number and beep the appropriate sound. That's just look up table. Touch screen is easy. About the only thing that's difficult is drawing the strings proportionately. A little mathematic should do it.


  1. INIT
  2. Build BEEP table
  3. Build Note table
  4. Build String table
  5. LOOP
  6. Draw Strings
  7. If Touch screen
  8. Highlight nearest string
  9. Play BEEP sound
  10. GOTO LOOP


So, do you think this will take you one hour to do? Time for another "Hour of Code" challenge!


  1. ACLS:CLEAR
  2. DIM BP[49]:'BEEP TABLE
  3. DIM NT$[49]:'NOTE TABLE
  4. DIM ST[16]:'STRING TABLE
  5. BREPEAT 0,60,12
  6. BREPEAT 1,60,12
  7. BREPEAT 2,60,12
  8. BREPEAT 3,60,12

  9. @INIT
  10. NSI=0
  11. P=4096/12:T$="CcDdEFfGgAaB"
  12. FOR I=-24 TO 24:J=I+24
  13. BP[J]=P*I
  14. NT$[J]=MID$(T$,(J%12),1)
  15. NEXT
  16. ST[0]=14:ST[1]=19
  17. ST[2]=21:ST[3]=22
  18. ST[4]=26:ST[5]=27
  19. ST[6]=31:ST[7]=33
  20. ST[8]=34:ST[9]=38
  21. ST[10]=39:ST[11]=43
  22. ST[12]=45:ST[13]=0
  23. ST[14]=0:ST[15]=0

  24. ACLS


That's about it for the Initialization table. I want to fiddle with the string, so I'll put in button interface so I can change the string values on the fly.


  1. @LOOP
  2. NS=13:A=256/NS:B=A/2
  3. VSYNC 1:BT=BTRIG():TX=FLOOR(TCHX*NS/256)
  4. IF NS<1 THEN NS=1
  5. FOR I=0 TO NS-1
  6. GLINE B+I*A,16,B+I*A,192,15
  7. LOCATE (B+I*A)/8,0:?FLOOR(ST[I]/12)
  8. LOCATE (B+I*A)/8,0:?NT$[ST[I]]
  9. NEXT
  10. GLINE B+TX*A,16,B+TX*A,192,8
  11. IF TCHTIME>0 THEN BEEP 20,BP[ST[TX]]
  12. GOTO @LOOP


And that's about it. 35 minutes so far, and that's because I was having trouble with the math. The truth is, had I did the math correctly beforehand, I wouldn't have had so much trouble and I wouldn't have spend the time debugging.

Oh, yeah, about the tuning on the fly. I think that it is nice to be able to change the notes. So, what I'll do is add some button interface. That's what the BREPEAT command is for. Also, I may as well throw the instrument along with it. Instead of the locked in BEEP 20, I substitute it with a variable that will allow you to choose your own instrument.

Finally, we're going to move the whole thing down to the lower screen for ease of play. What should we put on the top of the screen? I don't know. Title screen, maybe? Or some internal variables?


  1. REM DIGITAL KOTO
  2. REM BY HARRY HARDJONO
  3. REM DEC 2013

  4. ACLS:CLEAR
  5. DIM BP[49]:'BEEP TABLE
  6. DIM NT$[49]:'NOTE TABLE
  7. DIM ST[16]:'STRING TABLE
  8. BREPEAT 0,60,12
  9. BREPEAT 1,60,12
  10. BREPEAT 2,60,12
  11. BREPEAT 3,60,12
  12. PNLTYPE "OFF"

  13. @INIT
  14. NSI=0
  15. CI=16:'CURRENT INSTRUMENT
  16. P=4096/12:T$="CcDdEFfGgAaB"
  17. FOR I=-24 TO 24:J=I+24
  18. BP[J]=P*I
  19. NT$[J]=MID$(T$,(J%12),1)
  20. NEXT
  21. ST[0]=14:ST[1]=19
  22. ST[2]=21:ST[3]=22
  23. ST[4]=26:ST[5]=27
  24. ST[6]=31:ST[7]=33
  25. ST[8]=34:ST[9]=38
  26. ST[10]=39:ST[11]=43
  27. ST[12]=45:ST[13]=0
  28. ST[14]=0:ST[15]=0

  29. GPAGE 1:ACLS

  30. @LOOP
  31. NS=13:A=256/NS:B=A/2
  32. VSYNC 1:BT=BTRIG():TX=FLOOR(TCHX*NS/256)
  33. IF NS<1 THEN NS=1
  34. GPAGE 1,1,1
  35. FOR I=0 TO NS-1
  36. GLINE B+I*A,16,B+I*A,192,15
  37. LOCATE (B+I*A)/8,0:?FLOOR(ST[I]/12)
  38. LOCATE (B+I*A)/8,0:?NT$[ST[I]]
  39. NEXT
  40. GLINE B+TX*A,16,B+TX*A,192,8
  41. IF TCHTIME>0 THEN BEEP CI,BP[ST[TX]]

  42. IF BT AND 1 THEN ST[NSI]=ST[NSI]+1
  43. IF BT AND 2 THEN ST[NSI]=ST[NSI]-1
  44. IF BT AND 4 THEN NSI=NSI-1
  45. IF BT AND 8 THEN NSI=NSI+1
  46. IF BT AND 16 THEN CI=CI+1:GOSUB @DISP
  47. IF BT AND 32 THEN CI=CI-1:GOSUB @DISP
  48. NSI=(NSI+NS)%NS
  49. ST[NSI]=(ST[NSI]+49)%49
  50. CI=(CI+70)%70
  51. GOTO @LOOP

  52. @DISP
  53. ACLS
  54. ?"INST: ";CI
  55. FOR I=0 TO 15
  56. ?I,ST[I]
  57. NEXT
  58. RETURN



Oh, by the way. The actual problem is so simple, that you can actually fit the minimalistic version of the program into one screen. That's right. It's another single screen challenge program!


  1. REM DIGITAL KOTO
  2. REM BY HARRY HARDJONO
  3. ACLS:CLEAR:DIM BP[49]
  4. DIM NT$[49]:DIM ST[16]
  5. P=4096/12:T$="CcDdEFfGgAaB"
  6. FOR I=-24 TO 24:J=I+24
  7. BP[J]=P*I
  8. NT$[J]=MID$(T$,(J%12),1):NEXT
  9. ST[0]=14:ST[1]=19:ST[2]=21
  10. ST[3]=22:ST[4]=26:ST[5]=27
  11. ST[6]=31:ST[7]=33:ST[8]=34
  12. ST[9]=38:ST[10]=39:ST[11]=43
  13. ST[12]=45:ST[13]=0:ST[14]=0
  14. @LOOP
  15. NS=13:A=256/NS:B=A/2
  16. VSYNC 1:TX=FLOOR(TCHX*NS/256)
  17. GPAGE 1,1,1:FOR I=0 TO NS-1
  18. GLINE B+I*A,0,B+I*A,192,15
  19. NEXT
  20. GLINE B+TX*A,16,B+TX*A,192,8
  21. SD=BP[ST[TX]]
  22. IF TCHTIME>0 THEN BEEP 16,SD
  23. GOTO @LOOP


Friday, November 15, 2013

Petit Computer Journal #25


Background Maker

A while back, I did a BGMaker program. That's a program that takes in graphic screen (GRP0) and turn it into background (SCU0) and background tiles (BGU0, BGU1, BGU2,BGU3). I had suspected it that it fits into one screen, and it did. Here is my entry to the single screen programming challenge:


  1. 'BGMAKER BY HARRY HARDJONO
  2. CLS:CLEAR:DIM TL$[1024]:MT=-1
  3. OX=0:OY=0:RX=31:RY=23:P$="G2"
  4. ?"GRAPHIC?":INPUT P$
  5. LOAD "GRP0:"+P$,FALSE
  6. FOR Y=0 TO RY:FOR X=0 TO RX
  7. X1=X*8:X2=X1+7:Y1=Y*8:Y2=Y1+7
  8. G$="":FOR YY=Y1 TO Y2
  9. FOR XX=X1 TO X2
  10. G$=G$+HEX$(GSPOIT(XX,YY)%16)
  11. NEXT:NEXT
  12. CT=-1:FOR I=MT TO 0 STEP -1
  13. IF G$==TL$[I] THEN CT=I
  14. NEXT
  15. IF CT==-1 THEN GOSUB @SETCHR
  16. BGPUT 0,OX+X,OY+Y,CT,0,0,0
  17. NEXT:NEXT:SAVE "SCU0:T0"
  18. FOR I=0 TO FLOOR(MT/256)
  19. B$="BGU"+STR$(I)
  20. SAVE B$+":B"+STR$(I):NEXT:END
  21. @SETCHR
  22. MT=MT+1:TL$[MT]=G$:CT=MT
  23. BU$="BGU"+STR$(FLOOR(MT/256))
  24. CHRSET BU$,MT%256,G$:RETURN


I also did a version with no memory. I'm not going to show it here because it's not only complicated, but also very, very slow. In fact, at one point, I actually put in an array to do it. That's when I decided to do a version with arrays instead.

Anyway, if you look at the code above, you'll see that it only works on single graphic screen. That's not what I want to have. I want to have the full 64 by 64 background tile generator. As you can see, from the variables OX, OY, P$, even though they do nothing in this version, the original design does take the full background field into account.

Here is the updated BGMAKER program that includes all available background screen. You'll need six graphic screens. They're all loaded into GRP0, but the build is done on different parts of BG screen.

'BGMAKER BY HARRY HARDJONO
CLS:CLEAR:DIM TL$[1024]:MT=-1
@PICFILE
DATA "G1","G2","G3","G6","G5","G4"
RESTORE @PICFILE

All this does is some initialization. I put the file names into DATA statements because I'm too lazy to modify the code. So I simply replaced all INPUT P$ into READ P$.


  1. 'LOAD GRPS
  2. OX=0:OY=0:RX=31:RY=23:READ P$
  3. LOAD "GRP0:"+P$,FALSE
  4. BGOFS 0,OX*8,OY*8,60:GOSUB @TILER


Okay, you can see the pattern here. OX, OY are relative shifting or original X,Y coordinate. RX,RY are the size or width and height of the screen. I mentioned changing INPUT P$ into READ P$. Once I loaded the graphic into screen 0, I shifted the background to the appropriate place and call the @TILER subroutine. Since OX,OY are zeros, I guess I don't need to shift the background (using BGOFS), but I'm doing it here for consistency.


  1. OX=32:OY=0:RX=31:RY=23:READ P$
  2. LOAD "GRP0:"+P$,FALSE
  3. BGOFS 0,OX*8,OY*8,60:GOSUB @TILER

  4. OX=0:OY=24:RX=31:RY=23:READ P$
  5. LOAD "GRP0:"+P$,FALSE
  6. BGOFS 0,OX*8,OY*8,60:GOSUB @TILER

  7. OX=32:OY=24:RX=31:RY=23:READ P$
  8. LOAD "GRP0:"+P$,FALSE
  9. BGOFS 0,OX*8,OY*8,60:GOSUB @TILER

  10. OX=0:OY=48:RX=31:RY=15:READ P$
  11. LOAD "GRP0:"+P$,FALSE
  12. BGOFS 0,OX*8,OY*8,60:GOSUB @TILER

  13. OX=32:OY=48:RX=31:RY=15:READ P$
  14. LOAD "GRP0:"+P$,FALSE
  15. BGOFS 0,OX*8,OY*8,60:GOSUB @TILER


As you can see, only the first line is being changed. I could have just put the whole thing into a subroutine. However, I'm not doing it because of the possibility that I don't have the whole 6 graphics to play with. If I only have four graphic screens, for example, it's easy for me to just comment out the necessary lines. This is judgement call, so you can certainly do it different. Whatever works.


  1. @SAVEBG
  2. SAVE "SCU0:T0"
  3. FOR I=0 TO FLOOR(MT/256)
  4. B$="BGU"+STR$(I)
  5. SAVE B$+":B"+STR$(I)
  6. NEXT 
  7. WAIT 300


Even though this is labelled as a subroutine. This is just a piece of code. It's not being called by GOSUB. I simply put the label there because I don't need to use comment. I could have, but simply decided not to.


  1. FOR I=0 TO 99
  2. X=RND(512):Y=RND(512)
  3. BGOFS 0,X,Y,60:WAIT 60
  4. NEXT
  5. WAIT 300


This is simply the scrolling of the background. You see 60 at the end of BGOFS call. This is equivalent of one second. So, I scroll for one second, while waiting for one second. What happens if I don't wait? Then the scroll will be reset immediately.


  1. BGCLR
  2. CHRINIT "BGU0"
  3. CHRINIT "BGU1"
  4. CHRINIT "BGU2"
  5. CHRINIT "BGU3"
  6. GCLS

  7. END


This code is necessary to reset the states to the original state. Otherwise, you will see that your screen is overlaid with your background. Of course, during debugging, that's quite problematic for me, since oftentimes the program does not run to completion, so I end up doing these commands by hand.


  1. @TILER
  2. FOR Y=0 TO RY:FOR X=0 TO RX
  3. X1=X*8:X2=X1+7:Y1=Y*8:Y2=Y1+7
  4. GOSUB @TILESTR
  5. CT=-1:FOR I=MT TO 0 STEP -1
  6. IF G$==TL$[I] THEN CT=I
  7. NEXT
  8. IF CT==-1 THEN GOSUB @SETCHR
  9. BGPUT 0,OX+X,OY+Y,CT,0,0,0
  10. NEXT:NEXT
  11. RETURN


There's some confusion here. I should have put the X1,X2,Y1,Y2 line into @TILESTR as it serves no purpose here. TL$[I] is the 64 hexadecimal string that contains the tile info. What the program does is simply set CT (Current Tile) to -1. Whenever the tile is found, CT is set to I. If the tile is not found, then CT will contain the value of -1. Then we know to store the current string (G$) into the tile array. After that, it's trivial to just set CT into the background.

Notice that I'm not doing mirror comparison. The documentation mentioned X,Y rotation. I'm ignoring that here. Actually, those aren't X,Y rotation. Those are mirror flip. If you want to you may want to modify the code to include that check. It's easy enough to do.


  1. @TILESTR
  2. G$=""
  3. FOR YY=Y1 TO Y2
  4. FOR XX=X1 TO X2
  5. G$=G$+HEX$(GSPOIT(XX,YY)%16)
  6. NEXT:NEXT
  7. RETURN


I have to make a decision here. Graphic screens can handle 256 colors. BG tiles can only handle 16 colors. What do I do? Well, if you notice, BG colors can actually have 240 colors. 256 colors-16 transparent colors. You can differentiate the different palettes, but I simply decided not to.

If you want to differentiate the palettes, then you want to store FLOOR(GSPOIT(XX,YY)/16) value and enter it into G$ so that it doesn't match equivalent pattern but different palette.

Another factor to consider is the X,Y mirror. Now you see why there's X1,X2,Y1,Y2. This is done for ease of mirroring. Normal: Y1-Y2/X1-X2. X Mirror: Y1-Y2/X2-X1. Y Mirror: Y2-Y1/X1-X2. XY Mirror: Y2-Y1/X2-X1. Note that I haven't done so, so the above is not guaranteed to work. Making it work is left as homework for the readers. ;)


  1. @SETCHR
  2. MT=MT+1:IF MT>1023 THEN MT=1023
  3. TL$[MT]=G$:CT=MT
  4. BU$="BGU"+STR$(FLOOR(MT/256))
  5. CHRSET BU$,MT%256,G$
  6. RETURN


Nothing to it. This simply increment the MT (MaxTile) counter and set the character to the appropriate BGUX bank.

And there you go. A very easy to do Background Maker. Here is the whole completed source code for your convenience. I suppose I should do the QR. Well, maybe sometimes in the future, or maybe not. Easy enough for you to do it by hand.



  1. 'BGMAKER BY HARRY HARDJONO
  2. CLS:CLEAR:DIM TL$[1024]:MT=-1
  3. @PICFILE
  4. DATA "G1","G2","G3","G6","G5","G4"
  5. RESTORE @PICFILE

  6. 'LOAD GRPS
  7. OX=0:OY=0:RX=31:RY=23:READ P$
  8. LOAD "GRP0:"+P$,FALSE
  9. BGOFS 0,OX*8,OY*8,60:GOSUB @TILER
  10. OX=32:OY=0:RX=31:RY=23:READ P$
  11. LOAD "GRP0:"+P$,FALSE
  12. BGOFS 0,OX*8,OY*8,60:GOSUB @TILER
  13. OX=0:OY=24:RX=31:RY=23:READ P$
  14. LOAD "GRP0:"+P$,FALSE
  15. BGOFS 0,OX*8,OY*8,60:GOSUB @TILER
  16. OX=32:OY=24:RX=31:RY=23:READ P$
  17. LOAD "GRP0:"+P$,FALSE
  18. BGOFS 0,OX*8,OY*8,60:GOSUB @TILER
  19. OX=0:OY=48:RX=31:RY=15:READ P$
  20. LOAD "GRP0:"+P$,FALSE
  21. BGOFS 0,OX*8,OY*8,60:GOSUB @TILER
  22. OX=32:OY=48:RX=31:RY=15:READ P$
  23. LOAD "GRP0:"+P$,FALSE
  24. BGOFS 0,OX*8,OY*8,60:GOSUB @TILER

  25. @SAVEBG
  26. SAVE "SCU0:T0"
  27. FOR I=0 TO FLOOR(MT/256)
  28. B$="BGU"+STR$(I)
  29. SAVE B$+":B"+STR$(I)
  30. NEXT 
  31. WAIT 300

  32. FOR I=0 TO 99
  33. X=RND(512):Y=RND(512)
  34. BGOFS 0,X,Y,60:WAIT 60
  35. NEXT
  36. WAIT 300

  37. BGCLR
  38. CHRINIT "BGU0"
  39. CHRINIT "BGU1"
  40. CHRINIT "BGU2"
  41. CHRINIT "BGU3"
  42. GCLS

  43. END

  44. @TILER
  45. FOR Y=0 TO RY:FOR X=0 TO RX
  46. X1=X*8:X2=X1+7:Y1=Y*8:Y2=Y1+7
  47. GOSUB @TILESTR
  48. CT=-1:FOR I=MT TO 0 STEP -1
  49. IF G$==TL$[I] THEN CT=I
  50. NEXT
  51. IF CT==-1 THEN GOSUB @SETCHR
  52. BGPUT 0,OX+X,OY+Y,CT,0,0,0
  53. NEXT:NEXT
  54. RETURN

  55. @TILESTR
  56. G$=""
  57. FOR YY=Y1 TO Y2
  58. FOR XX=X1 TO X2
  59. G$=G$+HEX$(GSPOIT(XX,YY)%16)
  60. NEXT:NEXT
  61. RETURN

  62. @SETCHR
  63. MT=MT+1:IF MT>1023 THEN MT=1023
  64. TL$[MT]=G$:CT=MT
  65. BU$="BGU"+STR$(FLOOR(MT/256))
  66. CHRSET BU$,MT%256,G$
  67. RETURN



Tuesday, August 6, 2013

Petit Computer Journal #4

Input + Math Tutorial


Knowing that computer is composed of numbers makes it easy to understand. That does not make it easy to do, you see, just to understand. The point is: The computer does what you tell it to do, not what you think you tell the computer to do. Faulty language implementation is an exception to that rule, and even then, you need to figure out a way around the problem.

Computer programming can be fun, but it can be very frustrating, indeed. The question is, what will you do to make computer programming fun? If the answer is to make games, then you're probably off to the wrong start. If the answer is to make games that people want to play, then you're probably off to the right start.

You see, computer programming is all about problem solving. What problem are you trying to solve? Without a clear goal, you probably will just do things randomly. Maybe you discover something, or maybe not. With a clear goal, however, you can work on the steps to achieving that goal. Then, when you finally solve that problem and arrive at your goal, your satisfaction level is quite high. That, my friend, is the fun of computer programming.

It's like winning a game, solving a puzzle, guessing a riddle. Before you did it, you don't know. After you did it, you know. That's fun.

Speaking of goals, you are still a beginner, so let's keep things simple for now. Let's start by figuring out how to tell a computer to do something simple.

Inkey$, input, linput

Let's get the keyboard input out of the way real quick. What is the difference between INKEY$, INPUT, and LINPUT? Write a small program to check it out!

'Keyboard input source code example
@MAINLOOP
VSYNC 1: A$=INKEY$
IF A$!="" THEN B$=A$
LOCATE 0,0:?"A$=";A$;"   "
LOCATE 0,2:?"B$=";B$;"   "
GOTO @MAINLOOP

There are 3 things you have to see here:
VSYNC 1: This synchronized the system 1/60 second. Try it with different values and see what happens!
A$=INKEY$: This gets the keyboard value and assign it to A$
IF A$!="" THEN B$=A$: Since the value disappear at the next iteration, and we want to keep the old value, we assign the value of A$ to B$, but only if there is something to copy.

And that's it! If you are writing a computer game that cannot wait for user input, then INKEY$ is the way to go. I understand that it isn't the easiest to use, but it's there if you want it.

What's the difference between INPUT and LINPUT? Try them out and see!

@MAINLOOP
VSYNC 1: INPUT "X,Y",X,Y
?"X=";X:?"Y=";Y
?:?:'DOUBLE BLANK LINES
VSYNC 1: LINPUT "DATA:";A$
?"A$=";A$
WAIT 300
GOTO @MAINLOOP

INPUT takes several inputs and assign them to different variables. This is very useful for inputting numeric values. Just type them out and separate them with comma. LINPUT takes in a string, commas included. Just one string.

Can you take string and numbers using INPUT? Try it and see!

@MAINLOOP
VSYNC 1: INPUT "X$,Y",X$,Y  '<==change here
?"X=";X$:?"Y=";Y            '<==Change here
?:?:'DOUBLE BLANK LINES
VSYNC 1: LINPUT "DATA:";A$
?"A$=";A$
WAIT 300
GOTO @MAINLOOP

Yes, you can! If the program doesn't understand your input, it will ask you to re-enter the data "?Redo from start". In which case, you re-enter the data, hopefully without mistake this time!


Touch Screen TCHX,TCHY,TCHST,TCHTIME PNLTYPE


Buttons and keyboard are nice, but we have something there that is just begging to be used: Touchscreen! I know I'm bucking the convention here, since most people are satisfied writing their beginner's program using INPUT or BUTTON(), but I really want to use the touch screen. Fortunately, it's as easy to use as INKEY$.

It's just some variables, and you even use it like you do INKEY$. The difference is that there is more than one, and you use numeric variables. Let's do it. It is helpful if we disable the on-screen keyboard. We do it via PNLTYPE command. Simply set it to "OFF".

'Touchscreen input source code example
PNLTYPE "OFF"
CLS
@MAINLOOP
VSYNC 1
X=TCHX:Y=TCHY:S=TCHST:T=TCHTIME
LOCATE 0,0:?"X=";X;"   "
LOCATE 0,2:?"Y=";Y;"   "
LOCATE 0,4:?"S=";S;"   "
LOCATE 0,6:?"T=";T;"   "
GOTO @MAINLOOP

Hit the Select button to stop the program. Yup. Just like INKEY$. The difference is, X and Y values are not reset to zero when the stylus is off the screen even though the status (TCHST) and timer (TCHTIME) are reset.


Math - Arithmetic


Alright, I need you to confess: Who among you have not yet finished 1st Grade? You know, the school grade right after Kindergarten? Whaat? You don't know Arithmetic? Oh, dear. This is bad. I think maybe you need to learn how before we can continue.

Haha, joking aside, you do need to know Arithmetic. Some Trigonometry, too. How about Algebra? Yes, you do need to know how to manipulate variables. Fortunately, if you know Show-and-Tell, you may be alright. Here's a little something that's useful to know: Mapping function.

map() is something that is built-in in Processing computer programming language. It's a good programming language. Check out www.processing.org for details.

In the meantime, let's implement it in BASIC. The idea is, if you have a number that is between two numbers, given another two numbers, what will be the number that has the same ratio as the first? In mathematical format, assuming X is the first number, and Y is the second, we have

X1-X2-X3 X2 is between X1 & X3
Y1-Y2-Y3 Y2 is between Y1 & Y3
Since the ratio is the same, we have
(X2-X1)/(X3-X1)=(Y2-Y1)/(Y3-Y1)

Solve for Y2:
(Y2-Y1)/(Y3-Y1)=(X2-X1)/(X3-X1)
(Y2-Y1)=((X2-X1)/(X3-X1))*/(Y3-Y1)
Y2=(((X2-X1)/(X3-X1))*/(Y3-Y1))+Y1

And that's all there is to it! Work it out on paper if you're having trouble. I find it helpful to draw triangles to visualize the problem.


A Math Explorer sample program


We want to feature a lot of math here, so we're going to just do it all in one program. The program will features different modes, and take inputs from touch screen, normalized to 0-5 for both X and Y. Furthermore, if the stylus is on top-left corner, we'll change the mode.

0: Simple Arithmetic
1: Math functions
2: Logical Math
3: Exponent

Here goes:

Part 1: Touch screen input. No problem there. Just copy it from the sample program above.


'Math Explorer
PNLTYPE "OFF"
CLS
@MAINLOOP
VSYNC 1
X=TCHX:Y=TCHY:S=TCHST:T=TCHTIME

Part 2: Display X,Y, Mode, and Cycle Mode. If you remember our COUNTER program example? Yup, just like that!

IF (X<32 AND Y<24 AND T==1) THEN MODE=MODE+1
MODE=MODE%4:'MODE=0-3
LOCATE 0,0
?"X=";X;"     Y=";Y;"     MODE=";MODE


Part 3: Normalize X and Y. We already have the mathematical formula for this. Just implement that using GOSUB.

X1=0:X2=X:X3=255:Y1=0:Y3=5:GOSUB @MAP:XP=Y2:'CALCULATES XP=Y2
X1=0:X2=Y:X3=191:Y1=0:Y3=5:GOSUB @MAP:YP=Y2:'CALCULATES YP=Y2
?"XP=";XP;"     YP=";YP;"     "

GOTO @MAINLOOP

@MAP
Y2=(((X2-X1)/(X3-X1))*(Y3-Y1))+Y1
RETURN


And that's the beginning. We'll continue with Part 4 next, but first, run this program and see that we have normalized XP and YP, and that the MODE cycles 0-3 satisfactorily.



Change the program slightly to this before continuing. Yes, I expect you to be able to read! I know it's hard in the beginning, but please persevere.

'Math Explorer
PNLTYPE "OFF"
CLS
@MAINLOOP
VSYNC 1:IF MODE!=2 THEN CLS
X=TCHX:Y=TCHY:S=TCHST:T=TCHTIME

IF (X<32 AND Y<24 AND T==1) THEN MODE=MODE+1
MODE=MODE%4:'MODE=0-3
LOCATE 0,0
?"X=";X;"     Y=";Y;"     MODE=";MODE;"     "

X1=0:X2=X:X3=255:Y1=0:Y3=5:GOSUB @MAP:XP=Y2:'CALCULATES XP=Y2
X1=0:X2=Y:X3=191:Y1=0:Y3=5:GOSUB @MAP:YP=Y2:'CALCULATES YP=Y2
?"XP=";XP;"     YP=";YP;"     "

GOTO @MAINLOOP

@MAP
Y2=(((X2-X1)/(X3-X1))*(Y3-Y1))+Y1
RETURN


And that's the program. Now, here is some snippets of code. I trust that you know where to put this.

?:?
ON MODE GOTO @ARIT, @FUNC,@LOGI, @EXPO
GOTO @MAINLOOP:'INVALID CHOICE

@ARIT
?"X+Y=";(X+Y)
?"X-Y=";(X-Y)
?"X*Y=";(X*Y)
IF Y!=0 THEN ?"X/Y=";(X/Y)
IF Y!=0 THEN ?"X%Y=";(X%Y)
IF YP!=0 THEN ?"X%YP=";(X%YP)
GOTO @ENDLOOP

@FUNC
?"FLOOR(XP)=";FLOOR(XP)
?"RND(X)=";RND(X)
?"RND(XP)+20=";RND(XP)+20
?"ABS(X-128)=";ABS(X-128)
?"SGN(X-128)=";SGN(X-128)
?"SWAP  ":SWAP XP,YP
?"XP=";XP;"     YP=";YP
IF S==1 THEN WAIT 30
GOTO @ENDLOOP


@LOGI
LOCATE 0,4
?"X=  ";:V=X:GOSUB @BIN
?"Y=  ";:V=Y:GOSUB @BIN
?"AND ";:V=(X AND Y):GOSUB @BIN
?"OR  ";:V=(X OR Y):GOSUB @BIN
?"XOR ";:V=(X XOR Y):GOSUB @BIN
?
?"X=  ";:V=X:GOSUB @BIN
?"NOT ";:v=NOT(X):GOSUB @BIN
?"!   ";:v=!X:GOSUB @BIN
GOTO @ENDLOOP

@EXPO
?"SQR(X)=";SQR(X)
?"EXP(XP)=";EXP(XP)
IF X!=0 THEN ?"LOG(X)=";LOG(X)
?"POW(2,XP)=";POW(2,XP)
?"POW(3,XP)=";POW(3,XP)


@ENDLOOP
GOTO @MAINLOOP

'SPLIT THIS TO THE END

@BIN
FOR I=0 TO 7
P=POW(2,I)
IF (P AND V) THEN ?"1"; ELSE ?"0";
NEXT
PRINT
RETURN




One more round of Math and we'll be done! It's all about Trigonometry. We'll save it for later until after we learn Graphics!