JAPLA シンポジウム資料 2005/12/10 J のオブジェクト指向プログラミング (OOP- その 2 ( J Object Oriented Programming - II J のスプレッドシート (Grid と数独パズルへの適用 ( J Spreadsheet(Grid and its Application to 'Sudoku' Puzzle 西川利男 ( Toshio Nishikawa@kiu.ne.jp Jでも Excel や Lotus-1,2,3 などのようなスプレッドシートを自由自在に行うことができる.Jではこれを Grid と呼んでいるが, オブジェクト指向プログラミング (OOP の格好の適用例である. また,Jの Labs には Grid のていねいが解説がある. このデモを実行しつつ,Jの Grid をやさしく説明しよう. 一方, ごく最近, 数独 なるパズルが, 読売新聞, 毎日新聞などの紙上で紹介され話題となった. これは日本で生まれたパズルであるが, いまや Sudoku として世界中で大勢のファンがいる [1]. この数独パズルは, 一種の数字埋めパズルだが, われわれにとってこれをコンピュータでやらない法はない. 筆者は先に Excel を利用して作ったものを新聞社に投稿した ( 巻末を参照. 今回はJの Grid プログラミングを用いて, かつまたOOPの好例としてプログラムを作成してみたので, その実際をお目にかける. 1.JのOOPと Grid プログラミング JのOOPの基本については, 別報その1として易しく述べた. また, スプレッドシート Grid のプログラムは,J4 以降のシステムでOOPの典型的適用例として取り扱われている. このように,Jの Grid プログラミングを理解するには,[Studio]-[Labs] を開いて, 以下の Labs チュートリアルを順々に実行して, 学習するのが最も良い. Grid Basic Examples Grid Control Grid Low Level Programming まず,Grid Basic Examples を開いて走らせてみれば,Excel と同様の画面が現れ, もっと手軽に行われることに驚くだろう. 数値データ, 文字列データ, テーブルの計算, ファイナンシャルの図表などの例がある.Grid Control ではフォームの上でマウス操作によるイベントのプログラムを解説している.Grid Low Level Programming では Grid の各種コマンドをJのプログラムの詳細レベルで解説する. さらに必要とあれば, クラス プログラムのソースコードまで公開され見ることができて, 処理の細部まで検討できるのが JのOOPによる Grid の利点である. [1] ニコリ 数独パズル ホームページ http://www.puzzle.jp/ - 1 -
2.Grid プログラミングの基本 OOPのメリットとして,Grid をためしてみるには, 例えば, 次の数行を入力するだけで良い. corequire 'jwatch' d1 =: 1+?1+i. 20 10 w1 =: 'd1' conew 'jwatch' つまり, 値 d1 を元に Grid クラス jwatch からコマンド conew によりインスタンス w1 が作られ, それが即, 表示される. この簡便さは元となるOOPのクラス プログラムの資源がすべて継承されているからである. この Grid の上で,CTRL-e とすれば, 任意のセルで値を変更することが出来るようになる. また,CTRL-m とすると, 計算式の入力が促され, 次のように式を入れると 1=(#@:q:"(0 y. すべてのセルにわたって, 素数かどうかをテストして, 値が素数のセルの色が変わる. 3. 数独パズルとは最初, 以下のようなマス目に適宜,1から9の数字が入っている. そこで, ヨコの行に同じ数字があってはならない. タテの列に同じ数字があってはならない. 色わけしたブロック内に同じ数字があってはならない. というルールに従って, 空いたマス目に次々に数字を埋めて完成させる, というパズルである. いろいろな場所のマス目を選んで, 数字が一つに定まったところから埋めて行けば, だんだんと空いたマス目も数字で埋まり出来上がる. たとえば, 最初 2 行 6 列のマス目では数字はひとつに定まらないが,0 行 6 列のマス目では3と決まる. すると, 先の2 行 6 列のマス目も5と定まることになる. このようにして, 次々と数字を埋めて行けば良い. 5 7 1 4 7 3 1 2 8 4 6? 9 9 4 6 8 3 8 7 1 8 5 6 9 1 6 3 8 5 6 7 1 3 5 9 2-2 -
4.J-Grid による数独パズル作成のプログラミング プログラムはメイン プログラム sudoku.ijs とクラス プログラム psudoku.ijs とか ら成る. メイン プログラムは OOP により次のように極めて簡単である. da_sudoku =: _ 5 _ 7 _ 1 _ 4 _ da_sudoku =: da_sudoku, 7 _ 3 _ 1 _ 2 da_sudoku =: da_sudoku, _ 8 _ 4 _ 6 _ 9 _ da_sudoku =: da_sudoku, 9 _ 4 _ 6 _ 8 _ 3 da_sudoku =: da_sudoku, _ 8 _ 7 _ da_sudoku =: da_sudoku, 1 _ 8 _ 5 _ 6 _ 9 da_sudoku =: da_sudoku, _ 1 _ 6 _ 3 _ 8 _ da_sudoku =: da_sudoku, 5 _ 6 _ 7 _ 1 da_sudoku =: da_sudoku, _ 3 _ 5 _ 9 _ 2 _ da_sudoku =: 9 9 $ da_sudoku run =: 3 : 0 load 'user\classes\psudoku.ijs' d1 =: da_sudoku w =: 'd1' conew 'psudoku' まず, 数独パズルの初期値を数値の配列 da_sudoku として作る. このとき, 空白という値は数値にないので, これをどういう値にするかが問題になる. 幸いJには無限大 (_ という値があるので, パズルの表記にじゃまにならないし, これを利用した. 今の場合は大丈夫であろうが,0を使うと空白との区別など何かと問題が起こることもあるだろう. また,Grid で (Excel でもそうだが セルの値として, 数値を文字列として扱う場合, やっかいな考慮が必要になる. 配列値 da_sudoku を変数 d1( 数値の場合の共通の変数名 にセットして, コマンド conew によりクラス psudoku のインスタンス w を作って, 実行させる. クラス プログラム psudoku では, さらに親のクラス jwgrid を継承しているので, そこにない処理の部分のプログラムを作ることになる. クラス プログラムの全体は最後にのせた. ここには再掲しないが適宜, 参照されたい. 主要部分だけを説明する. 最初の1 行 coclass 'psudoku' はクラス プログラムであることの宣言である. なお,OOPに関するコマンドは多くの場合 co で始まるが, これは class object を意味する. 関数定義 create は起動時に実行されるプログラムである. まず,PSUDOU が実行され, フォームが作られる. 次に, クラス jwgrid のインスタンスが grid という名で作られ, その機能が使用可能となる. さらに,setcolor によるフォーム セルの色の設定, 文字フォントの設定などがなされる. - 3 -
主要プログラムは psudoku_grid_mbldown であり, マウスの左ボタンが押されたときに, イベントとして実行される. 一般にマウスを操作すると, その結果はシステム変数 sysdata として, 位置などの情報が返される. サブ関数 sys2cel は上の sysdata から Grid 上マウスで指示されたセルの行 R, 列 C の値に変換するものである. これを元に以下のような gl2 の grid graphics の命令により, それぞれの操作が行われる. glgridmark, glgriddrawmark, glgridgettext, glgridrchw, glgridtext マウスでマークしたセルの行の値, 列の値, セルの値は edit ボックス e1, e2, e3 に示す. 次にそのセルの値から, 数独パズルのルールに従って,3つの条件テストを行う. ヨコ方向 (horizontal のセルの値 (CDX は edit ボックス e4(x にタテ方向 (vertical のセルの値 (CDY は edit ボックス e5(y にブロック内 (block のセルの値 (CDZ は edit ボックス e6(block にさらにこれらのチェックにより入力できる候補となる値 (CD は edit ボックス e7(select にそれぞれ, 入れられ表示される. 従って,CD の値 (Select が1つだけにしぼられたとき, この値を確定値として, マークされたセルに入れればよい. 5.Jによる数独パズルの実際 2 行 2 列のセルをチェックしている状態の画面である. - 4 -
プログラムリスト ( クラス プログラム NB. 'Sudoku Puzzle' by Toshio Nishikawa 2005/10/31 coclass'psudoku' corequire 'jwgrid' PSUDOKU=: 0 : 0 pc psudoku; xywh 7 24 264 120;cc grid isigraph ws_border rightmove bottommove; xywh 7 144 128 11;cc sb scrollbar topmove rightmove bottommove; xywh 272 24 11 120;cc sbv scrollbarv leftmove rightmove bottommove; xywh 15 159 18 11;cc e1 edit ws_border es_autohscroll; xywh 40 159 18 11;cc e2 edit ws_border es_autohscroll; xywh 72 159 50 11;cc e3 edit ws_border es_autohscroll; xywh 85 6 46 11;cc e4 edit ws_border es_autohscroll; xywh 143 6 50 11;cc e5 edit ws_border es_autohscroll; xywh 215 6 50 11;cc e6 edit ws_border es_autohscroll; xywh 31 6 36 11;cc e7 edit ws_border es_autohscroll; xywh 11 7 19 10;cc sel static;cn "Select:"; xywh 77 8 9 10;cc vert static;cn "X"; xywh 137 8 7 10;cc horiz static;cn "Y"; xywh 200 8 16 10;cc block static;cn "Block"; pas 6 6;pcenter; rem form end; create=: 3 : 0 wd PSUDOKU formhwnd=: wd'qhwndp' grid=: ''conew'jwgrid' init grid 'd1_base_';'grid';'sb';'sbv' setcolor '' sizeenable grid=: 1 editenable grid=: 0 glgridfont0 '"courier new" 20 bold' D=: d1_base_ ('Row';'Col' =: $D gridws=: Row$50 gridhs=: Col$20 wd 'pshow;' - 5 -
setcolor =: 3 : 0 glgridrchw 1 1 3 3 glgridrchw 1 7 3 3 glgridrchw 7 1 3 3 glgridrchw 7 7 3 3 glgridrchw 4 4 3 3 destroy=: 3 : 0 wd'pclose' codestroy'' psudoku_cancel=:psudoku_cancel_button=:psudoku_close=:destroy formselect=: 3 : 'wd''psel '',formhwnd' psudoku_grid_size=: 3 : 'size grid 0' psudoku_grid_mmove=: 3 : 'mmove grid sysdata' psudoku_grid_mblup=: 3 : 'mblup grid sysdata' psudoku_grid_mbldbl=: 3 : 'mbldbl grid sysdata' psudoku_grid_char=: 3 : 'char grid sysdata' psudoku_grid_copy=: 3 : 'copy grid 0' psudoku_grid_paste=: 3 : 'paste grid 0' psudoku_sb_button=: 3 : 0 scrollbar grid sb wd'setfocus grid' psudoku_sbv_button=: 3 : 0 scrollbarv grid sbv wd'setfocus grid' - 6 -
psudoku_ectrl_fkey=: 3 : 0 editenable grid=: -. editenable grid NB. Check by mouse left down ================== sys2cel =: 3 : 0 NB. convert sysdata to Cell R, C d=. (0{d,-/3 1{d=. ".y. rc=. (+/(1{d>:+/\gridhs, +/(0{d>:+/\gridws rc psudoku_grid_mbldown=: 3 : 0 RC =: sys2cel sysdata ('R';'C' =. RC glgridmark RC,1 1 glgriddrawmark'' NB. cell position and data wd 'set e1 ', ": 0{_1 + RC wd 'set e2 ', ": 1{_1 + RC cdata =: glgridgettext R, C wd 'set e3 ', (": cdata NB. Cell Data Check Dislay CD =. >:i.9 NB. horizontal check ==== cdx =. '' j=. 1 while. j <: Col do. Cel_RC =. R, j cdx =. cdx, (glgridgettext Cel_RC, ',' j =. j + 1 end. CDX =. (". (}:cdx -. _ CD =. CD -. CDX wd 'set e4 ', (}:,(":,. CDX,"1 ',' NB. vertical check ==== cdy =. '' i=.1 while. i <: Row do. - 7 -
Cel_RC =. i, C cdy =. cdy, (glgridgettext Cel_RC, ',' i =. i + 1 end. CDY =. (". (}:cdy -. _ CD =. CD -. CDY wd 'set e5 ', (}:,(":,. CDY,"1 ',' NB. block check === cdz =. '' R0 =. 3*<.3%~_1+R C0 =. 3*<.3%~_1+C i=. 1 while. i<:3 do. j=. 1 while. j<:3 do. Cel_RC =. (R0+i, (C0+j cdz =. cdz, (glgridgettext Cel_RC, ',' j =. j + 1 end. i =. i + 1 end. CDZ =. (". (}:cdz -. _ CD =. CD -. CDZ wd 'set e6 ', (}:,(":,. CDZ,"1 ',' wd 'set e7 ', (}:,(":,. CD,"1 ',' psudoku_e7_button=: 3 : 0 editenable grid=: 1 glgridrchw RC, 1 1 glgridtext ": e7 glpaintx '' - 8 -
( 参考 Excel で数独ゲームを楽しむ 西川利男 ( 無職 元国立研究所勤務 70 才 読売新聞 10 月 15 日 ( 土 の朝刊に日本で生まれた 数独ゲーム がアメリカ ヨーロッパの各地で評判になっている という記事がのった ゲームのやり方はタテ ヨコおよび属するブロックの数字とぶつからない数字で空いたマスをつぎつぎうずめていく というだけの単純なものだが やってみると これがなかなかむずかしい そして定年後のアタマをボケさせないためにもけっこう楽しい コンピュータ プログラミングを仕事とし また趣味でもある私にとって別のおもしろさもある この 数独ゲーム をコンピュータの上で Excelを使って楽しむものを作ってみた これから 入れようとするマスでExcelのマクロとして CTRL-s を打ち込むと 候補となる数字を次々と示し 一つにしぼられ確定したときは その数字が自動的に入れられる ( 図はセル C3 に入れる数字をチェックしているところ 以前 別の新聞誌上でも紹介され 孫とともに楽しんでいたマイ ワイフに言わせると コンピュータが教えてくれてしまってはつまらない とのご感想である しかし 現代の孫たち若者にとっては かえってなじみやすく Excelのおもしろい使い方として 歓迎されるのではないだろうか - 9 -