B4J Question [SOLVED] How to activate different buttons randomly

GMan

Well-Known Member
Licensed User
Longtime User
I want to randomly activate 8 buttons, but always only once, and the program shouldnt wait.
So maybe there is a solution with the new ResumableSub feature ?
 

DonManfred

Expert
Licensed User
Longtime User
but always only once
So at the end all buttons should be activated?
Where is the problem? What did you tried so far?
 
Upvote 0

GMan

Well-Known Member
Licensed User
Longtime User
No, at the end all buttons should be off - only one should be on.
They started all off, then randomly one is activated for some time, then off and the next one.

I tried it with this as a base, but cant figure it out with the buttons
B4X:
'Returns a random number between Min (inclusive) Max (exclusive!) Step (Stp number)
Sub RndStep(Minimum As Int, Maximum As Int, Stp As Int) As Int
   Dim i As Int = Rnd(Minimum, Maximum)
   i = i - ((i - Minimum) mod Stp)
   Return i
End Sub

When i set the cyclus manually it works, but its not really random ;-)
Its for my model railway layout and is called Schattenbahnhof (in German) and has 8 rails),and i want to activate the 8 different rails randomly :)
 

Attachments

  • SBF.png
    SBF.png
    7.4 KB · Views: 217
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Something like this?

B4X:
'--- This code can be in AppStart or where needed.
    '--- Button1, Button2, etc variable name for the buttons to be randomly activated. 
    '--- This array should be Dim'ed after the layout containing the buttons is loaded (since this initializes the buttons).
    Dim buttons() As Button = Array As Button (Button1, Button2, Button3, Button4, Button5, Button6, Button7)
    ShuffleArray(buttons)
    Dim n_buttons As Int = buttons.Length
    Dim x As Int
    For x = 0 To n_buttons - 1
        buttons(x).Enabled = True
        Log(buttons(x).Text)
        Sleep(5000)
        If x > 0 Then
            buttons(x-1).Enabled = False
        End If
    Next

'--- Supporting sub to shuffle an array
'--- From: https://www.b4x.com/android/forum/threads/shuffle-string-of-array.23652/#content
'--- Modded for objects
Sub ShuffleArray(arr() As Object)
    ' Knuth's Algorithm P
    Dim n As Int = arr.Length
    Dim r As Int
    Dim t As Object
   
    For i = 0 To n - 1
        r = Rnd(i, n)
        t = arr(i)
        arr(i) = arr(r)
        arr(r) = t
    Next
End Sub

Note: Button1, Button2, etc variable name for the buttons to be randomly activated. This array should be Dim'ed after the layout containing the buttons is loaded (since this initializes the buttons).
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Reading comprehension failure. You wanted non-blocking, so you need this in a sub (not app-start):

B4X:
'Note: the passed on array will be in a different order
'after calling this sub
'Parameters:
'   btnarr: An array of buttons.
'   delay: The delay (in milliseconds) between button activation
Sub EnableRandomButton(btnarr() As Button, delay As Int)
    ShuffleArray(btnarr)
    Dim n_buttons As Int = btnarr.Length
    Dim x As Int
    For x = 0 To n_buttons - 1
        btnarr(x).Enabled = True
        Sleep(delay)
        If x > 0 Then
            btnarr(x-1).Enabled = False
        End If
    Next
End Sub

I also took the log statement out.
 
Upvote 0

GMan

Well-Known Member
Licensed User
Longtime User
It works good, but not randomly - rails are selected from 8 - 1 in 1 step each
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Upvote 0

GMan

Well-Known Member
Licensed User
Longtime User
i'm still trying the implementation of your code in mine - think i lost the Shuffle... part ;-)

And: no time necessary because the cycles are registred throught reead relais between each rail.
Some trains are longer, some are quicker ... so a time functions makes no sense.
When a train is back in the SBF, this will be checked through that reed relais
 
Upvote 0

jmon

Well-Known Member
Licensed User
Longtime User
If I understood correctly, it can be simpler than what you did above. Just a timer that picks randomly a button in a list, and disable the others:
B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
  
    Private t As Timer
    Private Button1 As Button
    Private Button2 As Button
    Private Button3 As Button
    Private Button4 As Button
    Private Button5 As Button
    Private Button6 As Button
    Private Button7 As Button
    Private Button8 As Button
  
    Private buttons(8) As Button
    Private previous As Int = -1
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("main") 'Load the layout file.
    MainForm.Show
 
    'timer  
    t.Initialize("t", 1000)
    t.Enabled = True
  
    'add all buttons to a list
    buttons(0) = Button1
    buttons(1) = Button2
    buttons(2) = Button3
    buttons(3) = Button4
    buttons(4) = Button5
    buttons(5) = Button6
    buttons(6) = Button7
    buttons(7) = Button8
  
End Sub

Sub t_Tick
    Dim r As Int
    'make sure we don't pick the same as the previous round
    Do Until r <> previous
        r = Rnd(0, 8)
    Loop
  
    For i = 0 To buttons.Length -1
        Dim b As Button = buttons(i)
        b.Enabled = r = i
      
        If b.Enabled Then b.Text = "Enabled" Else b.Text = "."
    Next
  
    previous = r
End Sub
 

Attachments

  • rndbtn.zip
    2.2 KB · Views: 173
Upvote 0

GMan

Well-Known Member
Licensed User
Longtime User
Got it, my fault - forgot to rename a variable.
Thx for that hints !
 
Upvote 0

GMan

Well-Known Member
Licensed User
Longtime User
If I understood correctly, it can be simpler than what you did above. Just a timer that picks randomly a button in a list, and disable the others:
B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
  
    Private t As Timer
    Private Button1 As Button
    Private Button2 As Button
    Private Button3 As Button
    Private Button4 As Button
    Private Button5 As Button
    Private Button6 As Button
    Private Button7 As Button
    Private Button8 As Button
  
    Private buttons(8) As Button
    Private previous As Int = -1
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("main") 'Load the layout file.
    MainForm.Show
  
    t.Initialize("t", 1000)
    t.Enabled = True
  
    buttons(0) = Button1
    buttons(1) = Button2
    buttons(2) = Button3
    buttons(3) = Button4
    buttons(4) = Button5
    buttons(5) = Button6
    buttons(6) = Button7
    buttons(7) = Button8
  
End Sub

Sub t_Tick
    Dim r As Int
    Do Until r <> previous
        r = Rnd(0, 8)
    Loop
  
    For i = 0 To buttons.Length -1
        Dim b As Button = buttons(i)
        b.Enabled = r = i
      
        If b.Enabled Then b.Text = "Enabled" Else b.Text = "."
    Next
  
    previous = r
End Sub
THIS was the my way i tried to start...but the other method works well also with less code.
Also to you Thx !
 
Upvote 0
Top