オセロゲームを作ろう(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
本サンプルでは、ReadKeyOptionsとして以下の2つを指定しています。
- NoEcho
- NoEchoを指定すると入力キーをエコー表示しません。
- この指定がないと、たとえば「A」キーを入力した際にコンソールに「a」と表示されます。
- IncludeKeyDown
- キーを押下した時点でキー情報を取得します。
- IncludeKeyUpを指定した場合は、キーを離すまで取得しません。
入力キーの判定
ReadKeyメソッドの戻り値はKeyInfoオブジェクトです。
VirtualKeyCodeプロパティにはそのキーコードが入っています。
本サンプルでは、[Windows.Forms.Keys]を利用して入力キーを判定しています。
キーコードの数値で判定するより可読性が高いので、個人的にはKeysでの判定の方がお気に入りです。(^^)
オセロゲームを作ろう(1)
先日、ふと思い立ち、PowerShellでオセロゲームを作ってみました。
CUI版とGUI版の2種類です。
PowerShellオセロゲーム(CUI)
上下左右のキー入力で、カーソルが盤面上を移動し、
Enterを押した場所に駒(という表現で良いのかな?)を置きます。
交互に駒を置き、ゲームを進めていきます。
PowerShellのコンソール操作は奥が深い
今回、PowerShellで初めて本格的なコンソールアプリを作成したのですが、
なかなかに奥が深いです。
ちょっとしたオセロゲームを作るだけでも、
- キー入力監視処理
- カーソル操作処理
- スクリーンバッファ操作処理
- 描画処理
などなど、考えることが色々あるのですね。
今後、上記要素を紹介していきたいと思います。
モジュールのインポート(2)
PowerShellモジュール
まず「psm1」という拡張子のPowerShellスクリプトを作成します。おそらくPowerShellモジュールという意味でしょう。
拡張子がps1ではありませんが、記述方法は通常のps1と変わりません。外部から呼び出したい関数などを定義しておきます。
モジュールは(通常は)以下に配置します。
- $home\documents\windowspowershell\packages\<パッケージ名>\
ドキュメントのパスをカスタマイズしている場合は、配置場所が上記ディレクトリと異なるので注意が必要です。<パッケージ名>以前の部分を、以下の実行結果に読み替えて下さい。
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向けのグループポリシーのテンプレートが公開されているそうです。
こちらです。