Showing posts with label qr. Show all posts
Showing posts with label qr. Show all posts
Tuesday, September 4, 2012
Lotto Number Picker
There is something to be said for a well written plan. It's easy to follow through. OTOH, there is more than one way to skin a cat, and there's more than one way to code a program.
This Petit Computer program was done while docked at King Sooper, waiting to be unloaded. It's very easy to do, and it is proof that computer programming can be convenient, fun, and with potential of great reward!
Look at the algorithm and see if you can follow the code! Feel free to modify to suit!
'LOTTO NUMBER PICKER
'THE ALGORITHM:
'1. TITLE AND INITIALIZATIONS
'2. FILL BALL ARRAY 1 TO MAXNUM
'3. RANDOMIZE BALL ARRAY
'4. FOR I=1 TO NUMBER OF BALLS
'4.1 IF BALL NUMBER < 10, ADD LEADING ZERO
'4.2 APPEND TO TICKET ARRAY STRING
'5. REPEAT STEPS 3-4 UNTIL NUMBER OF TICKETS
'6. FOR I=1 TO NUMBER OF TICKETS
'6.1 PRINT TICKET$ ARRAY. ONE PER LINE
'7. PRESS ANY KEY TO CONTINUE. BACK TO TOP
@STEP1
CLS:CLEAR:COLOR 2
?"LOTTO GENERATOR"
?"(C) 2012 Harry M. Hardjono"
MN=42:'MAXNUM 1-42
NB=6:'NUMBER OF BALLS
NT=20:'NUMBER OF TICKETS
@STEP2
@STEP3
@STEP4
@STEP5
REM THEN A MIRACLE OCCURS...
@STEP6
FOR I=0 TO NB*NT-1:C$=CHR$(RND(MN)+101)
IF !(I%NB) THEN LOCATE 0,I/NB+3:S$="":COLOR I/NB/3%2+4
IF 0>INSTR(S$,C$) THEN ?RIGHT$(STR$(ASC(C$)),2);" ";:S$=S$+C$ ELSE I=I-1
NEXT
@STEP7
FOR I=0 TO 1:I=TCHST OR BUTTON(0):NEXT
GOTO @STEP1
Monday, September 3, 2012
Petit Computer Journal #5
Petit Computer Journal #5 - Buttons and Touchscreen
Let's take a little detour for now. We should be doing strings and graphics, but I want to do something else real quick: Buttons, Touchscreen, and Keyboard. In other words: INPUT.
We have done buttons, touchscreen, and keyboard inputs before. However, I'm interested in doing them all at once. And the trick is to do it without stopping the other input methods. That's not too easy.
Regarding keyboard input method that doesn't stop other process, we have INKEY$. We also have touchscreen variables TCHX,TCHY and all those. How about buttons? We have BUTTON(0), and that is sufficient. So, at the surface, we have all that we need.
The thing is, I don't want to have to structure the program into multi-threading format at this point in time. So, we will have to make some sacrifices. The INKEY$ is well enough. How about buttons and touchscreen?
In Touchscreen, it is convenient to have a drag-and-drop process. That means X1,Y1,X2,Y2,TouchStatus. Let's build that capability.
@SETT
IF TCHST==0 THEN TS1=TCHST:RETURN
IF TS1==0 THEN TX1=TCHX:TY1=TCHY:TS1=1
IF TS1==1 THEN TX2=TCHX:TY2=TCHY
TS1=TCHST
RETURN
That looks simple enough. Basically, we want to update the variables if TCHST==1. The first line takes care of that by returning from subroutine if TCHST==0. Next, we want to see which pair we want to update X1,Y1 or X2,Y2? And that's all there is to it!
The buttons isn't so simple, though. There are 4 possible arrangements that I can see:
1. No Wait+Multiple: BUTTON(0)
2. No wait+Single: @SETB1
3. Wait+Multiple: @SETB2
4. Wait+Single: @SETB3
Of these, we want no wait version. If the no wait version is equivalent to INKEY$, then the wait version is equivalent to INPUT. The whole process involve trying out different versions of the commands. You see the finished product as clean, but I assure you that the process involves repeatedly trying and failing to come up with that clean method. You do not see the hard work that is done. At least, if you ever wonder why my progress is at glacial pace, you know the reason: Lacking tutorial such as this, I do a lot of experiments, not all of them successful.
There are 4 cases and only 3 subroutines. The first case can be easily met via BUTTON(0). The rest is done with simple subroutines. It only works on the first 8 bits, corresponding to UDLRABXY. This is because the method I use requires string characters, and those only goes to 255. I typed in the character in the actual program, but for the purpose of tutorial there are two index variables used by INSTR()
1. IST1$=CHR$(128)+CHR$(64)+CHR$(32)+CHR$(16)+CHR$(8)+CHR$(4)+CHR$(2)+CHR$(1)
2. IST2$=CHR$(129)+CHR$(65)+CHR$(33)+CHR$(17)+CHR$(9)+CHR$(5)+CHR$(3)+CHR$(2)
I use this technique a lot as it simplifies things greatly. It's not the fastest running code, and so only amateur hobbyist would use it. Certainly not a professional quality code. If need be, I may changed the code later to a more efficient one. But I like doing rapid prototyping in the beginning.
One more thing, the no wait version is tricky. If you check out the clock, you will see that no-wait @SETB1 does cause the program to stop when you press the button for a long time. A way to fix this would be to use a variable, but I would rather just do it directly with BUTTON(0) or @SETB2.
@SETB1 :'SINGLE FIRE
INBUTTON$="":Z=BUTTON(0):IF!Z THEN RETURN
FOR Z=0 TO 1:Z=BUTTON(3):NEXT:Z=Z AND 255
Z=INSTR(IST2$,CHR$(Z)):IF Z< 0 THEN RETURN
INBUTTON$=MID$("YXBARLDU",Z,1)
RETURN
@SETB2 :'CONTINUOUS
INBUTTON$="":Z=BUTTON(0):IF!Z THEN RETURN
Z=Z AND 255:Z=INSTR(IST1$,CHR$(Z)):IF Z< 0 THEN RETURN
INBUTTON$=MID$("YXBARLDU",Z,1)
RETURN
@SETB3 :'WAIT
INBUTTON$=""
FOR Z=0 TO 1:VSYNC 1:Z=BUTTON(1):NEXT:Z=Z AND 255
Z=INSTR(IST2$,CHR$(Z)):IF Z< 0 THEN RETURN
INBUTTON$=MID$("YXBARLDU",Z,1)
RETURN
And those are the functions. Next, let's write a quick demo program to demonstrate the different functions. It may be best that you write a program and save it because you will be using this at all times. I know I do!
'BUTTON/TOUCHSCREEN TEST EXAMPLE
CLS:CLEAR:P1=0:P2=1
@MAINLOOP
LOCATE 0,0:?TIME$
VSYNC 1:A$=INKEY$():?A$
GOSUB @SETB1:'?INBUTTON$;
GOSUB @SETT
IF INBUTTON$!="" OR TS1 THEN GOSUB @DT
GOTO @MAINLOOP
@DT :'DRAW TEXT
IF INBUTTON$!="" THEN L1=(L1+1)%32:LOCATE L1,1:?INBUTTON$;
'DRAW BOX
IF INBUTTON$=="L" THEN P1=P1+15
IF INBUTTON$=="R" THEN P1=P1+1
IF INBUTTON$=="U" THEN P2=P2+15
IF INBUTTON$=="D" THEN P2=P2+1
P1=P1%16:P2=P2%16
SX1=FLOOR(TX1/8):SY1=FLOOR(TY1/8)
SX2=FLOOR(TX2/8):SY2=FLOOR(TY2/8)
FOR X=SX1 TO SX2:FOR Y=SY1 TO SY2:
C$=CHR$(151):COLOR P2:'0=BIG BLOCK CHARACTER IN PETIT COMPUTER
IF X==SX1 OR X==SX2 THEN C$=CHR$(150):COLOR P1:'1=VERT LINE
IF Y==SY1 OR Y==SY2 THEN C$=CHR$(149):COLOR P1:'2=HORZ LINE
IF X==SX1 AND Y==SY1 THEN C$=CHR$(152):COLOR P1:'3=UPPERLEFT
IF X==SX2 AND Y==SY1 THEN C$=CHR$(153):COLOR P1:'4=UPPERRIGHT
IF X==SX1 AND Y==SY2 THEN C$=CHR$(154):COLOR P1:'5=LOWERLEFT
IF X==SX2 AND Y==SY2 THEN C$=CHR$(155):COLOR P1:'6=UPPERRIGHT
LOCATE X,Y:?C$;
NEXT:NEXT
RETURN
For some reason, my computer does not read my memory card. That's a setback. I have to have those special characters, and so, I'm forced to do it the hard way, which is very annoying. However, either I overcome that setback, or I don't do this at all. I can work on the DSi no problem, but if I want to share it, I have to do this thankless work of translating those characters into their numeric equivalent. I wrote a simple program just for that:
'ASCII TABLE
S=0
@MAINLOOP
CLS
FOR I=S TO S+15
R=I%16
LOCATE 0,R:?I;:LOCATE 5,R:?CHR$(I)
NEXT
GOSUB @SETB3
IF INBUTTON$=="U" THEN S=S+16
IF INBUTTON$=="D" THEN S=S+256-16
S=S%256
?:?"S=";S;" ";INBUTTON$:WAIT 60:'OPTIONAL FOR DEBUGGING
GOTO @MAINLOOP
And that's it. Not even 10 minutes. You need to provide Subroutine @SETB3, but that's trivial. Just copy the one above.
Problems and How to Ask Questions
You know how people say there's no such thing as stupid questions? I know I'm bucking the convention here, but I'd say there are! Here's a sample, quoted in its entirety:
"Help! SAVE doesn't work."
I'm not saying that SAVE command is so easy that it cannot fail. I am saying that the question doesn't even begin to show the framework in which the problem occurs. We need more data! You know how PRINT statement works, right? What if there's somebody who ask help like this: "How do you use PRINT?", following your answer with "It doesn't work."
You know it works, and you know how it works. The problem is, how does it doesn't work? You have no clue as to what problem this person encounter. So, here is how you handle a problem that you cannot solve, because the unwritten rule is, if you ask a question that you later answer without any prompting whatsoever, YOU JUST ASKED A STUPID QUESTION THAT YOU KNOW THE ANSWER TO!
Problem solving technique:
1. Ran into problem, WRITE IT DOWN!
2. Write down all the relevant elements.
3. Read the Manual/Help file
4. WRITE ALL THE POTENTIAL SOLUTIONS DOWN.
5. Implement them all.
That's step-by-step. You are not allowed to skip steps. Half of your problems can be solved this way. As for the rest, well, that's when it gets tricky.
Hard Problem Solving:
1. You are tired. STOP AND GO TO SLEEP!
2. Wake up. Eat something solid
3. Repeat problem solving steps above.
By this time, if you followed this advice, a lot of you would do a lot of face palming "Of course! Why didn't I think of that?" sequence. That happens to me, too.
Stubborn Problem Solving:
1. You are sadly misunderstanding the problem. YOU are at fault!
2. Find 3 different interpretations to the problem.
3. Also, find 3 different OTHER places where it may cause the problem.
4. Consult the manual for help.
It may help to pretend that you're a newbie who doesn't understand everything. Don't laugh. It works! I used that technique myself occasionally. For the next level you must first admit that you are stupid. No, really. You are! You may humbly ask other people for help. Ever seen somebody arrogantly ask for solution to their problem? That never gets resolved, does it? Bingo.
Impossible Problem Solving:
1. Explain What the Problem is
2. Tell what you think are the relevant elements
3. Show what you did to solve the problem
4. WRITE THE SIMPLEST, SHORTEST CODE to explain the problem.
That last element is vital. No one wants to read 200 lines of code just to debug your program. So, there. Problem solving explained. Either that or you explain your problem to a duck.
Haha, joking aside, the ability to properly explain your problem is crucial in getting it solved. You don't want to ask a question like a grade schooler if you can ask your questions like a professor!
My PRINT doesn't work!
1. Did you type it in RUN(direct) mode or EDIT (deferred) mode?
2. Did it give you Syntax Error?
3. Did it print 0?
4. Did you set VISIBILITY?
What if PRINT doesn't work because it was set to XOR Mode? How will you respond to that? You can't set Console to XOR mode, right? How does that work? This is where giving out sample code is crucial.
CLS
COLOR SET XOR ! DOIT
PRINT "HELLO WORLD"
SET and DOIT ARE not keywordS. Why is there an exclamation mark preceding it? Because when I put it after the word (DOIT!), the computer complained, DUH!
You see how sample source code clarifies the issue quickly and easily? Don't act like a grade schooler. Ask questions like a professor! When I see the words "I don't understand ..." it'd better be followed by "These are the things I tried in order to understand it."
Monday, August 20, 2012
Petit Computer Journal#3
Petit Computer Journal #3
How to use Buttons and Directional Pad
Let's do something real quick. Let's make a counter that will increase when a button is pushed. Looking at the various commands, it is obvious that it is either BUTTON() or BTRIG(). Let's use BTRIG(). Reading the Help entry shows that the value returned by BTRIG() is usually 0. Non-zero if there's a button pushed. Perfect. We come up with this very quickly:
CLS
@COUNTER
B=BTRIG()
IF B==0 GOTO @COUNTER
A=A+1:A=A%1000:'0-999 CYCLE
?A;" "
GOTO COUNTER
We run the program, and press a button. We see that the counter increments, all right. And it cycles to 999 like it should. However, the program registers so many button presses. That is not what we want. We want 1 increment per button push. So, we need to fix it. At this point, most people would do the sensible thing and type into Google: "Petit Computer how to use button".
Haha, joking aside, we do need to understand how to read buttons properly. What do we do when the platform does not have built-in debugger? Well, we make our own!
What to do when things go wrong
I know I'm bucking the convention, here, but writing self-debugging program isn't that much trouble. The most important thing is that you want to understand what's going on. The simplest, easiest method to do it is read the manual. When the manual fails, however, we need to do better. That means we need to try things out and see what happens. It's called, "Learning without a teacher" or "Research". If you passed high school, then you know how to do it.
First make a hypothesis: One button press=one event. (desired behavior)
Then gather data: One button press=many events (observed)
Therefore, the conclusion is: what we want, and what we have are two different things. Error!
There are many kinds of errors in computer programming, but let's just simplify things a bit for now.
Computers are stupid, remember? If you mistype a command, the computer cannot handle it. If you forget a variable, the computer cannot handle it. If you transposed commands or letters or anything, the computer cannot handle it. The computer will complain: "Syntax Error!" That means, you have typed something incorrectly as to confuse the computer.
Another kind of error occurs when you ask the computer to do the impossible. Dividing by zero is one. GOTO a unlabelled section is another. These kind of errors are called "Run-time Error", because they occur at the running of the program.
Sometimes the program runs fine, but doing something else than what we want. We want to roll 5 dice, but only 1 is rolled. That means that what we say and what we want to say are two different things. We need to figure out a different way to say what we want. This is called "Semantic Error".
If, however, your screen is cracked, plastic is chipped, and stylus bent, then we have what is called PEBKAC Error: Problem Exists Between Keyboard And Chair. You probably should stay off computer programming for a while.
A binary review
If you're wondering why the values for the buttons are 1,2,4,8 etc, the answer is that the buttons do not have separate variables. The figure is all one number! There are different bits to the number, and that is what we're seeing. We can take a look at various bits by doing this code:
V=9
FOR I=0 TO 7
P=POW(2,I)
IF (P AND V) THEN ?"1"; ELSE ?"0";
NEXT
In this case, we're doing a "Binary AND" (instead of "Logical AND") using bit 0-7. You can, of course, increase the bits to 31. I'm trying to keep it simple. Try putting in different values into V variable.
Source code for button readings
If we want to see what the buttons do, then it is very simple to do this:
CLS
@MAINLOOP
A=BUTTON(0)
B=BUTTON(1)
C=BUTTON(2)
D=BUTTON(3)
E=BTRIG()
LOCATE 0,0
?"BUTTON(0) ";:V=A:GOSUB @BIN
?"BUTTON(1) ";:V=B:GOSUB @BIN
?"BUTTON(2) ";:V=C:GOSUB @BIN
?"BUTTON(3) ";:V=D:GOSUB @BIN
?"BTRIG() ";:V=E:GOSUB @BIN
'PLACEHOLDER
GOTO @MAINLOOP
@BIN
FOR I=0 TO 7
P=POW(2,I)
IF (P AND V) THEN ?"1"; ELSE ?"0";
NEXT
RETURN
You can see the flickers for Button 1-3. That means the change happens in an instant. In this case, the change happens only in one frame, or 1/60 of a second. That's fast! I also see that the flickers on B is identical with the flicker on E. From that, I deduce that BTRIG() is equivalent to BUTTON(1). Is there any delay or waiting either with BTRIG() or BUTTON()? None that I can see.
If you want to make sure, replace the "'PLACEHOLDER" with these lines:
IF A!=E THEN LOCATE 0,7 :V=A:GOSUB @BIN:V=E:GOSUB @BIN
IF B!=E THEN LOCATE 0,10:V=B:GOSUB @BIN:V=E:GOSUB @BIN
IF C!=E THEN LOCATE 0,13:V=C:GOSUB @BIN:V=E:GOSUB @BIN
IF D!=E THEN LOCATE 0,16:V=D:GOSUB @BIN:V=E:GOSUB @BIN
The suspicion that BTRIG()==BUTTON(1) is confirmed! Now that's what I call successful research!
The fixed source code
Now that we know what is happening, we can do different things to fix it.
First, we can specify that the increase is between Button Push and Button Release, like so:
CLS
@COUNTER
B=BUTTON(2)
IF B==0 GOTO @COUNTER
A=A+1:A=A%1000:'0-999 CYCLE
@C2
B=BUTTON(3)
IF B==0 GOTO @C2
?A;" "
GOTO COUNTER
And that works nicely. However, let's see if we can improve things a bit. The manual mention VSYNC 1, as a way to get the input right. So, let's use that
CLS
@COUNTER
B=BUTTON(2):VSYNC 1
IF B==0 GOTO @COUNTER
A=A+1:A=A%1000:'0-999 CYCLE
?A;" "
GOTO COUNTER
That also works, and notice that it is cleaner. What happens if VSYNC is set to something other than 1? Try it! You'll see that you will be missing some button presses. The exception to that is if you use BUTTON(0), and only at the sync.
CLS
@COUNTER
B=BUTTON(0):VSYNC 15:IF B==0 GOTO @COUNTER
A=A+1:A=A%1000:'0-999 CYCLE
?A;" "
GOTO COUNTER
And that's what we want. Problem solved!
The rest of Console Entry Commands
Try out this command: BREPEAT 4,60,4
That will cause the A button to be repeated if you press it longer than 1 second. Pretty neat, eh?
Also, what is the difference between INKEY$, INPUT, and LINPUT?
INKEY$ behaves just like BUTTON(), in that it doesn't stop and wait for keypress.
LINPUT, LINE-INPUT, takes the whole line, including commas.
INPUT takes the line, and assign different values separated by commas.
And that's all there is to it!
Subscribe to:
Posts (Atom)