PowerShellでFibonacci Clockを再現する

いやーん、すてき!
フィボナッチ数列の最初の部分を使った時計ですって!
Fibonacci Clock - An open source clock for nerds with style by Philippe Chrétien — Kickstarter


、、、なんかこういうの、脳から変な汁出て、衝動的に投資したくなるけど、冷静に考えると高い。
$75でキットか、$135で完成品って、、、。
$75のキットに投げるくらいなら、
CHIP - The World's First Nine Dollar Computer by Next Thing Co. — Kickstarter
に投げて自分で作った方が納得感がある。
うんうん、高いよ。


ということで、変な汁出た分を解消するために、スクリプトを書いてみた。
いろいろ適当だけど。



スクリプト

左ドラッグで移動できます。
右クリックで終了。


時間表現に何パターンかあるので、30秒毎に入れ替えが行われます。
ランダムではありません。
なお、0を表現するパターンは1種類しかないため、12も0とみなすことにしました。

Add-Type -AssemblyName System.Windows.Forms

$form = New-Object System.Windows.Forms.Form
$form.SuspendLayout()
$form.ControlBox = $false
$form.ShowInTaskbar = $false
$form.ClientSize = New-Object System.Drawing.Size 160, 100
$form.Text = ''
$funcMouseUp = {
	Param ($sender, $ev)
	if($ev.Button -eq 'Right') { $form.Close() }
}
$funcMouseDown = {
	Param ($sender, $ev)
	if($ev.Button -eq 'Left') { $dragPos = New-Object System.Drawing.Point($ev.X, $ev.Y) }
}
$funcMouseMove = {
	Param ($sender, $ev)
	if($ev.Button -eq 'Left') {
		$form.Left += $ev.X - $dragPos.X
		$form.Top += $ev.Y - $dragPos.Y
	}
}
$form.Add_MouseUp($funcMouseUp)
$form.Add_MouseDown($funcMouseDown)
$form.Add_MouseMove($funcMouseMove)
$blocks = New-Object System.Windows.Forms.PictureBox[] 5
for($i = 0; $i -lt $blocks.Length; $i++) {
	$blocks[$i] = New-Object System.Windows.Forms.PictureBox
	$blocks[$i].BeginInit()
	$blocks[$i].BackColor = 'White'
	$blocks[$i].TabStop = $false
	$blocks[$i].Add_MouseUp($funcMouseUp)
	$blocks[$i].Add_MouseDown($funcMouseDown)
	$blocks[$i].Add_MouseMove($funcMouseMove)
	$form.Controls.Add($blocks[$i])
	$blocks[$i].EndInit()
}

$patternTable = @(
	@(	@( $false, $false, $false, $false, $false ),
		@(  $true,  $true,  $true,  $true,  $true )	),
	@(	@(  $true, $false, $false, $false, $false ),
		@( $false,  $true, $false, $false, $false )	),
	@(	@(  $true,  $true, $false, $false, $false ),
		@( $false, $false,  $true, $false, $false )	),
	@(	@(  $true, $false,  $true, $false, $false ),
		@( $false,  $true,  $true, $false, $false ),
		@( $false, $false, $false,  $true, $false )	),
	@(	@(  $true,  $true,  $true, $false, $false ),
		@(  $true, $false, $false,  $true, $false ),
		@( $false,  $true, $false,  $true, $false )	),
	@(	@(  $true,  $true, $false,  $true, $false ),
		@( $false, $false,  $true,  $true, $false ),
		@( $false, $false, $false, $false,  $true )	),
	@(	@(  $true, $false,  $true,  $true, $false ),
		@( $false,  $true,  $true,  $true, $false ),
		@(  $true, $false, $false, $false,  $true ),
		@( $false,  $true, $false, $false,  $true )	),
	@(	@(  $true,  $true,  $true,  $true, $false ),
		@(  $true,  $true, $false, $false,  $true ),
		@( $false, $false,  $true, $false,  $true )	),
	@(	@(  $true, $false,  $true, $false,  $true ),
		@( $false,  $true,  $true, $false,  $true ),
		@( $false, $false, $false,  $true,  $true )	),
	@(	@(  $true,  $true,  $true, $false,  $true ),
		@(  $true, $false, $false,  $true,  $true ),
		@( $false,  $true, $false,  $true,  $true )	),
	@(	@(  $true,  $true, $false,  $true,  $true ),
		@( $false, $false,  $true,  $true,  $true )	),
	@(	@(  $true, $false,  $true,  $true,  $true ),
		@( $false,  $true,  $true,  $true,  $true )	)
)
$keyTable = @(
	@( @(0, 0, 0, 0, 0, 0), @(0, 1, 0, 1, 0, 1) ),
	@( @(0, 0, 0, 0, 0, 2), @(0, 1, 0, 2, 1, 1) ),
	@( @(0, 0, 1, 0, 1, 2), @(1, 1, 1, 1, 1, 3) ),
	@( @(1, 0, 1, 2, 2, 0), @(1, 1, 2, 0, 2, 1) ),
	@( @(1, 0, 2, 1, 3, 2), @(1, 1, 2, 2, 3, 3) )
)
$_hour = -1
$_minute = -1
$_second30 = -1
$funcUpdateBlocks = {
	$time = [DateTime]::Now
	$hour = $time.Hour % 12
	$minute = $time.Minute
	$second30 = [int][Math]::Floor([double]$time.Second / 30)
	if ($hour -ne $_hour -or $minute -ne $_minute -or $second30 -ne $_second30) {
		$minute5 = [int][Math]::Floor([double]$minute / 5)
		$hb = $patternTable[$hour][$keyTable[$minute % 5][$second30][($patternTable[$hour].Length - 2) * 2]]
		$mb = $patternTable[$minute5][$keyTable[$minute % 5][$second30][($patternTable[$minute5].Length - 2) * 2 + 1]]
		for($i = 0; $i -lt $blocks.Length; $i++) {
			if($hb[$i]) {
				if($mb[$i]) {
					$blocks[$i].BackColor = 'Blue'
				} else {
					$blocks[$i].BackColor = 'Red'
				}
			} elseif($mb[$i]) {
				$blocks[$i].BackColor = 'Green'
			} else {
				$blocks[$i].BackColor = 'White'
			}
		}
		$_hour = $hour
		$_minute = $minute
		$_second30 = $second30
	}
}
$funcRelocateBlocks = {
	$widthU = [int][Math]::Floor([double]$form.ClientSize.Width / 8)
	$widthR = $form.ClientSize.Width - $widthU * 8 - 2
	$heightU = [int][Math]::Floor([double]$form.ClientSize.Height / 5)
	$heightR = $form.ClientSize.Height - $heightU * 5 - 2

	$i = 0
	$size = New-Object System.Drawing.Size $widthU, $heightU
	$loc = New-Object System.Drawing.Point ($widthU * 2 + 1), ($heightU + 1)
	$blocks[$i].Size = $size
	$blocks[$i].Location = $loc
	$i++
	$loc.Y = 0
	$blocks[$i].Size = $size
	$blocks[$i].Location = $loc
	$i++
	$loc.X = 0
	$size = New-Object System.Drawing.Size ($widthU * 2), ($heightU * 2 + 1)
	$blocks[$i].Size = $size
	$blocks[$i].Location = $loc
	$i++
	$loc.Y = ($heightU + 1) * 2
	$size = New-Object System.Drawing.Size ($widthU * 3 + 1), ($heightU * 3 + $heightR)
	$blocks[$i].Size = $size
	$blocks[$i].Location = $loc
	$i++;
	$loc.X = $widthU * 3 + 2
	$loc.Y = 0
	$size = New-Object System.Drawing.Size ($widthU * 5 + $widthR), ($heightU * 5 + $heightR + 2)
	$blocks[$i].Size = $size
	$blocks[$i].Location = $loc

	&$funcUpdateBlocks
}
$form.Add_Resize({
	&$funcRelocateBlocks
})

$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 5000
$random = New-Object Random
$timer.Add_Tick({
	&$funcUpdateBlocks
})
$timer.Enabled = $true
$form.ResumeLayout($false)

[void]$form.ShowDialog()
$timer.Dispose()
$form.Dispose()


言いたいこと。

  • フィボナッチ数列の最初の5つは、「0,1,1,2,3」です
  • 時が「赤」、分が「緑」、両方は「青」というカラーリングはイマイチです