The Challenges To The Beginners Tutorial

Started by Midimaster, January 25, 2022, 08:12:17

Previous topic - Next topic

Midimaster

Lesson X Challenge I

QuoteSpeed Chicken
Try to adjust the speed of the animation of the chicken in our Moorhuhn game.



Tipps and Tricks

The best point to manipulate the animation speed is the line where we change the variable AnimStep. You need a new variable AnimTime:Int and the function Millisecs()




If you still have questions feel free to ask the BlitzMax forum now:
https://www.syntaxbomb.com/blitzmax-blitzmax-ng/



Solution

Code (BlitzMax) Select
SuperStrict
Graphics 800,600
Global AnimTime:Int                 ' <------- NEW LINE
...
Repeat
       .....
SetColor 170,170,255
DrawImage Chicken , cX , cY, AnimStep
SetScale 1,1
If AnimTime<MilliSecs()                   ' <------- NEW LINE
AnimTime = MilliSecs()+100                ' <------- NEW LINE
AnimStep = (AnimStep +1) Mod 12
EndIf
TheChicken
If GunFire() =True Then
.......
...


This causes that the frames are ticking only every 100msec. Because of our command FLIP normally the main loop turns every 16msec and so do the frames. But with the AnimTime = Millisecs()+100 the frames can now only tick every 100msec ,the animation seem slower.
...back from Egypt

Midimaster

#31
Lesson X Challenge II

QuoteTraffic Lights
Try to code a traffic light that changes the colors every 5sec  from RED to YELLOW to GREEN to YELLOW and back to RED


Tipps and Tricks

Tipp 1

first try to draw a beautiful traffic light without function. All three lights are ON. Now encapsulate only the code for the traffic light into a function. The function is called with three parameter: position x and y and state.

Code (BlitzMax) Select
Function DrawLights(X:Int, y:Int, State:Int)

We will have 4 different states:

sequence:
0=RED
1=YELLOW
2=GREEN
3=YELLOW
1=RED
...




Tipp 2

The difference between ON and OFF of a light is defined by a SetColor() command: 255=ON 77=OFF

Code (BlitzMax) Select

If State=2
GREEN= 255
EndIf
...
SetColor 0,GREEN,0



Tipp 3

Switch through the states by using Millisecs()

If you still have questions feel free to ask the BlitzMax forum now:
https://www.syntaxbomb.com/blitzmax-blitzmax-ng/



Solution

Code (BlitzMax) Select
Graphics 800,600

Global Time:Int=MilliSecs()
Global Phase:Int
SetClsColor 130,230,250
Repeat
Cls
SetColor 0,128,0
DrawRect 0,500,800,100
If Time<MilliSecs()
If Phase=1 Or Phase=3
Time = Time+5000
Else
time=Time+2000
EndIf
Phase = (Phase+1) Mod 4

EndIf
DrawLights 100,100, Phase
DrawLights 500,100, (Phase +2) Mod 4

Flip
Until AppTerminate()

Function DrawLights(X:Int, y:Int, State:Int)
SetColor 55,55,55
DrawRect X,Y, 100, 300
DrawRect X+40,Y+300, 20, 300
Local RED:Int=77, YELLOW:Int=77, GREEN:Int=77
If State=0 Or state=1
RED=255
EndIf
If State=1 Or State =3
YELLOW= 255
EndIf
If State=2
GREEN= 255
EndIf

SetColor RED,0,0
DrawOval X+15 , Y+20 , 70 , 70
SetColor YELLOW,YELLOW,0
DrawOval X+15 , Y+115 , 70 , 70
SetColor 0,GREEN,0
DrawOval X+15 , Y+210 , 70 , 70

End Function 


There are three nice gimmicks in the code:

One is the "yellow-red"-phase before returning to GREEN.

Second: We can easily establish a second traffic light by using the same funtion twice.

Third: Did you recognize that the YELLOW-phases are shorter than the RED and GREEN phase?
...back from Egypt

Midimaster

#32
Lesson X Challenge III

QuoteDrum Computer
Try to code a drum-computer playing a rock- rhythm

Audio-Example:
https://www.syntaxbomb.com/worklogs/the-challenges-to-the-tutorial/?action=dlattach;attach=5262

Tipps and Tricks


Tipp 1

You need the LoadSound commands like we did it in Lesso VI Challenge I. And you need to save your code into the project folder where the sound files are! Otherwise the sounds cannot be found by your app.


Tipp 2

The code looks very similar to the traffic light code. This time we have 8 phases, related to the 8 Eights in a pattern. Things happen on phase 0, 2, 3, 4 and 6.



Tipp 3

do you hear somthing like a motor sound? Your  PlaySound() command happen to often! They should only happen in the moment when you incremented the phase



If you still have questions feel free to ask the BlitzMax forum now:
https://www.syntaxbomb.com/blitzmax-blitzmax-ng/



Solution

We need only 20 code lines to play fantastic music!

Code (BlitzMax) Select
Graphics 800,600

Global BD:TSound = LoadSound("bd2.ogg")
Global SD:TSound = LoadSound("sd2.ogg")

Global Phase:Int=7
Global Time:Int=MilliSecs()
Global Speed:Int=250
Repeat
If Time<MilliSecs()
Time = Time+Speed
Phase = (Phase+1) Mod 8

If Phase=0 Or Phase=3 Or Phase=4
PlaySound BD
EndIf
If Phase=2 Or Phase=6
PlaySound SD
EndIf
EndIf
Flip
Until AppTerminate()


If you want to play the rhythm faster or slower connect the variable Speed with the MouseX()
...back from Egypt

iWasAdam

OK I'm going to respond to "Lesson IX Challenge III" The triangle...

The only way I can replay is with a classic Spaghetti Western: The Good, The Bad, And The Ugly

1. The Good
The triangle filling concept is superb. An interesting take on filling and an unusualy way of getting the result. So kudos for some left-field thinking.

2. The Bad
Hmm. more troubling - it works. It's a very (extremely very) advanced way of doing something simple
But it is using such an obscure and strange way of doing it. if you understand what is going on behind the scenes with the rendering system. it is a sort of hybrid 2d/3d system that in some respects takes the worse concepts from both and puts them together. It works - but is brute force and not really a good solution.

3. The Ugly
OK. This really expands on 'The Bad' and explain what is going on and why it is an ugly solution plus how it could better be achieved.

First it is a hybrid solution using some brute 2d to chop up a triangle. and then using 3d to fill it.

The reality is there isn't a drawtriangle command. and if there was it would be a simple case of beginopengl, fill in the 3 corners, openglfill a triangle and then close. This would be around 3 -5 lines of code and should really have been added to NG.

So actually writing the correct triangle fill would just mean writing the new method and getting it added to mojo/graphics - which is where monkey and monkey2 and wonkey come from - they patch the gaping holes in NG.

Why is DrawTriangle not in the core? In essence because no one really uses filled triangles, that it was overlooked.

Second thing to get to know is this completely fundamental thing:
THERE IS NO 2D IN MODERN LANGUAGES
There is only a 3d GPU with vertexes, etc. All 2d commands are cached and converted in some way at some time before being sent as a list of 3d calls!
And further to this there are only a few base primitives to work with:
TRIANGLE
TRIANGLE FAN
TRIANGLE STRIP
When you call DrawRect - it sorts out the internal vertexes it need and places a reference to what it want to draw into a list. when you call Flip - this list is then sent to the GPU and it renders the result. A Rect would be made from 2 triangles, or one trianglefan or one trianglestrip... !!

So... breaking (what you think is) a 2d triangle (which is the base primitive) into rects is the ugliest way of doing this - the best way would just be to fix a new method to draw it correctly - you would need to ask the NG mods to do this as there would be extra stuff in regard to shaders etc which you wouldn't know about.

If all this is starting to sound long, complex and frankly Ugly... Then you are correct - it is.

Breaking up the triangle into this way is an amazing piece of (and I hate to say this) code. It is an advanced technique and an odd way to do it even if you were dealing with advanced computer graphics - plus a dated one.

For anyone not at an advanced level of very old methods of computer graphics. it has no place. and certainly should NEVER be shown to anyone who is ot interested in this sort of thing - Beginners should never have to know anything like this EVER!!!

iWasAdam

Let take exception to programming style

lots of if statements = bad programming
what you need to use is select case. this has the following format
Quote
Select inputValue
  Case 1
    print "1 selected"
  Case 2
    print "2 selected"
End Select

But why is it better than lots of ifs?
there are 2 answers:
1. the compiler will optimize select case better that a load of ifs. it might create a jump table, or other such internal stuff to make select case very quick
2. select case has some very nifty shortcuts: E.G.

Quote
Select inputValue
  Case 1,2,3
    print "1/2/3 selected"
  Case 4
    print "2 selected"
  Default
    print "something else that isn't handled above"
End Select

Midimaster

#35
Lesson XI Challenge I

QuoteCar Racing: Speed and Course
Try to add a background image, which shows a top-down-view of a racing course. Try to add a accelerator. When the user press the "S" button the car gets faster, pressing "B" works like a break.


Tipps and Tricks

Tipp 1

If you want to add a top-view racing course, you could draw it with a painting app.


Tipp 2

To add a variable speed to the game you have to replace the const 2 with a variable Speed:Double
'before:
X = X + Cos(Degree)*2
Y = Y + Sin(Degree)*2
' after:
X = X + Cos(Degree)*Speed
Y = Y + Sin(Degree)*Speed


Now connect the variable Speed with a KeyDown(). As long as the key is pressed add a little amount to Speed


Tipp 3

To get realistic acceleration or breaks you have to experiment with the amount you add or substract. Additional you have to care, that Speed does not exceed limits

Code (BlitzMax) Select
If Speed<0 Then Speed=0
If Speed>3 Then Speed=3
...



If you still have questions feel free to ask the BlitzMax forum now:
https://www.syntaxbomb.com/blitzmax-blitzmax-ng/



Solution

Instead of sending you a background image, I coded you a procedural way to paint the roads:


The function PaintACourse() is like a list of course-sections. The function AddRoad() connects them to a endless course. (I did not close the course to demonstrate, where the first section is). There are upto three parameters:

Code (BlitzMax) Select
AddRoad(Length:Int, Turn:Int=0, Radius:Double=1)

Length  =  the length of the section

Turn    =  -1  if road turns left
            0  or nothing if road goes straight
           +1  if road turns right

Radius  =  size of radius of a curve
           or nothing if road is straight



Here is our racing game

Use keys S for acceleration and B for breaks and MouseWheel for Turning

Code (BlitzMax) Select
SuperStrict
Graphics 1200,900
Global Car:TImage=LoadImage("car.png")
MidHandleImage Car

Global X:Double=300, Y:Double=650, Degree:Int=340
Global CourseX:Double, CourseY:Double, CourseDegree:Int

Global Speed:Double
SetClsColor 40,80,0
Repeat
Cls
Degree = Degree + MouseZSpeed()*4
If KeyDown(KEY_S)
speed=speed+0.01
ElseIf KeyDown(KEY_B)
speed=speed - 0.02
EndIf
speed = speed - 0.003
If Speed<0 Then Speed=0
If Speed>3    Then Speed=3
Local TestX:Double = X + Cos(Degree)*Speed
Local TestY:Double = Y + Sin(Degree)*Speed
If TestX>30 And TestX<1170 And TestY>30 And TestY<870
X = TestX
Y = TestY
EndIf
PaintACourse
SetColor 255,255,255
SetRotation Degree
DrawImage Car , X , Y
Flip
Until AppTerminate()


Function PaintACourse()
SetColor 55,55,55
SetRotation 0
SetHandle 0,25
CourseX      = 700
CourseY      = 490
CourseDegree = 0
AddRoad 150
AddRoad  90, 1, 1
AddRoad 200
AddRoad 180,-1, 1
AddRoad 200
AddRoad  45, 1, 1
AddRoad 110,-1, 1
AddRoad 700
AddRoad 100,-1, 3
AddRoad 350
AddRoad 120,-1, 1
AddRoad 510
AddRoad  16, 1, 1
AddRoad  50
End Function


Function AddRoad(Length:Int, Turn:Int=0, Radius:Double=1)
For Local i:Int=0 To Length
CourseDegree = CourseDegree+Turn
CourseX = CourseX + Cos(CourseDegree)*Radius
CourseY = CourseY + Sin(CourseDegree)*Radius
SetRotation CourseDegree
DrawRect CourseX, CourseY, 5, 120
Next
End Function
...back from Egypt

Midimaster

#36
Lesson XI Challenge II

QuotePing Pong
Try to code a ping-pong-game: A ball plays back and forth  while the mouse moves a racket to turn the ball back


Tipps and Tricks


It looks like this got lost during the syntax bom reset...

Code (BlitzMax) Select
'coming soon
...



If you still have questions feel free to ask the BlitzMax forum now:
https://www.syntaxbomb.com/blitzmax-blitzmax-ng/



Solution

It looks like this got lost during the syntax bom reset...

Code (BlitzMax) Select
'coming soon
...




Here is an extended solution:

Code (BlitzMax) Select
Graphics 800,600
Global RacketY:Int, RacketX:Int=100
Global BallX:Double=-999, BallY:Double, AddX:Double, addY:Double
HideMouse
Repeat
Cls
DrawField
DrawRacket
DrawAndCheckBall
Flip
Until AppTerminate() Or KeyHit(KEY_ESCAPE)


Function DrawField()
SetClsColor 0,55,111
SetColor 0,60,120
Local i:Int
Repeat
DrawRect 0,i,800,3
DrawRect i,0,3,600
i=i+60
Until i>800

SetColor 255,155,0
DrawRect 50,5,740,5
DrawRect 50,590,740,5
DrawRect 790,5,5,590
End Function


Function DrawRacket()
MoveMouse 30, MouseY()
RacketY = MouseY()
If RacketY<15  Then RacketY = 15
If RacketY>475 Then RacketY = 475
'shadow:
SetColor 44,44,99
DrawRect RacketX+10, RacketY+5+5, 11,95
DrawOval RacketX+10, RacketY+5, 11,11
DrawOval RacketX+10, RacketY+95+5, 11,11
SetColor 255,222,111
DrawRect RacketX, RacketY+5, 11,95
DrawOval RacketX, RacketY, 11,11
DrawOval RacketX, RacketY+95, 11,11
SetColor 255,11,255
DrawRect RacketX+2, RacketY+5, 7,95
End Function


Function DrawAndCheckBall()
Local Speed:Double=5
If Ballx<-100
' ball disappeared left side, so new game:
BallX=700
BallY=300
Local degree:Double  = Rand(120,240)
AddX = Cos(degree)*Speed
AddY = Sin(degree)*Speed
ElseIf BallX>780
' ball at right wall
AddX = - AddX
EndIf

If BallY<10
' ball at top wall
AddY = -AddY
ElseIf BallY>575
' ball at bottom wall
AddY = -AddY
EndIf

BallX = BallX+AddX
BallY = BallY+AddY

'now check for Racket:
If BallX>RacketX And BallX<RacketX+10
If BallY>RacketY And BallY<RacketY+100
Local degree:Double  = Rand(-60,60)
AddX = Cos(degree)*Speed
AddY = Sin(degree)*Speed
EndIf
EndIf
'shadow:
SetColor 44,44,99
DrawOval BallX+15,Bally+10,15,15
'
SetColor 255,255,255
DrawOval BallX,Bally,15,15
End Function
...back from Egypt

Midimaster

#37
Lesson XI Challenge III

QuoteOutline Circle
Try code a function that draws a not filled circle. You need a formula like this and a loop over 360°:

X = middleX + Cos(Angle)* Radius


Tipps and Tricks

Tipp 1

You can descripe circular movements with the functions Sin() and Cos(). Think about the car in our car game. What would be, if it drives in a circle and marks "traces" on the ground


Tipp 2

This draws a dot at a circular positon around [X/Y] with the distance of Radius and the direction Degree. You need to do this 360 times:
Code (BlitzMax) Select
DrawOval X+Cos(Degree)*Radius, Y+Sin(Degree)*Radius, 2,2


If you still have questions feel free to ask the BlitzMax forum now:
https://www.syntaxbomb.com/blitzmax-blitzmax-ng/


Solution


Slow Motion Explanation:

Code (BlitzMax) Select
Graphics 800,600
Global Degree:Int
Repeat
DrawOutLineCircle  300,300,100
Flip
Until AppTerminate()

Function DrawOutLineCircle(X:Int, Y:Int, Radius:Int)
DrawOval X+Cos(Degree)*Radius, Y+Sin(Degree)*Radius, 2,2
Degree=degree+1
End Function





Now faster:


Code (BlitzMax) Select
Graphics 800,600
Repeat
Cls
DrawOutLineCircle  300,300,100
Flip
Until AppTerminate()

Function DrawOutLineCircle(X:Int, Y:Int, Radius:Int)
Local Degree:Int
Repeat
DrawOval X+Cos(Degree)*Radius, Y+Sin(Degree)*Radius, 2,2
Degree=degree+1
Until Degree>360
End Function



but this has limitations! Try to change the radius to 280 and see what happens... We have to use DrawLine to get no holes.



Here with DrawLine()


Now a position defined by Degree is connected with the position of Degree+1 by DrawLine()

Code (BlitzMax) Select
Graphics 800,600
Repeat
Cls
DrawOutLineCircle  300,300,280
Flip
Until AppTerminate()

Function DrawOutLineCircle(X:Int, Y:Int, Radius:Int)
Local Degree:Int
Repeat
DrawLine X+Cos(Degree)*Radius, Y+Sin(Degree)*Radius, X+Cos(Degree+1)*Radius, Y+Sin(Degree+1)*Radius
Degree=degree+1
Until Degree>360
End Function


...back from Egypt

Midimaster

Lesson XII Challenge I

QuoteCalculate
Write an app that calculates the sum of all numbers from 1 to 1000 with a For/Next



Tipps and Tricks

The result is 500500



If you still have questions feel free to ask the BlitzMax forum now:
https://www.syntaxbomb.com/blitzmax-blitzmax-ng/



Solution

Code (BlitzMax) Select
SuperStrict

Global Sum:Int
For Local i:Int= 1 To 1000
sum = sum+i
Next

Print sum
...back from Egypt

Midimaster

#39
Lesson XII Challenge II

QuoteJesu's Saving  Book
If the parents of Jesus would have invested 1Cent (=0.01$) at his birth. And the bank would have paid only 1% interest a year ... How many dollars would now be on his saving book? Write an app that calculates anual interests and loops through 2121 years with For/Next .



Tipps and Tricks


Tipp 1

Each year the bank adds 1/100 of the sum to the sum


Tipp 2

If your result is displayed with too many decimal places you need to cut them with help of an temporary INTEGER variable.



If you still have questions feel free to ask the BlitzMax forum now:
https://www.syntaxbomb.com/blitzmax-blitzmax-ng/



Solution

There are many solutions with different results... All are senseful

Scientific solution A:

here we add 1% each year

Code (BlitzMax) Select
SuperStrict

Global Sum:Double=0.01
For Local i:Int= 1 To 2121
Local interest:Double =Sum/100*1  ' 1%
sum = sum+interest
Next

Print sum +"$"

The result is 14643125.784554791 $. This means the family would have more than 14 Billion Dollar after that time.


Scientific solution B:
Code (BlitzMax) Select
SuperStrict

Global sum:Double = 0.01* 1.01^2121

Print sum +"$"

The result is 14643125.784555167 $



INTEGER solution A:

Here we manipulate the sum at the end  to get only two decimal  places

Code (BlitzMax) Select
SuperStrict

Global Sum:Double=0.01
For Local i:Int= 1 To 2121
Local interest:Double =Sum/100.0*1  ' 1%
sum = sum+interest
Next
Global AsInteger:Int = sum*100
Print (AsInteger/100) + "." + (AsInteger Mod 100) +"$"

The result is 14643125.78 $


BANK solution A:

An here is the methode like banks are handling the interest on your account. They only calculating your account in cents.

Code (BlitzMax) Select
SuperStrict

Global Sum:Int=1  '    <---- one cent instead of 0.01 Dollar
For Local i:Int= 1 To 2121
Local interest:Double = Sum/100.0*1  ' 1%
sum = sum + interest
Next
Print sum + " cent"

The result is 1cent or 0.01 $ after 2121 years.  :P


Would that have gone better with a start capital of  one Dollar instead of one Cent?


Here we compare bank method verus scientific method for the start capital of 1.00 $

Code (BlitzMax) Select
SuperStrict

Global SumA:Long = 100
Global SumB:Double= 1.00

For Local i:Int= 1 To 2121
Local interest:Double
'bank method
interest = SumA/100.0 *1  ' 1%
SumA = SumA + interest

'scientific method
interest = SumB/100.0 *1  ' 1%
SumB = sumB + interest
Print i + " " + suma + " " + sumb
Next
Print "      Bank method result =  " + Int(SumA/100) + "$"
Print "Scientific method result = " + Int(SumB) + "$"


Also here the bank has a "little" advantage of 680 Mio Dollar over all the years.
...back from Egypt

Midimaster

#40
Lesson XII Challenge III

QuoteDraw a chessboard
Write an app, that draws a chessboard by using nested For/Next loops. A chess has  8x8 fields with two different colors: dark wood and pale wood.


Tipps and Tricks


Tipp 1

You need two nested For/Next-loops with each 8 interations. Each of these 64 loop draws one rectangle at a position calculated from i and j


Tipp 2


The wood color changes related to the position of the rectangle. Or you can say related on the value of i and j.




If you still have questions feel free to ask the BlitzMax forum now:
https://www.syntaxbomb.com/blitzmax-blitzmax-ng/



Solution

Code (BlitzMax) Select
SuperStrict
Graphics 800,600

Repeat
Cls
Local b:Int = 60
For Local i:Int=1 To 8
For Local j:Int=1 To 8
If (i+j) Mod 2=0
SetColor 140,100,40
Else
SetColor 220,180,130

EndIf
DrawRect i*b, j*b, b-2,b-2
Next
Next
Flip
Until AppTerminate()


The tricky part is how I flip the wood color. You can do it more complicate but understandable. Here you have to a solution based on the fact that the variables i and j continously switch between odd and even


Explanation:

First Row

In the first row i is 1 and j runs from 1 to 8. This produces the following seqence for the sum (i+j):

2  3  4  5  6  7  8  9

a mod 2 calculation works like finding out if the result is odd or even:

0  1  0  1  0  1  0  1

This is the base for the SetColor-Decision.


Second Row


In the second row i is 2 and j runs again from 1 to 8. This produces the following seqence for the sum (i+j):

3  4  5  6  7  8  9  10


This changes the results of the  mod 2 calculation:

1  0  1  0  1  0  1  0

That is the reason why the colors alternate from row to row
...back from Egypt

Midimaster

#41
Lesson XIII Challenge I

QuoteSnow Falls
Try to code a snowfall, where 2000 snowflakes starting at random positions above the screen, then falling down. When they reach the bottom, the start again above the screen.


Tipps and Tricks

Tipp 1

You need 4 Arrays:
Code (BlitzMax) Select
Global SnowX:Double[2000], SnowY:Double[2000],SnowAddX:Double[2000],SnowAddY:Double[2000]

Fill them with random values. And write a first function to only display them without moving. Use a For/Next loop with 2000 iterations. Use DrawOval() to paint a snowflake.


Tipp 2

The second function you have to write is to move them by adding SnowAddX and SnowAddY each loop.


Tipp 3

Your last function checks whether the snowflake left the screen. In this case we restart it by settng the SnowY to a negative value



If you still have questions feel free to ask the BlitzMax forum now:
https://www.syntaxbomb.com/blitzmax-blitzmax-ng/



Solution

this is only one possible solution. Your solution is just as good too!

Code (BlitzMax) Select
SuperStrict
Graphics 800,600

Global SnowX:Double[2000], SnowY:Double[2000],SnowAddX:Double[2000],SnowAddY:Double[2000]

For Local I:Int=0 Until 2000
SetSnowFlake I,True
Next


Repeat
Cls
DrawSnowFlakes
Flip
Until AppTerminate()


Function DrawSnowFlakes()
For Local I:Int=0 Until 2000
DrawOval SnowX[i] , SnowY[i] , 3,3
MoveSnowFlake i
Next
End Function

Function SetSnowFlake(n:Int, firstTime:Int=0)
SnowX[n]    = Rand(0,800)
If firsttime=True
SnowY[n]    = Rand(-100,600)
Else
SnowY[n]    = Rand(-100,0)
EndIf
SnowAddX[n] = Rnd(-1,1)
SnowAddY[n] = Rnd(3,7)
End Function


Function MoveSnowFlake(n:Int)
SnowY[n] = SnowY[n] + SnowAddY[n]
SnowX[n] = SnowX[n] + SnowAddX[n]
If ( SnowY[n]> 600 ) Or ( SnowX[n]<0 )  Or ( SnowX[n]>800)
SetSnowFlake n
EndIf
End Function
...back from Egypt

Midimaster

#42
Lesson XIII Challenge II

Quote10 Crazy Cars
Try to code a demo, where 10 individual cars driving in all direction. When they left the screen they turn around with a random angle to come back.



Tipps and Tricks


Tipp 1

This is a variation of the car-code in lesson XI. Start with expanding that code:

Code (BlitzMax) Select
SuperStrict
Graphics 800,600
Global Car:TImage=LoadImage("car.png")
MidHandleImage Car
Global X:Double=400, Y:Double=300
Global lastX:Double, lastY:Double
Global Degree:Int=290

Repeat
        Cls
        Degree=degree + MouseZSpeed()*4
        X = X + Cos(Degree)*2
        Y = Y + Sin(Degree)*2
        If X<30 Or x>770 Or Y<30 Or Y>570
                X = lastX
                Y = lastY
        Else
                lastX = X
                lastY = Y
        EndIf

        SetRotation Degree
        DrawImage Car,X,Y
        Flip
Until AppTerminate()



Tipp 2

You need three arrays:

Code (BlitzMax) Select
Global X:Double[10], Y:Double[10]
Global Degree:Int[10]


Move the car by adding someting:

Code (BlitzMax) Select
For Local i:Int=0 Until 10
X[i] = X[i] + Cos(Degree[i])*2
Y[i] = Y[i] + Sin(Degree[i])*2
...



Tipp 3

to prevent really crazy looking movements at the bounds of the screen, you should not only check the bounds, but set the car back into the screen:

Code (BlitzMax) Select
If (X[i]<0)
Degree[i] = Rand(0,360)
X[i]=1
EndIf





If you still have questions feel free to ask the BlitzMax forum now:
https://www.syntaxbomb.com/blitzmax-blitzmax-ng/



Solution

Code (BlitzMax) Select
SuperStrict
Graphics 800,600
Global Car:TImage=LoadImage("car.png")
MidHandleImage Car
Global X:Double[10], Y:Double[10]

Global Degree:Int[10]


For Local i:Int=0 Until 10
X[i]      = Rand(0,800)
Y[i]      = Rand(0,600)
Degree[i] = Rand(0,360)

Next


Repeat
Cls

For Local i:Int=0 Until 10
X[i] = X[i] + Cos(Degree[i])*2
Y[i] = Y[i] + Sin(Degree[i])*2
If (X[i]<0)
Degree[i] = Rand(0,360)
X[i]=1
EndIf
If (X[i]>800)
Degree[i] = Rand(0,360)
X[i]=799
EndIf
If (Y[i]<0)
Degree[i] = Rand(0,360)
Y[i]=1
EndIf
If (Y[i]>600)
Degree[i] = Rand(0,360)
Y[i]=599
EndIf
SetRotation Degree[i]
DrawImage Car, X[i] , Y[i]

Next
Flip
Until AppTerminate()

...back from Egypt

Midimaster

Lesson XIII Challenge III

QuoteSort Numbers
Try to code a sorting algorithm: An array gets filled with 100 random numbers. Now try to find the highest number and copy it to the first index of a second (empty) array, the second highest number to the second index... and so on. Hint: mark the already copied values (in the first array) by setting them to "-1" so that they are to low to be taken in acount again.



Tipps and Tricks


Tipp 1

You need two arrays. Fill Global Source:Int[100] with random numbers from 1 to 1000. Keep Global Result:Int[100] empty. 


Tipp 2

You need two nested For/Next-loop. Each running from 0 to 99. In total there will be 10.000 interations. The outer loop fills the Result[100]-array with one new value after the inner loop found the highest value of the  Source[100]-array


Tipp 3

To remember the highest value until the end of the inner loop you need two variables Maxi:Int for the value and Position:Int to remember the position where you found the maximum. Before the inner loop starts both are set to -1. within the inner loop you compare Maxi with the source values. If you find a higher value set Maxi to it, but continue searching for even higher values.


Tipp 4

After the inner loop finished Maxi knows the highest value and Position knows where it was. Now set Result[...] to Maxi and dont forget to set Source[Position] to -1. We do that to prevent finding the same high value again and again.




If you still have questions feel free to ask the BlitzMax forum now:
https://www.syntaxbomb.com/blitzmax-blitzmax-ng/



Solution

Code (BlitzMax) Select
SuperStrict

Global Source:Int[100]
Global Result:Int[100]
Print " BEFORE:"
For Local i:Int=0 Until 100
Source[i] = Rand(1,1000)
Next
Print "....."
For Local i:Int=0 Until 10
Print i + ". source element=" + Source[i]
Next

For Local r:Int=0 Until 100
Local maxi:Int     = -1
Local Position:Int = -1

' step 1: find the maximum
For Local s:Int=0 Until 100
If Source[s]>Maxi
Maxi = Source[s]
Position = s
EndIf
Next

'step 2: copy it to results
Result[r] = Maxi
source[Position] = -1
Next
Print
Print " AFTER:"
For Local i:Int=0 Until 100
Print i + ". result element=" + Result[i]
Next
...back from Egypt

Midimaster

#44
Lesson XIV Challenge I

QuoteStart A Chess Game
Code a chess board, where only the pawns exist. Try to move them "ahead" by random every 2 seconds.


Tipps and Tricks



Tipp 1

We already coded "Display A Chessboard". Use this code but pack it into a function. Additional you will need a 2-dimensional array for the pieces (actors). Make it bigger as you need (10x10) and let play the actors from (1,1) to (8,8)



Tipp 2

To be able to easy differentiate between white and black actors we use positiv numbers for the black and negative numbers for the white actors. Define the following constants:  BLACK=1  WHITE=-1 and PAWN=1 KING=2 ... for the two players (sides). so the "white king" is build from WHITE*KING



Tipp 3
Develop the game in 6 steps and perfectionate each step before you start the next.


  • Draw a chessboard without figures.


  • Add a Board:Int[] array for the actors and set Board[5,5]=BLACK*PAWN to simulate a first actor.
    Write a general function to display all the (still standing and only one) actors. Simply use a white or black circle as representative for the actor. Now test with the single actor the correct working of the new function: Test things like: Board[5,5]=WHITE*PAWN or  Board[2,5]=BLACK*PAWN


  • Write a StartUp() function to fill all 16 actors at the  correct rows.


  • Write a MoveRandom() function that ticks every 2000msec. It selects a random Field, check whether it is usefull. After that the movement is a y-addition  +1 or -1 depending on the actor's color. Test the movement, ignore collisions


  • Now optimize your MoveRandom() to alternately move black and white.


  • Now optimize your MoveRandom() to omit collisions and outbounds


  • now optimize ..... and so on...

This time you will find the 6 step-solutions in the Solution-chapter (see below)



Tipp 4

The optimizing could be done in three nested Repeat/Until loop. The inner choose a random coordinate and checks whether the field contains any actor. The middle loop checks whether the color of the actor suits to the player whose turn it is. The outer loops checks if the target field is empty... and so on.



If you still have questions feel free to ask the BlitzMax forum now:
https://www.syntaxbomb.com/blitzmax-blitzmax-ng/



Solution Step 1 & 2: Test with one actor

Code (BlitzMax) Select
SuperStrict
Graphics 800,700
SetClsColor 0,111,0

'actors:
Const BLACK:Int=1, WHITE:Int=-1
Const PAWN:Int=1, KING:Int=2
Const WIDTH:Int=70
Global Board:Int[10,10]

Board[5,5]= BLACK*PAWN

Repeat
Cls
DrawBoard
DrawActors
Flip
Until AppTerminate()



Function DrawBoard()
SetColor 145,90,35
DrawRect WIDTH,WIDTH,8*WIDTH,8*WIDTH
SetColor 220,190,135
For Local x:Int=1 To 8
For Local y:Int=1 To 8
If (x+y) Mod 2=0
DrawRect x*WIDTH ,y*WIDTH, WIDTH, WIDTH
EndIf
Next
Next
End Function


Function DrawActors()
For Local x:Int=1 To 8
For Local y:Int=1 To 8
If Board[x,y]<>0
DrawActorAt(x, y)
EndIf
Next
Next
End Function


Function DrawActorAt(x:Int, y:Int)
If Board[x,y] < 0  ' WHITE side
SetColor 222,222,222
Else
SetColor 111,111,111
EndIf
DrawOval X*WIDTH+10, y*WIDTH+10, 50, 50
End Function







Solution Step 3: StartUp() function

Code (BlitzMax) Select
...
Global Board:Int[10,10]

StartUp   '   <-------- NEW LINE

Repeat
Cls
DrawBoard
DrawActors
Flip
Until AppTerminate()

Function StartUp()
For Local y:Int=0 Until 9
For Local x:Int=0 Until 9
Board[x,y] = 0
Next
Next
For Local x:Int=1 To 8
Board[x,2] = BLACK*PAWN
Board[x,7] = WHITE*PAWN
Next
End Function


Function DrawBoard(w:Int)
.....






Solution Step 4: Movement

Code (BlitzMax) Select
...
StartUp

Global Player:Int=1  '   <-------- NEW LINE
Global  Time:Int=MilliSecs()+ 2000  '   <-------- NEW LINE
Repeat
Cls
DrawBoard
DrawActors
Flip
If Time<MilliSecs() '   <-------- NEW LINE
MoveRandom
EndIf
Until AppTerminate()


Function MoveRandom()
Local x:Int, y:Int
Repeat
x=Rand(1,8)
y=Rand(1,8)
Until Board[x,y]<>0

If Board[x,y] < 0 'WHITE side
Board[x,y-1]=Board[x,y]
Else
Board[x,y+1]=Board[x,y]
EndIf
Board[x,y]=0
End Function

Function StartUp()
....






Solution Step 5: Alternate Player

This is very tricky now. The fact that white actors have to run in "negative" directions (y=y-1) but  black actors in positiv (y=y+1) to get forward, brings us the problem that we always have to differ between white and black situations. f.e. sometimes the blacks are the "Enemies", sometimes the whites. Also a move "to the left" (x=x-1) results in moving "to the right" for the black actors. The code will become longer and longer related to the fact that we always need different code lines for black and white moves.

There is a simple solution: Turn the board every time when WHITE moves. Do what we need to do. At the end turn the board back to display it like normal. This is also what you would do in real life if your fellow player asks you for an advise: You would turn the board for this moment to get "normal" observing of the situation.

Code (BlitzMax) Select
Function TurnBoard:Int[,](SourceBoard:Int[,])
Local locBoard:Int[10,10]
For Local x:Int=1 To 8
For Local y:Int=1 To 8
' negativ signature changes the actors color
' the "9-..." aproach changes the board sides
locBoard[9-x,9-y] = -SourceBoard[x,y]
Next
Next
Return locBoard
End Function


This trick make our coding very easy. We turn the board and WHITE becomes BLACK for this moment. This means in fact, that always BLACK is moving now. And WHITE is always the enemy. The function return a 2-dimensional array


Function TurnBoard:Int[,](...) means that the function does not return a simple variable but a whole 2-dimensional array.



Code (BlitzMax) Select
...
Function MoveRandom()
Player = -Player
If Player= WHITE
Board = TurnBoard(Board)
EndIf

Local x:Int, y:Int
Repeat
x=Rand(1,8)
y=Rand(1,8)
Until Board[x,y]>0

time = MilliSecs() +2000
Board[x,y+1] = Board[x,y]
Board[x,y]=0

If Player= WHITE
Board = TurnBoard(Board)
EndIf
End Function
...






Solution Step 6: Check allowed target fields



Code (BlitzMax) Select
...
Function MoveRandom()
Player = -Player
If Player= WHITE
Board = TurnBoard(Board)
EndIf

Local x:Int, y:Int
Repeat
Repeat
x=Rand(1,8)
y=Rand(1,8)
Until Board[x,y]>0
Until Board[x, y+1]=0 And (Y+1)<9

time = MilliSecs() +2000
Board[x,y+1] = Board[x,y]
Board[x,y]=0

If Player= WHITE
Board = TurnBoard(Board)
EndIf
End Function
...

...back from Egypt