Nov 16

先週の日曜日、弊社若手社員3人でICPC東京大会を観戦、懇親会にも参加させていただきました。
(ICPCの公式ページはこちら→ACM/ICPC Asia Regional Contest 2009, Tokyo, Japan
今回は弊社もスポンサーとして、ICPCと学生プログラマーの支援をさせていただきました!

ICPCの会場に入るや否や、さっそく大きな歓声が!!
そう、そこで行われていたのは「Javaチャレンジコンペ」という、各チームが短時間で作成したAI同士の熱い戦いです。

こういったAI同士を競い合わせる競技は熱く盛り上げれますね。次回天下一プログラマー大会の参考にさせていただきます!

本選の優勝者は「HITORI#」チーム。チームの一人は天下一プログラマーコンテストの優勝者です。他にも天下一プログラマーに参加されていた方々が多数入賞されていました。おめでとうございます!!

表彰の後の懇親会ではinada-nがスピーチをさせていただきました。

今後も、プログラミングコンテストの主催や後援を通して、学生プログラマーを応援していきたいと考えております!
夏に開催された天下一プログラマーコンテストが気になる方はこちらにアクセス!!

Oct 19

Haskellで、TCPのサーバーを書いてみたいと思い、手始めにエコーサーバーを書いてみました。
エコーサーバーというのは、クライアントからの入力をそのまま返すサーバーです。

以下の記事を参考にもっと簡単なものを作ってみます。
A simple TCP server | The Haskell Sequence

main = withSocketsDo $ do
         [p] <- getArgs
         let port = fromIntegral (read p :: Int)
         soc <- listenOn $ PortNumber port
         putStrLn $ "start server, listening on: " ++ show port
         acceptLoop soc `finally` sClose soc

main部分です。
ソケットを開いてlistenします。

acceptLoop soc = do
  (hd, host, port) <- accept soc
  forkOS $ echoLoop hd
  acceptLoop soc

mainのあとの処理です。
クライアントがきたら、accept(受け付け)して、新しいスレッドを生成し、そちらに処理を任せます。
新しいクラアントに対応しつづけるため、処理が終わってはいけませんので、こちらは無限ループを続けます。

echoLoop hd = do
  sequence_ (repeat (do { -- ioアクションの無限リスト
                          l <- hGetLine hd;
                          hPutStrLn hd l;
                          hFlush hd
                     }))
  `catch` (\(SomeException e) -> return ())
  `finally` hClose hd

クライアントごとの処理です。
こちらは、一行読み込んで一行そのまま書き込むという処理を繰り返しているだけです。

さっそく実行してみましょう。

$ ghc -o echoHS -O --make -threaded echosimple.hs
$ ./echoHS 8080
start server, listening on: 8080

別のコンソールをひらきアクセスしてみます。

$ telnet localhost 8080
hoge
hoge
aiu
aiu


できました!
30行程度で、エコーサーバーが完成しました。
ついでにRubyでも同じものを書いたのでそちらも掲載しておきます。

Continue reading »

Oct 19

天下一プログラマー実行委員の takada-at です。
今回は、本戦1日目の1問目にあたる「障害物ありNクイーン」を紹介します。

解答

20
-Q--*******Q----
---Q*******--Q--
----******-----Q
-----****Q------
-----***------Q-
------*-Q-------
----------Q*****
Q---------******
--Q-------******
----------Q*****
-----Q*Q--------
-----***-----Q--
----Q****------Q
----******--Q---
----*******---Q-
----*******Q----

問題について

エイト・クイーン・パズルの変形版です。問題文にある通り、他のクイーンが一手で移動できるマスを避け、盤面上にクイーンを置いていきます。

 ----*******-----
 ----*******-----
 ----******------
 -----****-------
 -----***--------
 ------*---------
 -----------*****
 ----------******
 ----------******
 -----------*****
 ------*---------
 -----***--------
 -----****-------
 ----******------
 ----*******-----
 ----*******-----

まず素朴にこのパズルを解く方法を考えてみましょう。
以下では、縦のラインを「列」、横のラインを「行」と呼ぶことにします。
左からi列目、上からj行目のマスを(i,j)と書きます。i,jは0から数えます。

各行に対し、左から右、上の行から下の行へクイーンを置いていくとしましょう。
最初に(0,0)に置いた場合、このクイーンの経路には他のクイーンは置けませんから、次にクイーンを置けるマスは(12,0)、さらにその次に置けるのは(2,0)となります。
最初に(1,0)に置いた場合は、次にクイーンを置けるマスは(12,0)、さらにその次に置けるのは(3,0)となります。

-最初に(0,0)に置いた場合

Qxxx*******Qxxxx
xxQx*******-----

-最初に(1,0)に置いた場合

xQxx*******Qxxxx
xxxQ*******-----

このように、「(0,0)に置く? / 置かない?」「(0,1)に置く? / 置かない?」というそれぞれの選択肢が運命の分かれ道となり、それによってその後にクイーンを置けるマスが変わっていきます。左側の矢印を「置く」、右側の矢印を「置かない」として、次に置けるマスを図示しますと、以下のようになります。

問題は、これらの経路の内、「置く」を選んだ回数が最大のものを探すことです。

アルゴリズム

このようなグラフの探索問題を解くアルゴリズムにはいくつかバリエーションがありますが、ここでは「深さ優先探索」を使います。
他にも代表的なアルゴリズムとして「幅優先探索」がありますが、エイト・クイーンのような問題の場合、考慮すべき経路の量が多く、ふさわしくありません。
http://ja.wikipedia.org/wiki/深さ優先探索
http://ja.wikipedia.org/wiki/幅優先探索

深さ優先探索の実装は、スタックを利用するか再帰を利用するのが一般的です。
Rubyで再帰を利用した場合の探索部分を以下に示します。

def depthFirst x, y, h
    return h if (h[:map].size==y) #それ以上行がないので終了
    max = h
    x.upto(h[:map][y].size-1) do |x1|
    # y行目でx列目より右の、クイーンを置くことができるマスのそれぞれについて...
        next if h[:map][y][x1] != BRANK
        nmap = deepcopy(h[:map])
        setQueen(nmap, [x1,y])
        #クイーンを置いてみて、その後の運命を見定める
        r = depthFirst(x1+1, y, {:map=>nmap, :count=>h[:count]+1})
        #最大のものをとる
        if(max[:count] < r[:count])
            max = r
        end
    end
    #あえて置かないという選択肢も調べる
    r = depthFirst(0, y+1, h)
    if(max[:count] < r[:count])
        max = r
    end
    max
end

日本語で書くと以下のようになります。

  • y行目でx列目より右で、クイーンを置くことができるマスのそれぞれについて、
    • とりあえずクイーンを置いてみて、その右のマスに対し同じ操作を繰返す
    • それぞれの結果の内最大のものを取る
  • 行の右端まで行ったら下の行へ行く
  • それ以上行がなくなったら終了

あとはデータ構造です。
単純に考えれば盤面は二重配列にするのがよいでしょう。最適化を考え、ビットの配列にしてもよいですが、「何もない場合」「障害物」「クイーン」「クイーンの経路」といった状態が考えられるため、ビットの配列を複数持つ必要があります。
また、クイーンの数を比較するため、クイーンの合計数を盤面とは別に持つのもよいでしょう。

最適化

さて、以上を実装して解答が出れば話は簡単なのですが、この問題の場合、計算量の多さがネックになります。
素朴に解こうとすると一時間では計算が終わらないということにもなりかねません。
そこで、いくつか最適化の手段を考えていきましょう。

まず何度も繰り返すことになるクイーンの配置を最適化します。すべてのマスに対するクイーンの経路をあらかじめ計算してキャッシュ(メモ化)おきましょう。
あらかじめ計算しておけば、すべてのマス(障害物以外)を一度ずつ処理するだけで済みます。
経路の探索中は、同じマスに対し何度も何度もクイーンを配置する処理が必要になりますから、計算結果のキャッシュが有効にはたらくはずです。
さらに言えば、左から右、上から下に処理していくため、クイーンの経路は「右、右下、下、左下」の4つのみ考慮すれば済みます。左上や左にすでにクイーンがあった場合はそもそもそのマスにはクイーンを配置できません。

--x-*******-----
---xx****-------
xxxxQx*---------
---xxx-----*****
--x-x-x---******
左上、左、上にクイーンがないことはすでに確定しているため、考慮しなくていい。

また、以下のようなメモ化も考えられます。
パターン1とパターン2は違う盤面ですが、下から2つの行だけを見ると、同じ状態になっています。
ということは、下から2つの行を処理をする際にはどちらの場合でも同じ結果が出てくるはずです。つまり、「残りの行」の状態をキーにして結果をキャッシュして置くことで、いくつかの分岐を省略することができます。
とりわけ探索の後半は、ほとんどクイーンの経路で塗りつぶされた盤面を処理することになるはずですから、この処理が有効なはずです。
ただし、これによってメモリを食うことにもなるので、どの程度このキャッシュを働かせるかは微妙な選択でしょう。実際、言語によっては、このメモ化をしない場合の方が速くなることもありました。

---Q
Qxxx
xxQx
xxxx
x-xx
xxxx
パターン1
----
--Qx
Qxxx
xxxQ
x-xx
xxxx
パターン2

この探索の場合、網羅性を考えると、最適な配置のために「置ける場所にあえてクイーンを置かない」という選択肢も検討する必要があります。しかし、これによって探索する経路が大分増えてしまうのも事実です。
仮に「あえて置かない」選択肢を取らなかった場合の計算量が「n の m乗」(選択肢の数+深さ)だったとすると、「あえて置かない」選択肢を追加することで、概算で「(n+1) の m乗」にまで経路が増えてしまいます。
さらに言えば、「この行にはあえて置かない」という選択を10回繰り返したあとの経路などは、クイーンの数が最大になるとは考えづらいため、検討する必要がないものです。
よって、「あえて置かない」選択肢の回数を制限することにしましょう。この場合網羅性を犠牲にしているので、「クイーンの数が最大であること」を示さなければなりません。しかし「あえて置かない」選択肢の許容量を順次増やしていくことで最大の解を検討することもできるはずです。ところでその際、90度回転してから探索をはじめた方が都合がよくなります。これはこの盤面の特性によります。
障害物で分断された行(or列)のそれぞれを「ブロック」と呼ぶことにしましょう。縦のラインには、22ブロック(2つに分割された列が6、分割されていない列が10)あります。横のラインには、28ブロック(2つに分割された行が12、分割されていない行が4)あります。
縦または横のラインだけを見ていっても、1ブロックにクイーンを1つしか置けないのはあきらかです。つまり、縦のラインを見ていくと、この盤面におけるクイーンの最大値は22であることが明らかになります。縦のラインの方が最大値が低いため、横回転して縦のラインを基準に考えた方がよいのです。

実際には、この盤面の場合、「あえて置かない」選択肢の数は1回で十分であることがわかります。
計算を実行してみると、以上の最適化を組み合わせることで、Rubyでも10分程度、Haskellなどでは5分以下で解にたどりつくことができました。
解は以下のようになります。

20
-Q--*******Q----
---Q*******--Q--
----******-----Q
-----****Q------
-----***------Q-
------*-Q-------
----------Q*****
Q---------******
--Q-------******
----------Q*****
-----Q*Q--------
-----***-----Q--
----Q****------Q
----******--Q---
----*******---Q-
----*******Q----

この盤面が最大であることの証明は以下のようになります。
縦のラインに注目しましょう。クイーンが置かれていないブロックは(6,j)の列と、右から4列目、(11,j)の列だけです。ということは、もしクイーンを増やせるとしても、最大で2つにとどまります(1ブロックにクイーンを1つ以上置くことはできません)。

つまり余地が一つしかない以上、「2ブロック見逃す」という選択肢を考慮することで、置けるクイーンの数が増えることはありえません(理論上の最大値が22である以上、2つ見逃した時点で、20を超えることはないはずです)。
以上より、この解が最適解の1つであることがわかりました。

Ruby, Python, Haskellによるコードの例を以下に掲載します。
(Haskellは解答用言語に含まれていませんでしたが、おまけです)。

Continue reading »

Oct 08

お初にお目にかかります。
ひよこエンジニアtakei-hです。ぴよぴよ。
さて、amo-k先輩からの課題にやっと手を付けました!
さっそく本題です!

Continue reading »

Oct 05

はじめまして、nagai-kです。

今回は、携帯サイト開発のサポートツール「FireMobileSimulator」のご紹介とそれをちょっとハックしたよ、ということを書いてみたいと思います。

FireMobileSimulatorは、主要3キャリア(DoCoMo/Au/SoftBank)の携帯端末ブラウザをシミュレートして、モバイルサイト開発を容易にするために作成されたFirefoxのアドオンです。

私は携帯サイトを開発する事がよくありますので、このアドオンは業務をする上で必須のツールになっています。

携帯サイトの開発で大変なことといえば、最終出力であるHTMLの確認です。
プログラムを修正するたびに、ファイルをサーバにアップロードして携帯から確認する・・・・。
そんなことをするのは大変なので、普段は「FireMobileSimulator」を使って、Firefox で確認しています。
※もちろん最終的は確認は携帯端末の実機で行っていますよ^^

今回はこの「FireMobileSimulator」を勝手にハックしてみました。
さらに、作者の方に送ってみたら正式に採用されてしまいました!

追加した機能は、

  • 特定のURL(ドメイン)だけで端末選択機能が有効になる機能
  • 端末ごとにUIDなどの個体識別番号を設定する機能

です。内容について詳しくはオフィシャルサイト「1.1.9リリースノート」をご覧ください。

Continue reading »

Oct 01

本日は天下一(10/1)の日です。

天下一といえば7、8月にかけ 天下一プログラマーの予選・本戦をやりましたが、未だ全ての問題を公開していませんでした。

ということで遅くなりましたが今回出題した問題を全て公開します。

  1. WEB予選第1回(2009/7/5)
  2. WEB予選第2回(2009/7/15)
  3. WEB予選第3回(2009/7/25)
  4. 本戦(2009/8/1,2)

それぞれの問題の解説については準備が出来次第、更新するため今暫くお待ちください。

Oct 01
54階建てのビルに、22人乗りのエレベータが一機ある。
このエレベータは、人数に関係なく一回の乗降に10秒かかり、1階あたり1秒の速度で昇降する。

a 秒時点で b 階に c 階へ行きたい ddd さんが来るという情報を、

a, b, c, ddd

というcsv形式で与える。このデータは時刻aで昇順にソートされており、同時に二人の人物が来た場合は2行に分けられる。

これを元に、入力に出現した全員を目的の階に降ろすまでのエレベータの昇降と人物の乗降を、各人の所要時間
の合計が最小になるようにスケジューリングし、e 秒時点に f 階で ggg, hhh, iii さ
んが乗降するというデータを

e, f, ggg, hhh, iii

という形式で出力せよ。 e は乗降開始の時刻であり、同時に乗降する人物は一列にまとめよ。出力は e で昇順にソートせよ。同一人物は出力の中に二度出現し、一度目は乗車、二度目は降車を表す必要がある。

回答フォームには、規定された出力と、各人の所要時間の合計を入力せよ。

なお、各変数の定義域と値域は次の通りである.

  * 時点をあらわす a, e は、スケジュール開始時点を 0 とする非負の整数である.
    値域は、 [1, 1000000] の範囲である。(スケジュール開始と同時には人は来ない)
  * 階をあらわす b, c, fは、1階を1, 54階を54とする正の整数である. 値域は
    [1, 54] である。
  * 人物を表す ddd, ggg, hhh, iii は、asciiのアルファベット小文字3つで構成
    される三文字の文字列である。 aaa, aab, ... ,zzz の値をとる。

また、詳細な条件は以下の通りである。

  * 入力には、同一人物は一度しか出現しない。
  * 出力では、同一人物を必ず二回出現させる必要がある。目的の階に到着するとは
    目的の階で降車することであり、出発階以外の階からの乗車や目的階以外の階への
    降車は認めない。
  * スケジューリング開始時点 (時刻 0[sec]) に、エレベータは1階で、すぐに移動可能
    な状態で待機している。 (たとえば、時刻 3[sec] に 3階 で乗降を開始することが出来る)
  * 乗降は、乗降終了時点 (=移動開始時点) まで可能である。

    たとえば、20[sec] 時点に 10階に出現する abc が、 10[sec] 時点に
    10 階で乗降を開始したエレベータに乗車し、30[sec] 時点で 20 階で
    降車することが可能である。この場合、abcの所要時間とは、降車時点の30
    から出現時点の20[sec]を引いた10[sec]になる。

データ: schedule.csv 

1, 16, 1, aaa
20, 20, 10, aab
75, 1, 6, aac
101, 15, 1, aad
127, 13, 1, aae
156, 13, 1, aaf
185, 4, 1, aag
213, 17, 10, aah
226, 1, 7, aai
286, 1, 5, aaj
302, 16, 10, aak
373, 8, 18, aal
432, 13, 1, aam
498, 12, 10, aan
573, 13, 1, aao

解説はこちらとなります。

Oct 01
以下に定義された言語GNの実行環境を作成し、以下のコードの出力を答えよ。
コード: sample.gn
GNのソースコードは単一の自然数である。
自然数を素因数分解することで指数の列が得られる。これがGNの実行時コードであり、命令および引数の列として解釈される。

たとえば、140は以下のように素因数分解され、下のLのような指数列(実行時コード)が得られる(以下aのb乗を a^b と表記する)。
22 × 30 × 51 × 71
L = [2, 0, 1, 1]

GN処理系は実行時コードの他にメモリとポインタを持つ。メモリは0で初期化された配列である。ポインタは配列の1つの位置を指す。
配列のサイズに制限はない。
ポインタは初期状態では配列の先頭を指し、初期状態では配列の要素はすべて0である。
また、処理系はプログラムカウンタを持ち、実行時コードを順次読み取って実行していく。
GNには以下の命令がある。
1, 2, 3, 4は引数を取り、実行時コードにおける命令の次の数が引数と見なされる。

1: ポインタをn進める
2: ポインタをn戻す
3: ポインタが指す値に n 加算する
4: ポインタが指す値から n 減算する
5: ポインタが指す値をアスキーコードとして出力する
6: ポインタが指す値が0なら対応する7の直後までプログラムカウンタをジャンプする
7: ポインタが指す値が0でないなら対応する6までプログラムカウンタジャンプする

注:
-ポインタは初期地点より前には移動しない。
-ポインタが指す値は0以下にならない。
-引数以外の位置にある0は無視される。
-6および7は入れ子になることがある。たとえば[6, 1, 1, 6, 2, 2, 7, 1, 2, 7] は2重ループと見なされる。最初の6を読み取った際、ポインタが指す値が0ならば、[1, 2, 7]の直後までプログラムカウンタを進める。一方、2つ目の6を読み取った際、ポインタが指す値が0ならば、[2, 2, 7]の直後までプログラムカウンタを進める。

例: : gn.txt 
以下の自然数はGN上で実行すると"Hello, world"と出力する。
(10進数で2549桁の単一の自然数である)。

2958106527037147932522799632893684637443193969398590127391830758248732725171494768562797967767791353683984427
18417530573877274081779430311745932689954120650305923259595867797790830861414486245570197481943009141937393478519254592623804
60776409945241666135623515576457155760725038527507713373195753840321861085031489701564491750744098878985806591816523081908294
61283105527716558509971171005858411245808421769992246863114351254431335737223878383791011620893422481505646222666688253017465
57802716259139633848866741528740719414914728858637969588791966689851317063150884185898981960460675295937735497349287973702957
38620574941857589823049829705846049461413969644779874433999329064371847480353568185103295523592054828279601510522112950624511
84595936474900730437224772695520567438056979131690276862280608024105855730894533729219856785845215550245697436767104075456221
81498088386167225544770290201359679919065682293247595708926680895742113997918052225689520959952562522489027195263944251298935
18226411894600368673452988892889242744668250530926131889228788353279891196002953863955036988620551780208216820904096713956573
11787584626222645802734068774871855690123741533898666352151559757643205001049057050452790789700919148880305662491890796783445
56881682765949453424229590336098515172543904288108103237904757179714193677589032225540163775143775195191697235338607548787578
38609665665451910531236989859315547896023826570664551604385678906166598725895539784981711730494441169160256011603297319575708
03475380231503771671324112842032176089902223607357360446669794097958394002228305251661924188244948685091993871616027726151260
93725457017922790196670773561594574106588867246715198548570684119344631762247386048909463390838468264616513375339015154144366
37401501770107202075869618193853996294474182147934132492506951195055315858141503877465911044521931727076612267111611092259163
43023548069059880484911832762839120688365473963014977648452152737797917653276358529255902736894343871854272216226959652772794
27775521306040911872171851035663187888059868529870606313778126063559058600073876724536181539541709228914525108195864442580453
66147848520158737104588535487342991983517189086079652855792142819089521183481046000133327452610029862345142900147219564761990
58988934466328196341675351313211247983750860548134170636123186528053423211684906781420107343182818289592512789947557613546855
41039542627630216183485152228986444577683303886169445507956368365573042442042440205283976192126925913420446498648255688324533
46114451256340883492092941868462221894307267118598466547706749550

素因数分解すると以下の実行時コードが得られる。

[1, 2, 2, 1, 3, 72, 6, 2, 1, 3, 1, 1, 1, 4, 1, 7, 2, 1, 5, 1, 3, 2, 2, 3, 2,
 9, 6, 2, 1, 3, 1, 1, 1, 4, 1, 7, 2, 1, 5, 1, 4, 2, 3, 3, 7, 6, 2, 1, 3, 1, 1, 1,
 4, 1, 7, 2, 1, 5, 1, 5, 2, 4, 3, 0, 6, 2, 1, 3, 1, 1, 1, 4, 1, 7, 2, 1, 5, 1, 6,
 2, 5, 3, 3, 6, 2, 1, 3, 1, 1, 1, 4, 1, 7,
 2, 1, 5, 1, 7, 2, 6, 3, 67, 6, 2, 1,
 4, 1, 1, 1, 4, 1, 7, 2, 1, 5, 1, 8, 2, 7, 3, 12, 6,
 2, 1, 4, 1, 1, 1, 4, 1, 7,
 2, 1, 5, 1, 9, 2, 8, 3, 87, 6, 2, 1, 3, 1, 1, 1, 4, 1, 7, 2, 1, 5, 1, 10, 2, 9,
 3, 8, 6, 2, 1, 4, 1, 1, 1, 4, 1, 7, 2, 1, 5, 1, 11, 2, 10, 3, 3, 6, 2, 1, 3, 1,
 1, 1, 4, 1, 7, 2, 1, 5, 1, 12, 2, 11, 3, 6, 6, 2, 1, 4, 1, 1, 1, 4, 1, 7, 2, 1,
 5, 1, 13, 2, 12, 3, 8, 6, 2, 1, 4, 1, 1, 1, 4, 1, 7, 2, 1, 5, 1, 14]
Oct 01
ナンクロとは、ナンバークロスワードの略称で、ヒントとなるカギ(補足説明)のないクロスワードパズルです。
文字の並びから単語を推理し、マスに文字を埋め、解いていくパズルになります。

通常のクロスワードとは異なり、すべてのマスに番号がついています。
同じ番号には同じ文字が入るので、他のマスでも単語の一部として使えるようにマスに文字を埋めなくてはなりません。
なお、1つの番号に2つの文字が当てはまったり、逆に2つの番号に同じ文字が当てはまることはありません。
また、同じ単語が2度出てくることもありません。

このルールを踏まえ、下記のナンクロ問題を解くプログラムを作成し、ナンクロを解いてください。
なお、この問題を解く際には、下記に指定された辞書ファイルを使用してください。

 numbercross.PNG 

english.dic

解説はこちらとなります。

Oct 01
8x8のチェス盤でクイーンは以下のように移動が可能である。

  x-x-x---
  -xxx----
  xxQxxxxx
  -xxx----
  x-x-x---
  --x--x--  -:移動不可
  --x---x-  x:移動可能
  --x----x  Q:クイーン

※: Qの配置されたマスから縦・横・斜めのすべての方向に何マスでも移動が可能

エイト・クイーン問題とは8x8のチェス盤に対しどのクイーンも他のクイーンに一手で移動できないような配置する問題である。

例:
  ----Q---
  ------Q-
  Q-------
  --Q-----
  -------Q
  -----Q--
  ---Q----  -:空いているマス
  -Q------  Q:クイーン

ここでチェス盤の一部のマスに障害物があるとする。
この障害物に対してクイーンを配置することはできず、またクイーンの移動上で衝突する場合はその先にも配置することはできないとする。

例
  x-x-x---
  -xxx*---
  xxQx****
  -xxx*---
  x-x-*---  -:移動不可
  --x**---  x:移動可能
  --**----  * :障害物
  --*-----  Q:クイーン

この時以下のように16x16のチェス盤に障害物があるとき最大で何個のクイーンを配置可能か求めなさい。
 queen.txt 

 ----*******-----
 ----*******-----
 ----******------
 -----****-------
 -----***--------
 ------*---------
 -----------*****
 ----------******
 ----------******
 -----------*****
 ------*---------
 -----***--------
 -----****-------
 ----******------
 ----*******-----
 ----*******-----

またその時のチェス盤の様子を一つ
「-:空いているマス」
「Q:クイーン」
「*:障害物」
(※「-」「Q」「*」は一つのマス)
を使用し16x16のアスキーアートとして示しなさい。