まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

普段のエディタは Vi(m) か ATOM(+vi プラグイン)を気に入って使ってます。軽量で使いやすく、vi の慣れたキーバインドで使えるという点にメリットを感じています。 が、最近になって Visual Studio Code(以下 VSCode)を vi キーバインドで使うという選択肢も気になっています。特に後述する Visual Code Live Share(以下 VSCode LiveShare)は、今日のようなオンライン中心のイベントや勉強会で使える共同開発ツールとしてポテンシャルを感じています。そんなわけで、このブログでも VSCode LiveShare を使ったモブプログラミング(共同開発作業)を紹介しようと思いました。まず今回は環境準備の説明です。


【前提条件】
Windows 7 以上、64 bit Linux、 または macOS 10.13 以上 を使っている必要があります。VSCode 自体は Raspberry Pi などの他環境向けにも提供されていますが、後述する VSCode LiveShare プラグインは動作環境が限られているようで、現時点(2020/04/20)では Windows, Linux または macOS を使う必要があるようです。


【VSCode のインストール】
VSCode の公式サイトから VSCode をダウンロードして(普通に)インストールしてください。なお、VSCode LiveShare を使う場合はバージョン 1.22 以上が必要です。


【VSCode LiveShare プラグインのインストール】
VSCode LiveShare は VSCode を使ったコーディングの共同作業を行うツールです。それを実現するための拡張機能が VSCode LiveShare プラグインです。このプラグインは共同作業におけるホスト役の人(自分のコードを他の人に編集させる人)だけでなく、ゲスト役の人(他の人のコードを編集する人)の環境にも両方にインストールが必要です。

インターネットに接続された状態で VSCode を起動し、画面左のメニューから Extension タブを選び、検索フィールドに Live Share と入力して検索します。その名の通りの Live Share プラグインが見つかるのでこれをインストールします:
2020042001


プラグインのインストールの最後にリロードを促されるのでリロードします。この後バックグラウンドで依存ライブラリのインストールが始まり、完了まで少し待ちます。

プラグインのインストールが完了すると画面左下が以下のようになり、Live Share が利用可能になっていることがわかるようになります:
2020042002


なお、VSCode に(日本語化パックや VIM など)他のプラグインを使う場合はこのタイミングで必要なものを導入しておいてください。


【ログイン】
VSCode LiveShare で共同作業する際、「誰が」コードを編集しているのかがわかりやすいようにログインする必要があります。VSCode LiveShare の場合、Microsoft アカウントまたは GitHub アカウントで OAuth 認証を行う必要があります。以下は GitHub アカウントを使ってログインする例を紹介します。

上述画面の Live Share と白抜きで表示されている部分をクリックしてログインします。下図のような表示になるのでログインに利用するアカウントを選んで進めます(以下は "Sign in with GitHub" を選んだものとして説明を続けます):
2020042003


選択したアカウントの OAuth 認証の画面が表示されます。内容を確認して、許可(Authorize)するボタンをクリックします:
2020042004


プログラムを起動するダイアログが表示されたら、"Visual Studio Code" が洗濯されていることを確認して「リンクを開く」をクリックします:
2020042005


再び VSCode の画面に戻ります。この時点で画面左下にログインしたアカウントのユーザー名が表示され、VSCode LiveShare を利用するための準備も完了しています:
2020042006


これで VSCode LiveShare を使う準備ができました。次回はこの続きで実際に VSCode LiveShare を使う様子を紹介する予定です。


(2020/04/23 追記 続きはこちら)
http://dotnsf.blog.jp/archives/1077356596.html


突然ですが、以下の間違った式からマッチ棒を一本だけ動かして正しい式にしてください。なお ≠ (not equal)記号は使えないものとします:



正解は下にスクロールして確認してください:

 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓

模範解答はこちらです:



いかがですか? 意外と難しかったでしょうか? 「一本だけ」動かして成立させる、というルールが絶妙で、また色々なマッチ棒の使い方や可能性があったりして、時間制限によっては僕も解けなかったりします。結構盛り上がる遊びです。 ちなみに BSフジで放送中の「クイズ!脳ベル SHOW」の中のミニクイズの1つでもあったりします。

で、今回のブログエントリで紹介するのは、このマッチ棒クイズを自動的に解くプログラムです。デモサイトはこちらです(スマホで見る場合は画面を横長にしてください):
https://dotnsf.github.io/matchbo/

2020041200


赤字で「問題」と書かれたフィールドに初期状態の(問題文となる正しくない)式を入力します(掛け算は * 、割り算は /)。するとそのすぐ下に入力式がマッチ棒に変換されて表示されます:
2020041201


これが出題です。この 4+3=5+9 は解くのにトリッキーなワザが必要な出題例ですが、答はわかりますか? 答がわかったか、或いはギブアップする場合は次に進んでください。

ここで入力した問題の答をコンピュータに解かせることで答の一例を確認できます。コンピュータに解かせるには、問題フィールドが入力状態になっている時に Enter を押します(要は Submit します)。するとクイズの答となりえるものを探して下部に表示してくれます。

 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓
 ↓

2020041203

※わかりますか? 4から一本動かして 11 にして式を成立させています。こういう所に気づかないといけなかったりして、意外と奥の深いクイズだったりします。

なお、問題や解答として識別可能な文字はクイズ!脳ベル SHOW のルールに従って以下の通りとします(記号も掛け算割り算以外は変更が加わる可能性があることに注意が必要です):
2020041202


上記以外の文字表記は使えないものとします。また掛け算・割り算は足し算・引き算よりも優先されます。また最終的に成立していればですが、イコール記号は2つ以上使っても構いません、という番組ルールにのっとって判断されます。

また解がない(一本動かしただけでは成立しない)とコンピュータが判断した場合はその旨のメッセージが表示されます。本当は解が存在しているのにこのメッセージが出た場合は僕の作ったアルゴリズムが未熟なせい、ということにしてください:
2020041204



クイズとしても面白いのですが、解いていくうちに、自分の頭の中よりも効率的な解法アルゴリズムを思いついて、試しに実装してみたらなかなかの出来だったので公開します。なおソースコードも公開するので、興味ある方は中身も御覧ください。僕の独自アルゴリズムなので、もっと効率的な方法が存在している可能性大ですけど:
https://github.com/dotnsf/matchbo



オープンな地図データである OSM(OpenStreetMap) と、オープンな地図操作 JavaScript ライブラリである Leaflet.js を使うことで、ライセンスフリーな地図アプリを作ることができます。このブログでも過去に何度か扱ったことがあります:
http://dotnsf.blog.jp/tag/leaflet

例えば、単に地図を全画面表示するのであればこんな感じのコードを書くと実現できちゃいます:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3c.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta charset="utf8"/>
<meta http-equiv="pragma" content="no-cache"/>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.2.0/leaflet.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.2.0/leaflet.js"></script>

<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
<meta name="apple-mobile-web-app-title" content="OSM Sample"/>

<title>OSM Sample</title>
<script>
</script>
<script>
//. 初期中心位置
var lat = 35.681377778;
var lng = 139.76736389;

//. 初期ズームレベル
var zoomlevel = 9;

var map = null;

$(function(){
  //. 初期位置を中心とした地図を OpenStreetMap データで表示
  map = L.map('demoMap', {}).setView( [ lat, lng ], zoomlevel );
  L.tileLayer(
    'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: 'Map data © <a href="//openstreetmap.org/">OpenStreetMap</a>',
    }
  ).addTo( map );
});
</script>
<style>
html, body {
  width: 100%;
  height: 100%;
  padding: 0px;
  margin: 0px;
}
#demoMap{
  position: fixed;
  width: 100%;
  height: 100%;
}
</style>
</head>
<body>
  <div>
    <div id="demoMap"></div>
  </div>
</body>
</html>

(東京あたりを中心に、ズームレベル9で地図を表示)
2020041501


さて、上図の左上にズームコントロールがあります(上記コードでは特に指定していませんが、明示的に非表示にしない限り、デフォルトでズームコントロールが表示されます)。スマホであればピンチイン・アウトの操作でズームイン・アウトができるのですが、タッチスクリーンに対応していない PC のブラウザで地図を見ている場合は、このコントールを使ってズームイン・アウトを行うことになります。

ただ例えば画面上部に常に表示されるメッセージがある場合など、メッセージとズームコントロールが重なってしまい、操作しにくくなってしまうことがあります:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3c.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta charset="utf8"/>
<meta http-equiv="pragma" content="no-cache"/>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.2.0/leaflet.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.2.0/leaflet.js"></script>

<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
<meta name="apple-mobile-web-app-title" content="OSM Sample"/>

<title>OSM Sample</title>
<script>
</script>
<script>
//. 初期中心位置
var lat = 35.681377778;
var lng = 139.76736389;

//. 初期ズームレベル
var zoomlevel = 9;

var map = null;

$(function(){
  //. 初期位置を中心とした地図を OpenStreetMap データで表示
  map = L.map('demoMap', {}).setView( [ lat, lng ], zoomlevel );
  L.tileLayer(
    'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: 'Map data © <a href="//openstreetmap.org/">OpenStreetMap</a>',
    }
  ).addTo( map );
});
</script>
<style>
html, body {
  width: 100%;
  height: 100%;
  padding: 0px;
  margin: 0px;
}
#demoMap{
  position: fixed;
  width: 100%;
  height: 100%;
}
#message{
  position: absolute;
  top: 10px;
  font-size: 20px;
  color: red;
  font-weight: bold;
}
</style>
</head>
<body>
  <div>
    <div id="demoMap"></div>
    <div id="message">このメッセージが邪魔でズーム制御ができない?</div>
  </div>
</body>
</html>

(画面上のメッセージとズームコントロールが重なってしまう例)
2020041502


この状態をなんとか回避できないか、というのが今回のブログエントリのテーマです。メッセージ側の位置を変えるのは簡単ですが、当然意図があって画面上部にメッセージを表示しているわけですから、できればズームコントロールの位置を変えたい。一方、なまじデフォルトで表示されてしまっているズームコントロールだけにどうすると位置を変更できるのか、がわかりにくいのでした。

正解の一例を先にお見せすると、こんな感じになります:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3c.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta charset="utf8"/>
<meta http-equiv="pragma" content="no-cache"/>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.2.0/leaflet.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.2.0/leaflet.js"></script>

<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
<meta name="apple-mobile-web-app-title" content="OSM Sample"/>

<title>OSM Sample</title>
<script>
</script>
<script>
//. 初期中心位置
var lat = 35.681377778;
var lng = 139.76736389;

//. 初期ズームレベル
var zoomlevel = 9;

var map = null;

$(function(){
  //. 初期位置を中心とした地図を OpenStreetMap データで表示
  map = L.map('demoMap', { dragging: true, zoomControl: false }).setView( [ lat, lng ], zoomlevel );
  L.control.zoom( { position: 'bottomright' } ).addTo( map );
  L.tileLayer(
    'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: 'Map data © <a href="//openstreetmap.org/">OpenStreetMap</a>',
    }
  ).addTo( map );
});
</script>
<style>
html, body {
  width: 100%;
  height: 100%;
  padding: 0px;
  margin: 0px;
}
#demoMap{
  position: fixed;
  width: 100%;
  height: 100%;
}
#message{
  position: absolute;
  top: 10px;
  font-size: 20px;
  color: red;
  font-weight: bold;
}
</style>
</head>
<body>
  <div>
    <div id="demoMap"></div>
    <div id="message">このメッセージがあってもズーム制御できる</div>
  </div>
</body>
</html>

青字部分が肝になります。初期化時(L.map() 実行時)のオプションで zoomControl: false をつけることでズームコントロールを(一旦)非表示にします。なおもう一つ指定しているオプション dragging: true は地図のスクロール(ドラッグ)ができるようにするオプションで、ここを false にするとスクロールできない地図になります。

このままだとズームコントロールは表示されないのですが、直後の1行でズームコントロールを再び表示しています。そしてこの行では position: 'bottomright' というオプションをつけることで「右下」にズームコントロールを表示させています(デフォルトは 'topleft'):

2020041503

↑こんな感じになって、メッセージと重ならない位置にズームコントロールを移動できました。


(参考)
https://www.wrld3d.com/wrld.js/latest/docs/leaflet/L.Control.zoom/



このページのトップヘ