Home > Blockchain >  Powershell - Get-Random combinations of values in array but follow certain rules
Powershell - Get-Random combinations of values in array but follow certain rules

Time:01-06

G'day everyone

I'm pretty new to scripting and Powershell so I've given myself a little challenge to learn some basics. I'm trying to script a small number callout system for my cardio kickboxing workout. It's based on "Bas Ruttens system".

The idea is that every few random seconds a combo of strikes and kicks is shown, for example... ... 1,2,3,Kick (left jab, right straight, left hook, right kick) or ... 1,2,Knee (left jab, right straight, right knee)

What I got working so far is the basic number callout with a random break between combos.

Here's what I have so far:

#Number callout system for cardio kickboxing
#Version 1.0
#Created by Burger

#Add more exercises here
$Combo = @('1','2','3','4','Knee')

#For higher intensitiy decrease the gap between Minimum and Maximum or increase the duration
[int]$Minimum = 2
[int]$Maximum = 6
[int]$Duration = 1

#Create the timer
$TimeStart = Get-Date
$TimeEnd = $timeStart.addminutes($Duration)
Write-Host "Start Time: $TimeStart"
write-host "End Time:   $TimeEnd"

#Start the session until time runs out
Do { 

    $TimeNow = Get-Date
    
        if ($TimeNow -ge $TimeEnd) {
            Write-host "Great Work. It's time for your Cool Down. :)"
        } else {
            Write-Host (Get-Random $Combo)
        }
        Start-Sleep -Seconds (Get-Random -Minimum $Minimum -Maximum $Maximum)
   }
Until ($TimeNow -ge $TimeEnd)
#EOF

Now, what I can't wrap my head around is how can I tell Powershell to create random combos like "1,2,3,Knee" or "1,1,4" with certain rules that for example prevent a combo that would ruin the flow like "Knee,4,2".

What I tried

I thought about creating a textfile with all valid combos, and pick random combos out of the file with "Get-Content". This does work and I get random combos between random amounts of seconds.

Correct output with Get-Content

But the amount of valid combos is huge and only increases when I want to add certain cardio moves in the future like burpees or jumping knees, etc. So I'd love to only feed the array and let PS create the combos.

Also I've tried to at least generate the combos with more variables like this.

$Combo_1 = (Get-Random $Combo)
$Combo_2 = (Get-Random $Combo),(Get-Random $Combo)
$Combo_3 = (Get-Random $Combo),(Get-Random $Combo),(Get-Random $Combo)
$Combo_4 = (Get-Random $Combo),(Get-Random $Combo),(Get-Random $Combo),(Get-Random $Combo)

#Combo Randomizer
$FullCombo = (Get-Random -InputObject $Combo_1, $Combo_2, $Combo_3, $Combo_4)

But I couldn't get it to work because I kept receiving the error: Cannot convert the "System.Object[]" value of type "System.Object[]" to type "System.Double".

Then I thought about IF statements like "If Number1=1 THEN (Get-Random from 1,2 or Knee)" etc. But that way I see myself writing dozens of IF statements to get all the valid combos.

So, is there a more elegant and simple way to create random combos with certain rules like these?

Pseudo Code

While time has not run out
Do
Get-Random Combo with "1,2,3,4,Knee" BUT
Never start with 4,
Never start with knee,
Never follow 3 on 1,
Never 3 times knee in a row
Done
Write-Output "Time ran out. Session over."

I'd be happy if someone could point me in the right direction. Thank you for your help

Cheers

CodePudding user response:

Your selection rules are stateful - in other words, in order to select the next move in the sequence you'll need to inspect the previous moves and eliminate some options.

Here's one way to do that...

Before it selects a move it first eliminates options that would violate the rules, and then just calls Get-Random on the remaining valid moves...

function Get-Sequence
{

    param( $Length = 4 )

    if( $Length -lt 1 )
    {
        throw new InvalidOperationException("Length must be greater than zero.");
    }

    $moves = @("1", "2", "3", "4", "Knee");

    $sequence = @();

    # Never start with 4
    # Never start with Knee
    $allowed = $moves | where-object { $_ -notin @("4", "Knee") }
    $sequence  = Get-Random $allowed;

    for( $i = 1; $i -lt $Length; $i   )
    {

        $allowed = $moves;

        # Never follow 3 on 1
        if( $sequence[-1] -eq "1" )
        {
            $allowed = @( $allowed | where-object { $_ -ne "3" } );
        }

        # Never 3 times knee in a row
        $knees = @($sequence | select-object -last 2 | where-object { $_ -eq "Knee" }).Length;
        if( $knees -ge 2 )
        {
            $allowed = @( $allowed | where-object { $_ -ne "Knee" } );
        }

        $sequence  = Get-Random $allowed;

    }

    return @(, $sequence);

}

Example usage:

PS> Get-Sequence
1
Knee
2
4

PS> Get-Sequence -Length 10
1
4
4
Knee
3
Knee
4
1
Knee
3
  • Related