Asked by:
Challenge of the Month  January 2013

Welcome to the monthly SmallBasic Challenge!
These challenges are intended for people who are learning to program for the first time or for those returning to programming who want to start using SmallBasic. Some will be easy, some will be hard  but they will all make you think, and more importantly be GREAT FUN!
Please post your solutions / partial solutions / questions / feedback etc. into this thread that will remain 'sticky' for the month. The only rule is that your solution must use standard SmallBasic methods (no extensions).
It would be good if people could post their problems with these challenges so that a discussion can start so that everyone can learn from each other.
Also post feedback on the kind of challenges that you want to see more of in the future.
Small Challenge 1
Write a program to calculate the average of 10 random numbers (in the range 1 to 100). Then calculate the average of 100, 1000 or more of the random numbers. The average is just all the random numbers added together and then their total divided by the number of random numbers.
Small Challenge 2
Write a program to display a colorful welcome message in the GraphicsWindow when a button is clicked.
Small Challenge 3
Write a program to play 'Happy Birthday' or another well known tune using the Sound method.
Text Challenge
I have a lot of Small Basic files and they are not always well named  I can sometimes remember a variable name I used in one or some other phrase, but not the file name.
Write a program that searches all Small Basic programs in a directory to find all files (and the line numbers) containing a user input text.
Basically 'find a text' in files.
Physics Challenge
Write a program to reflect a light beam off a rotated surface.
Further challenge  make a game where the user must rotate the surfaces to get the beam to bounce off several surfaces and hit a target.
Community Suggestion Challenges
By Nonki Takahashi
1] Draw a picture of any zodiac (star) sign.
2] Write a quine. (Math Man early answer HRC429). Can you do it without a File command that reads the file, i.e. only File write commands?
By Amir CPS
1] Convert a number in decimal form to the equivalent mixed number with the fraction portion reduced to lowest terms.
Sample Input:
 2.96
 14.2
 5.625
Sample Output:
 2 AND 24/25
 14 AND 1/5
 5 AND 5/8
2] Read a string and determine whether each left parenthesis ‘(‘ has a matching right parenthesis ‘)’.
Sample Input:
 (3 + (7 * 2) – 6)
 HELLO AND (WELCOME (TO THE) SB (FORUM)
 TODAY) IS ((SATURDAY())
Sample Output:
 MATCH
 NO MATCH
 NO MATCH
3] The 8Queens problem in chess is to place 8 queens on a chess board such that none of the queens is threatening any of the others. The problem is to input the 8 columns of the queens on the rows of a chess board, with 1 being the first column and 8 being the last, e.g. 1 2 3 4 5 6 7 8 means the queens are along the diagonal, which would not be a valid solution.
Write a program to test a user input guess.
Examples:
 Enter board configuration: 2 4 6 8 3 1 7 5  This is a valid configuration (as above).
 Enter board configuration: 1 8 2 5 3 7 4 6  This is NOT a valid configuration.
Do you have an idea for a future challenge? Please post it here!
 Edited by litdevModerator Sunday, January 06, 2013 10:30 PM
General discussion
All replies

My solution for the Text Challenge is published as JDS276.
It can search for text with and without ignoring upper/lower case.
A simple sulution for Amir CPS Challenge 2 is:
''PARENTHESES 20130102 WhTurner t[1]="(3 + (7 * 2) – 6)" t[2]="HELLO AND (WELCOME (TO THE) SB (FORUM)" t[3]="TODAY) IS ((SATURDAY())" For i=1 To Array.GetItemCount(t) txt=t[i] TextWindow.WriteLine(txt) count=0 For j=1 To Text.GetLength(txt) char=text.GetSubText(txt,j,1) If char="(" Then count=count+1 EndIf If char=")" Then count=math.Max(0,count1) EndIf EndFor If count=0 Then TextWindow.WriteLine("MATCH") Else TextWindow.WriteLine("NO MATCH") EndIf TextWindow.WriteLine("") EndFor
Jan [ WhTurner ] The Netherlands
 Edited by WhTurner33Editor Wednesday, January 02, 2013 2:00 PM




If you put these lines instead of the IF/ENDIF with Math.Max in it it signals the lonely right parentheses, but gives then MATCH if the number left/right are equal.
If char=")" Then
count=count1
If count<0 then
TextWindow.WriteLine("Right parentheses before a left one")
EndIf
EndIf
Jan [ WhTurner ] The Netherlands



That works too, assuming there aren't 999 misplaced right parentheses!
Also if count is < 0 then there is no way we can get a MATCH so there is no point continuing counting  therefore slightly more efficient to Break out of the loop; most languages have a Break command for this  Small Basic doesn't hence using a GoTo for this is one option, or set i = Array.GetItemCount(t) which ends the loop.
 Edited by litdevModerator Wednesday, January 02, 2013 3:11 PM

Physics Challenge
LMB722
A spark to start a fire is necessary. But mainly you need dry kindling.
 Edited by Zock77Editor Wednesday, January 02, 2013 8:44 PM

Here is the code I wrote for the famous 8Queens problem in chess. I tried it on sevaral configurations and it turned out to work well. However I'm not still sure if there aren't any bugs. Try to find bugs and let me know (if any). Here is the link:
And here is the source code:
startover: TextWindow.WriteLine("Enter your configuraion as a serial number from left of the board to the right of the board(The nth character of your serial number represents the row at which the nth queen is located): ") config = TextWindow.Read() length = Text.GetLength (config) If length<>8 Then TextWindow.ForegroundColor = "red" TextWindow.WriteLine("There are supposed to be 8 queens, but your serial number has "+length+ " characters") TextWindow.ForegroundColor = "White" Goto startover EndIf For i=1 To length t[i] = Text.GetSubText(config, i, 1) EndFor For i=1 To length t2[i] = t[i] EndFor validity = "true" For i=1 To length For j=1 To length If t[i] = t2[j] And i<>j Then TextWindow.ForegroundColor = "Red" TextWindow.WriteLine("THIS IS NOT A VALID CONFIGURATION. The "+i+"th and the " +j+ "th queens threaten each other horizontally") TextWindow.WriteLine("") validity = "false" TextWindow.ForegroundColor = "White" Goto end EndIf EndFor EndFor If validity<>"false" Then For i=1 To length For j=1 To length If ((t[i] = t2[j]  (ij)) Or (t[i] = t2[j]  (ji))) And i<>j Then TextWindow.ForegroundColor = "Red" TextWindow.WriteLine("THIS IS NOT A VALID CONFIGURATION. The queen at the "+t[i]+"th row and "+i+"th column threatens the queen at the " +t2[j]+"th row and the "+j+"th column.") TextWindow.WriteLine("") validity = "false" TextWindow.ForegroundColor = "White" Goto end EndIf EndFor EndFor EndIf end: If validity = "true" Then TextWindow.ForegroundColor = "Red" TextWindow.WriteLine("It is valid configuration. Congratulations!") TextWindow.WriteLine("") TextWindow.ForegroundColor = "White" EndIf Goto startover
 Edited by Behnam Azizi Thursday, January 03, 2013 1:21 AM



My solution for the 8Queen problem.
Import : SMP050
@Nonki
Your program not working for me..??
@WhTurner33
Highlight the first lone right parenthesis if occurred or show a appropriate error message.
AndWhat about highlighting like this?
(3 + (7 * 2) – 6)
Merry Xmas!


Behnam,
Check source code of my program. I used unicode characters for chessmen.
Thanks.
Nonki Takahashi
 Edited by Nonki TakahashiModerator Friday, January 04, 2013 12:31 AM

Amir CPS,
Input such as "12345678".
Following inputs will be neglected.
"1 2 3 4 5 6 7 8"
"1234567"
"11234567"
"12345679"Or can't see any queens?
Nonki Takahashi
 Edited by Nonki TakahashiModerator Thursday, January 03, 2013 11:14 PM


A new version for the parentheses checking follows. It marks matching parentheses with a "graphical" textline, and marks lonely right parentheses, and nonmatched left parentheses.
''PARENTHESES 20130103 WhTurner space=" " line="^" t[1]="(3 + (7 * 2) – 6))(" t[2]="HELLO AND (WELCOME (TO THE) SB (FORUM)" t[3]="TODAY) IS ((SATURDAY())" t[4]="(aaa(bbb(ccc)(ddd)))) For i=1 To Array.GetItemCount(t) pos=0 a="" txt=t[i] TextWindow.ForegroundColor="Green" TextWindow.WriteLine(txt) TextWindow.ForegroundColor="Gray" For j=1 To Text.GetLength(txt) If Text.GetSubText(txt,j,1)="(" Then pos=pos+1 a[pos]=j endif If Text.GetSubText(txt,j,1)=")" Then If pos=0 then TextWindow.Write(Text.GetSubText(space,1,j1)) TextWindow.ForegroundColor="Red" TextWindow.Write("^") TextWindow.Write(" lonely right parentheses") TextWindow.ForegroundColor="Gray" TextWindow.WriteLine(" END checking") TextWindow.WriteLine("") j=999 ''end of check else TextWindow.Write(Text.GetSubText(space,1,a[pos]1)) TextWindow.WriteLine(Text.GetSubText(line,1,ja[pos])+"^") a[pos]="" pos=pos1 endif endif '' ) EndFor ''j (textlength) If pos>0 Then For k=1 To pos TextWindow.Write(Text.GetSubText(space,1,a[k]1)) TextWindow.ForegroundColor="Red" TextWindow.WriteLine("^") endfor TextWindow.WriteLine("unpaired left parentheses") TextWindow.WriteLine("") TextWindow.ForegroundColor="Gray" endif EndFor ''i (all teststrings)
Jan [ WhTurner ] The Netherlands
 Edited by WhTurner33Editor Thursday, January 03, 2013 1:01 PM



Amazing!! Didn't know that one could make such good shapes using unicode. Actually I don't have the knowledge to understand these yet.
I need a simple code by which I can learn the basics of making a shape using unicode characters. Can anyone help me?
 Edited by Behnam Azizi Thursday, January 03, 2013 7:22 PM

Behnam,
I couldn't find any bugs in your 8Queens program. I tried 3 nonvalid configurations and 13 valid configurations.
Test data:
NOT valid:
12345678
18253746
87654321
valid:
24683175
17468253
17582463
41582736
51842736
31758246
51468273
71386425
51863724
57142863
63184275
53172864
46827135
Nonki Takahashi
 Edited by Nonki TakahashiModerator Friday, January 04, 2013 12:32 AM

Behnam,
How to use unicode characters in Small Basic program:
(1) Find characters in charmap.exe.
I can find chessmen only in "MS UI Gothic" font.
(2) Copy characters (e.g. "♟") or their code (e.g. "U+265F").
(3) For code, convert hexadecimal to decimal (e.g. 265F > 9823) and use Text.GetCharacter(code).Nonki Takahashi

Small Challenge 1
Code :
' 'Challenge of the month : January 2013  'Category : Small Challenge 1  'Date 4/01/2013  DD/MM/YYYY  ' 'Title of the text window TextWindow.Title = "Avarage of sum of N number" 'Call main subrutine Init() Sub Init Sum = 0 TextWindow.Write("Enter number : ") 'Ask user to input a number Num = TextWindow.ReadNumber() 'Get user input and allow only if Num is a whole number If Math.Floor(Num)  Num <> 0 Or Num < 0 Then ' Show a error message if condition is not met Error() Else 'proceed further otherwise Go() EndIf EndSub Sub Go 'Generate random number GenRandomNums() 'sum em all SumofAllNum() 'Print the output on text window Print() EndSub Sub GenRandomNums For i = 1 To Num Rnd = Math.GetRandomNumber(100) RandomNums[i] = Rnd ' Store number in an array EndFor EndSub Sub SumofAllNum For i = 1 To Num Sum = Sum + RandomNums[i] 'Sum all of them EndFor EndSub Sub Print For i = 1 To Num TextWindow.WriteLine(RandomNums[i]) EndFor TextWindow.WriteLine("") TextWindow.WriteLine("Sum of all random numbers = "+Sum) Avarage = Sum / Num TextWindow.WriteLine("Avarage of all random numbers = "+Avarage) TextWindow.Pause() TextWindow.Clear() Init() EndSub Sub Error TextWindow.WriteLine("Should be a whole number. Please try again.") TextWindow.Pause() TextWindow.Clear() Init() EndSub
Merry Xmas!

Amir, this works well, I like the input validation. For a large number input, what would you expect the average to be?
For large, numbers Small Basic arrays are slow, and in this case they are not needed. All the work could be done in one loop without storing the random numbers to an array  speeds it up a lot for say 10000. With this mod I can calculate 1000000 in about 1 sec.

Amir, this works well, I like the input validation. For a large number input, what would you expect the average to be?
For large, numbers Small Basic arrays are slow, and in this case they are not needed. All the work could be done in one loop without storing the random numbers to an array  speeds it up a lot for say 10000. With this mod I can calculate 1000000 in about 1 sec.
I tried up to 10000 times and the average was always 50 ∓ 23.
And about the program, i actually made it to look like a 'program' otherwise i was could make it under 10 lines.
Edit :
TextWindow.Write("Enter a whole number : ") Sum = 0 Num = TextWindow.ReadNumber() For I = 1 To Num Rnd = Math.GetRandomNumber(100) TextWindow.WriteLine(Rnd) Sum = Sum + Rnd EndFor Avarage = Sum/Num TextWindow.WriteLine("The sum is = "+Sum+" And the Average is = "+Average)
Merry Xmas!
 Edited by 4mir ' Friday, January 04, 2013 6:59 PM


Num = 100 FiftyCount = 0 For J = 1 To 1000000 Main() EndFor TextWindow.WriteLine(FiftyCount +" Times") Sub Main Sum = 0 For I = 1 To Num Rnd = Math.GetRandomNumber(100) Sum = Sum + Rnd EndFor Average = Sum / Num If Average = 50 Then FiftyCount = FiftyCount + 1 EndIf EndSub
I Ran this program multiple times the occurrence of Average was :
In a range of 4951 = 48456
And exact 50 was occurred 1385 times.
Merry Xmas!

50 is not the average "exact" value I would expect  there are 100 numbers possible from 1 to 100, their average can be seen below.
sum = 0 For i = 1 To 100 sum = sum + i EndFor TextWindow.WriteLine(sum/100)
Or by symmetry 1+100 = 101, 2+99 = 101 .... 50+51 = 101, therefore the average is (first+last)/2 = (1+100)/2.

Average of random numbers.
The following program shows what happens if you calculate the average of a number of random numbers.
For 100, 1000 and 10000 the average is calculated 1000 times. The distribution of the results is shown in a graphical window. You can see values between 50 and 50.9999 are the most abundant, and the distribution becomes smaller for a greater number of draws of random numbers.
''Disribution of average random 20130106 WhTurner ''=========================================== col="1=Red;2=Green;3=Blue" GraphicsWindow.Show() GraphicsWindow.Top=10 GraphicsWindow.Height=650 GraphicsWindow.PenColor="Black" GraphicsWindow.BrushColor="Black" GraphicsWindow.DrawText(100,50,"Distribution of the average of Math.GetRandomNumber(100)") GraphicsWindow.DrawText(100,70,"calculated 1000 times") GraphicsWindow.DrawLine(100,600,500,600) For i=40 To 60 Step 5 GraphicsWindow.DrawLine(10*i205,600,10*i205,100) GraphicsWindow.DrawText(10*i215,610,i) EndFor N=10 For k=1 To 3 N=N*10 ''100,1000,10000 GraphicsWindow.BrushColor=col[k] GraphicsWindow.PenColor=col[k] GraphicsWindow.DrawText(400,50+20*k,"average of "+N+" draws") For i=1 To 1000 sum=0 For j=1 To N sum=sum+math.GetRandomNumber(100) EndFor bar=math.Floor(sum/N) Distr[k][bar]=Distr[k][bar]+1 EndFor lx=200 ly=600 For i=40 To 59 ii=10*i200 aa=600Distr[k][i]/2 GraphicsWindow.DrawEllipse(ii3,aa3,6,6) GraphicsWindow.DrawLine(lx,ly,ii,aa) lx=ii ly=aa EndFor endfor
Jan [ WhTurner ] The Netherlands
 Edited by WhTurner33Editor Sunday, January 06, 2013 5:08 PM




@Math Man,
Nice your answer is nice. BTW there is very simple way to achieve this
WholeNumber = Text.GetSubText(Input,1,WhereDecimalPoint1) 'the decimal part AfterDecimalPoint = Text.GetSubTextToEnd(Input,WhereDecimalPoint+1) If Text.GetLength(AfterDecimalPoint) > MaxDecimalLength Then 'it exceeds the total length so we shorten it AfterDecimalPoint = Text.GetSubText(AfterDecimalPoint,1,MaxDecimalLength)
By
AfterDecimalPoint = Input  Math.Floor(Input) BeforeDecimalPoint = Math.Floor(Input)
Merry Xmas!

My decimal to lowest terms fraction convertor: PBS429
Amir, I've found a problem in one of your outputs. 2 AND 19/20 should be 2 AND 24/25.
I am a 10 year old that loves math, games, and computers. 'Binary is as easy as 1, 10, 11.'
My Solution, not commented like yours neither has any input validation but i managed to done it in a single nested loop and couple of if else commands.
Import : DZS164
Merry Xmas!


Community Suggestion Challenges By Amir CPS
1] Convert a number in decimal form to the equivalent mixed number with the fraction portion reduced to lowest terms.
maxNMB=Math.Power(10,6) ' you may change Power number
TextWindow.Write("input a number= ")
a=textwindow.ReadNumber()
For i=1 To maxNMB
b=a*i
If (b*10math.Floor(b)*10)=0 Then
bb=i 'Denominator
bs=math.Floor(b) 'Numerator+WholeNumber
i=maxNMB
EndIf
EndFor
nmb=math.Floor(bs/bb) 'WholeNumber
bs=bsnmb*bb 'Numerator
TextWindow.WriteLine("Answer= "+nmb+" and "+bs+"/"+bb)
resid=bs/bb ' confirmation
midP=text.GetIndexOf(resid,".")
TextWindow.WriteLine("Your input number is ... "+nmb+" . "+Text.GetSubTextToEnd(resid,midP+1)) 

Amir,
Yes, the shape was drawn by Shapes Editor.
The calendar is just a text drawn by Shapes.AddText(). So I used "Consolas" as fixed pitch font. Your screen shot seems using proportional font. If you don't have "Consolas" in your system, please use fixed pitch font such as "Courier New" in Cal_DrawMonth subroutine.
Nonki Takahashi


My Solution for the Text Challenge
Import : LSB518
@NaoChanON
look like you have big collection of Small Basic programs, if you don't have any problem please send me all those files. :)
@LitDev
Could you explain what is the reason behind getting average of random numbers close to 50 every time. I ask my teacher the same question and he replied that you will learn all this in next grades.
PS: My Email is amir_rt@live.com :P @NaoChanON
 Edited by 4mir ' Friday, January 11, 2013 6:10 AM

Amir,
LitDev gave an answer on januari 5th. MathGetRandomNumber(X) gives all possible integer numbers from 1 to X. So MathGetRandomNumber(100) gives all number from 1 to 100 inclusive with equal possibilities. The average is then (1+100)/2.
When you want simulate the throw of a dice the possible outcomes are 1,2,3,4,5 and 6. The average is then (1+6)/2 = 3.5 You can try that in your averagecalculation program with MathGetRandomNumber(6). You will get then the average of 3.5 after a sufficient numer of draws.
Jan [ WhTurner ] The Netherlands

@NaoChanON
look like you have big collection of Small Basic programs, if you don't have any problem please send me all those files. :)
Amir and guys.
Most of them are available from here. Total 212 files. (Those are all published programs)
3 folders.
1)CoOp programs ...11 (with absolue,amir,zock)
2)My programs........ 73
3)Other person's programs...128 (Microsoft,Litdev,Amir,Nonki,Math man,Alex,Krueg,timo etal)


I have made a new version of my TextSearch program (Text Challenge) JDS2760
In addition to give linenumbers in all *.sb files in which the text is found, it can now LIST the lines in one given file in which the search text is found.
Jan [ WhTurner ] The Netherlands
 Edited by WhTurner33Editor Sunday, January 13, 2013 10:40 AM



@Math Man. Pretty good, I like the use of the reflection angle method.
LightBeamAngle = (NormalLightBeamAngle)*2+LightBeamAngle
The detection of hitting a mirror could be modified using algebra (basically finding the intersection of 2 lines, the mirror and light beam), but what you have works well and certainly meets the challenge.


I've posted my answer to the
Small Challenge 2Write a program to display a colorful welcome message in the GraphicsWindow when a button is clicked.
http://smallbasic.com/smallbasic.com/program/?FBT176
It has 2 buttons and is hopefully simple to read and use for the operator. Not overly colourful but some animation designed to assist the operator.
I'm not upto the controls part of the curriculum yet so it was a good exercise for me.
It runs better on my PC than it does in the Program Listing window...?


This is my community suggestion challenge 2] by Nonki.
code[1] = "C = Text.GetCharacter(99)" code[2] = "O = Text.GetCharacter(111)" code[3] = "D = Text.GetCharacter(100)" code[4] = "E = Text.GetCharacter(101)" code[5] = "BL = Text.GetCharacter(91)" code[6] = "BR = Text.GetCharacter(93)" code[7] = "SP = Text.GetCharacter(32)" code[8] = "EQ = Text.GetCharacter(61)" code[9] = "WQ = Text.GetCharacter(34)" code[10] = "For i = 1 To 15" code[11] = " TextWindow.WriteLine(C+O+D+E+BL+i+BR+SP+EQ+SP+WQ+code[i]+WQ)" code[12] = "EndFor" code[13] = "For i = 1 To 15" code[14] = " TextWindow.WriteLine(code[i])" code[15] = "EndFor" C = Text.GetCharacter(99) O = Text.GetCharacter(111) D = Text.GetCharacter(100) E = Text.GetCharacter(101) BL = Text.GetCharacter(91) BR = Text.GetCharacter(93) SP = Text.GetCharacter(32) EQ = Text.GetCharacter(61) WQ = Text.GetCharacter(34) For i = 1 To 15 TextWindow.WriteLine(C+O+D+E+BL+i+BR+SP+EQ+SP+WQ+code[i]+WQ) EndFor For i = 1 To 15 TextWindow.WriteLine(code[i]) EndFor
Nonki Takahashi
 Edited by Nonki TakahashiModerator Tuesday, January 15, 2013 2:27 PM



I thought the challenge meant for when a mouse button was clicked, but I see many others put a real button in their programs.
Nonetheless, I bring you my taste of "Small Challenge 2."
As always, I used the GraphicsWindow.GetRandomColor... I am addicted to it :P
Here is the import code: SXK087
TextWindow.Write("Do you like Small Basic? Y/N: ")
yn = TextWindow.Read()
If yn = "Y" Then
TextWindow.WriteLine("HighFive! You are awesome!")
ElseIf yn = "N" Then
TextWindow.WriteLine("Deep down inside, you like Small Basic :)")
EndIf Edited by Joman Mied Saturday, January 19, 2013 5:40 AM Added a hyperlink to my import code for the Silverlight Webbased app.


10Line solution for Small Challenge 1: QBK201 / http://smallbasic.com/program/?QBK201
This program calculates and displays the average of 10, 100, then 1,000 random numbers:
For i = 1 To 3 End = Math.Power(10, i) DisplayAverageOfRands() EndFor Sub DisplayAverageOfRands For j = 1 To End Total = Total + Math.GetRandomNumber(100) EndFor TextWindow.WriteLine("Average of " + End + " numbers: " + Total / End) EndSub
Note that I didn't bother with user input.
EDIT: I added 8 lines, and now it safely handles user input and clueless users. New code: SGW300 / http://smallbasic.com/program/?SGW300
TextWindow.Write("Calculates the average of random numbers. Input a positive number to average that many numbers, or input nothing or '0' to see examples of 10, 100, and 1,000 numbers: ") End = Math.Round(TextWindow.ReadNumber()) If End > 0 Then DisplayAverageOfRands() ElseIf End < 0 Then TextWindow.WriteLine("Only positive integers are accepted.") Else For i = 1 To 3 End = Math.Power(10, i) DisplayAverageOfRands() EndFor EndIf Sub DisplayAverageOfRands For j = 1 To End Total = Total + Math.GetRandomNumber(100) EndFor TextWindow.WriteLine("Average of " + End + " numbers: " + Total / End) EndSub
Note that if you input any value over 10,000,000 even this simple implementation will lag pretty badly. Anything under 100,000 should be instantaneous.
 Edited by AgentE382 Monday, January 28, 2013 6:11 PM Changed program.


