オセロゲームを作ろう(3):スクリーンバッファ操作(1)

スクリーンバッファの操作

今回はスクリーンバッファの操作です。


具体的には、オセロゲームを実行するタイミングで、
その時点でコンソールに表示されている内容をバックアップし、
オセロが終了した際にバックアップ内容をコンソールにリストアします。


処理は、PowerShellコンテストのグランプリである「ウィンドウの切り替え」を参考にしています。

「キー入力監視」+「スクリーンバッファ操作」サンプル


# 初期処理
$rui = $host.UI.RawUI
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$keyMap = [Windows.Forms.Keys]
$script:screen = $null

# メイン
function Start-Game()
{
Backup-ScrBuf
Draw-Init
Get-InputKey
Restore-ScrBuf
}

# キー入力関数
function Get-InputKey()
{
while($true)
{
# キー取得
$keyInfo = $rui.ReadKey("NoEcho,IncludeKeyDown")
$keyCode = $keyInfo.VirtualKeyCode

# Enterを入力
if($keyCode -eq $keyMap::Enter){Show-Msg 'Enter';continue}

# Escを入力→終了
if($keyCode -eq $keyMap::Escape){return}
}
}

# メッセージ表示
function Show-Msg([String]$msg)
{
Write-Host -NoNewLine $msg
}

# スクリーンバッファのバックアップ
function Backup-ScrBuf()
{
$rect = New-Object System.Management.Automation.Host.Rectangle
$rect.Left = 0
$rect.Top = 0
$rect.Right = $rui.WindowSize.Width
$rect.Bottom = $rui.CursorPosition.Y
$script:screen = $rui.GetBufferContents($rect)
}

# スクリーンバッファのリストア
function Restore-ScrBuf()
{
Clear-Host
$origin = New-Object System.Management.Automation.Host.Coordinates(0, 0)
$rui.SetBufferContents($origin, $script:screen)
$pos = New-Object System.Management.Automation.Host.Coordinates(0, $script:screen.GetUpperBound(0))
$rui.CursorPosition = $pos
}

# 初期描画
function Draw-Init
{
Clear-Host
Write-Host "=================================="
Write-Host " Othello by PowerShell "
Write-Host "=================================="
}

# 処理スタート
Start-Game


上記スクリプトを実行すると、コンソールの内容がバックアップ、クリアされ、以下の文字列が表示されます。

==================================
      Othello  by  PowerShell     
==================================

キー入力は前回と同様「Enter」と「Escape」だけ個別処理をしています。
Escapeキーを押すとアプリが終了し、先ほどバックアップしたコンソール内容をリストアします。



つづく・・・。

オセロゲームを作ろう(2):キー入力監視

CUIのオセロゲームを作成する過程を、扱っていこうと思います。
まずは、キー入力監視についてです。

キー入力の監視

CUI版オセロゲームでは、駒を置く場所を指定するのに「上下左右キー + Enterキー」を利用します。
そのためにはアプリの起動中、常にキー入力を監視する必要があります。

キー入力監視サンプル


# 初期処理
$rui = $host.UI.RawUI
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$keyMap = [Windows.Forms.Keys]

# メイン
function Start-Game()
{
Get-InputKey
}

# キー入力関数
function Get-InputKey()
{
while($true)
{
# キー取得
$keyInfo = $rui.ReadKey("NoEcho,IncludeKeyDown")
$keyCode = $keyInfo.VirtualKeyCode

# Enterを入力
if($keyCode -eq $keyMap::Enter){Show-Msg 'Enter';continue}

# Escを入力→終了
if($keyCode -eq $keyMap::Escape){return}
}
}

# メッセージ表示
function Show-Msg([String]$msg)
{
Write-Host -NoNewLine $msg
}

# 処理スタート
Start-Game

サンプル解説

このサンプルを実行すると、キー入力の監視を開始します。
入力キーが「Enterキー」または「Escキー」の時のみ、個別処理を実行しています。

  • Enterキー
    • 「Enter」という文字列を表示する
  • Escキー
    • アプリケーションを終了する
入力キー取得:ReadKeyメソッド

$host.UI.RawUI.ReadKeyメソッドで入力キーを取得します。引数は、ReadKeyOptionsです。

本サンプルでは、ReadKeyOptionsとして以下の2つを指定しています。

  • NoEcho
    • NoEchoを指定すると入力キーをエコー表示しません。
    • この指定がないと、たとえば「A」キーを入力した際にコンソールに「a」と表示されます。
  • IncludeKeyDown
    • キーを押下した時点でキー情報を取得します。
    • IncludeKeyUpを指定した場合は、キーを離すまで取得しません。
入力キーの判定

ReadKeyメソッドの戻り値はKeyInfoオブジェクトです。
VirtualKeyCodeプロパティにはそのキーコードが入っています。


本サンプルでは、[Windows.Forms.Keys]を利用して入力キーを判定しています。
キーコードの数値で判定するより可読性が高いので、個人的にはKeysでの判定の方がお気に入りです。(^^)

オセロゲームを作ろう(1)

先日、ふと思い立ち、PowerShellでオセロゲームを作ってみました。
CUI版とGUI版の2種類です。

PowerShellオセロゲーム(CUI

上下左右のキー入力で、カーソルが盤面上を移動し、
Enterを押した場所に駒(という表現で良いのかな?)を置きます。

交互に駒を置き、ゲームを進めていきます。

PowerShellオセロゲーム(GUI

GUI版は、DataGridViewコントロールを利用してオセロの盤面を表現しています。
駒を配置可能なセルは背景色を少し濃くしています。

PowerShellのコンソール操作は奥が深い

今回、PowerShellで初めて本格的なコンソールアプリを作成したのですが、
なかなかに奥が深いです。


ちょっとしたオセロゲームを作るだけでも、

  • キー入力監視処理
  • カーソル操作処理
  • スクリーンバッファ操作処理
  • 描画処理

などなど、考えることが色々あるのですね。


今後、上記要素を紹介していきたいと思います。

モジュールのインポート(2)

PowerShellモジュール

まず「psm1」という拡張子のPowerShellスクリプトを作成します。おそらくPowerShellモジュールという意味でしょう。
拡張子がps1ではありませんが、記述方法は通常のps1と変わりません。外部から呼び出したい関数などを定義しておきます。


モジュールは(通常は)以下に配置します。

ドキュメントのパスをカスタマイズしている場合は、配置場所が上記ディレクトリと異なるので注意が必要です。<パッケージ名>以前の部分を、以下の実行結果に読み替えて下さい。

Join-Path  (split-path $profile) "packages"


オフィシャルのヘルプが提供されていないので、推測となってしまいますが、
モジュールのファイル名(拡張子除く)はパッケージ名と同じ名前のpsm1ファイルを配置する必要があるようです。
たとえば、このような形です。(以下はVista環境、ユーザ名:Yoshiokaの場合です)

C:\Users\Yoshioka\Documents\WindowsPowerShell\packages\sample\sample.psm1

モジュールのインポート(1)

ドットソースとモジュール

従来、PowerShell V1でスクリプトファイルのインクルードを行う場合、
「ドットソース」を利用する必要がありました。

ドットソースは、指定したスクリプトファイルの内容をPowerShellのコンソールにペースト実行するのと同じ挙動を示します。
しかし、この仕様ではモジュールベースの開発に不都合が生じます。
たとえば、スクリプトをドットソースで読み込んだ場合、名前が重複する関数があると他方が上書きされてしまいます。
パッケージという概念がなかったために、読み込んだスクリプトを区別する方法がありませんでした。


今回、PowerShell V2 CTP2ではモジュールとパッケージという概念が導入されました。
モジュールに関連するコマンドレットは以下です。

  • Add-Module
  • Get-Module
  • Remove-Module
  • Export-ModuleMember


上記URLからダウンロードできるリリースノートにこれらのコマンドレットのサンプルが載っていますが、
情報が少ないので気付いた点を記述しておきます。

Execution Policyを一元管理する

現在、マイクロソフト本社のあるレドモンドでは、
年に一度、世界中のMVPが集まるイベント、「2008 MVP Global Summit」が開かれています。
#私も参加しています。

PowerShell向けのグループポリシーのテンプレート

今日、PowerShellのアーキテクトであるJeffrey Snoverと話す機会があり、
以下の質問をしました。

 PowerShellを組織全体に適用する際、Execution Policyを一元管理したい。どうすればよいか?


答えは簡単、グループポリシーを利用すればよい、とのことでした。
私は全く知らなかったのですが、(^^;
PowerShell向けのグループポリシーのテンプレートが公開されているそうです。


こちらです。