My PowerShell Usergroup:
As I said before, I am a regular at my local PowerShell user group. I keenly look forward to our monthly meetings. We share a lot of PowerShell code/tips/tricks among ourselves. It is a small but close-knit group. Yesterday, one of the members, Jason Walker came up with coding puzzles for the group. This blog post is about the puzzles Jason created for solving using PowerShell. This is the kind of simple stuff that keeps the meetings interesting and fun (besides the Pizza!).
My solutions may not be the most elegant or concise but they work and were created on the fly during the meeting!
Puzzle 1: Generate Prime Numbers
The first puzzle for the night was to generate Prime numbers. As described, “A prime number (or a prime) is a natural number greater than 1 that cannot be formed by multiplying two smaller natural numbers“.
The first 25 prime numbers (all the prime numbers less than 100) are:
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97
The solution is to have two loops. The outer loop loops through all the numbers in a sequence. The inner loop loops from 2 up to the current number trying to divide it by the inner loop number. If the outer loop number is divisible with a remainder of zero, we break from the inner loop as it is a composite number and not a prime. If we have exhausted the inner loop, it is a prime!
[int[]] $allnumbers = @(1..100); [bool] $divisible = $false; [int] $numSub = 0; ForEach ($num in $allnumbers) { $divisible = $false; foreach ($numSub in @(2..$num)) { if ($num -ne $numSub) { if (($num % $numSub) -eq 0) ` { $divisible = $true; break; } } } if ($divisible -eq $false) { $numSub; } }
Puzzle 2: Is Number Even – Without Any Arithmetic Operators
This puzzle requires some out-of-the box thinking as no arithmetic operators can be used (like +, -, *, /, % etc.). It clicked after Jason gave us a clue which is to convert them to Binary. To understand what I mean let us convert the numbers 1 through 25 to their binary equivalent and see the results:
@(1..25) | %{"$_ = " + [Convert]::ToString($_, 2)}
The results are:
1 = 1 2 = 10 3 = 11 4 = 100 5 = 101 6 = 110 7 = 111 8 = 1000 9 = 1001 10 = 1010 11 = 1011 12 = 1100 13 = 1101 14 = 1110 15 = 1111 16 = 10000 17 = 10001 18 = 10010 19 = 10011 20 = 10100 21 = 10101 22 = 10110 23 = 10111 24 = 11000 25 = 11001
Do you see the pattern? All even numbers end with a zero and all odd numbers end with a one. The right-most (first digit) of the binary form. The first digit is the 1’s place. The picture here should explain things better.
Once, the above is clear, the answer is simple!
[int[]] $allnumbers = @(1..100) ForEach ($num in $allnumbers) { #convert to binary and if the last digit is 0, it is a even number if (([Convert]::ToString($num, 2)).EndsWith(0)) { $num } }
This should give us the results we need
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 ....
Puzzle 3: Bi-weekly Pay Days For The Year + Bonus For Finding 3 Payment Months
Starting with a date like January 11, 2019, the goal is to find all the bi-weekly Pay Day’s for the year. You get bonus points for identifying the months with more than 2 payments!
For this one, I had two solutions. The long and mundane solution and then the concise solution.
Solution #1: The mundane one:
This does not need much explanation. We just increment the start date by 14 days and keep a counter for month to see if we have 3 of the same month in a row to print:
[Datetime]$startDate = [Datetime]'1/11/2019' [Datetime]$endDate = [Datetime]'1/11/2019' [int] $sameMonthCounter = 0 #First paydate $endDate While ($endDate -le [Datetime]'12/31/2019') { $endDate = $endDate.AddDays(14) $endDate if ($endDate.Month -eq $endDate.AddDays(-14).Month) { $sameMonthCounter++ } else { $sameMonthCounter = 1 } if ($sameMonthCounter -eq 3) { "******** $endDate has 3 paydays ********" } }
The output is as below:
Friday, January 11, 2019 12:00:00 AM Friday, January 25, 2019 12:00:00 AM Friday, February 8, 2019 12:00:00 AM Friday, February 22, 2019 12:00:00 AM Friday, March 8, 2019 12:00:00 AM Friday, March 22, 2019 12:00:00 AM Friday, April 5, 2019 12:00:00 AM Friday, April 19, 2019 12:00:00 AM Friday, May 3, 2019 12:00:00 AM Friday, May 17, 2019 12:00:00 AM Friday, May 31, 2019 12:00:00 AM ******** 05/31/2019 00:00:00 has 3 paydays ******** Friday, June 14, 2019 12:00:00 AM Friday, June 28, 2019 12:00:00 AM Friday, July 12, 2019 12:00:00 AM Friday, July 26, 2019 12:00:00 AM Friday, August 9, 2019 12:00:00 AM Friday, August 23, 2019 12:00:00 AM Friday, September 6, 2019 12:00:00 AM Friday, September 20, 2019 12:00:00 AM Friday, October 4, 2019 12:00:00 AM Friday, October 18, 2019 12:00:00 AM Friday, November 1, 2019 12:00:00 AM Friday, November 15, 2019 12:00:00 AM Friday, November 29, 2019 12:00:00 AM ******** 11/29/2019 00:00:00 has 3 paydays ******** Friday, December 13, 2019 12:00:00 AM Friday, December 27, 2019 12:00:00 AM Friday, January 10, 2020 12:00:00 AM
Solution #2: The more elegant solution:
Here, we collect the dates into an ArrayList and then do a Group-Object to get the months with more than 3 or more pay dates.
[Datetime]$startDate = [Datetime]'1/11/2019' [Datetime]$endDate = [Datetime]'1/11/2019' [System.Collections.ArrayList]$ArrayList = @() $ArrayList.Add($endDate) | Out-Null While ($endDate -le [Datetime]'12/31/2019') { $endDate = $endDate.AddDays(14) $ArrayList.Add($endDate) | Out-Null } #The results $ArrayList "-----------" #Months with more than 2 payments $ArrayList | %{$_.ToString('MMM')} | Group-Object | Where-Object {$_.count -gt 2} | Select-Object Name, Count | Format-Table
This again gives us the desired output
Friday, January 11, 2019 12:00:00 AM Friday, January 25, 2019 12:00:00 AM Friday, February 8, 2019 12:00:00 AM Friday, February 22, 2019 12:00:00 AM Friday, March 8, 2019 12:00:00 AM Friday, March 22, 2019 12:00:00 AM Friday, April 5, 2019 12:00:00 AM Friday, April 19, 2019 12:00:00 AM Friday, May 3, 2019 12:00:00 AM Friday, May 17, 2019 12:00:00 AM Friday, May 31, 2019 12:00:00 AM Friday, June 14, 2019 12:00:00 AM Friday, June 28, 2019 12:00:00 AM Friday, July 12, 2019 12:00:00 AM Friday, July 26, 2019 12:00:00 AM Friday, August 9, 2019 12:00:00 AM Friday, August 23, 2019 12:00:00 AM Friday, September 6, 2019 12:00:00 AM Friday, September 20, 2019 12:00:00 AM Friday, October 4, 2019 12:00:00 AM Friday, October 18, 2019 12:00:00 AM Friday, November 1, 2019 12:00:00 AM Friday, November 15, 2019 12:00:00 AM Friday, November 29, 2019 12:00:00 AM Friday, December 13, 2019 12:00:00 AM Friday, December 27, 2019 12:00:00 AM Friday, January 10, 2020 12:00:00 AM ----------- Name Count ---- ----- Jan 3 May 3 Nov 3
Puzzle 4: Floyd’s Triangle With Numbers
This puzzle is to build a triangle with numbers. The first line has one number, the second line two numbers, the third line three numbers and so on. Only when you try to code this will you see that it is not as simple as it sounds. If you don’t believe me, please try.
The output should be like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
The code that I created to produce it is not too complex. Basically, $line keeps track of which line number we are writing to. The line should have as many numbers printed. The counter $numsWritten keeps tracks of how many numbers have been written on the current line. Once we are done, we reset the counters and continue.
[int[]] $allnumbers = @(1..100) [int] $line = 0 [int] $numsPerLine = 1 [int] $numsWritten = 0 [int] $totalLines = 12 ForEach ($num in $allnumbers) { Write-Host "$num " -NoNewline $numsWritten++ if($numsWritten -gt $line) { Write-Host " " $numsWritten = 0 $line++ if ($line -gt $totalLines) { break; } } }
The output is as expected:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
We did a more complex version of this same thing in an earlier Puzzle Night.
Hope you got something out of this as I did. Thanks for reading!
One thought on “PowerShell: Puzzle Night At the User Group!”