見出し画像

ほぼノーコーディングで将棋棋士の出身地マップのWebアプリを作ってみる

随分前になりますが、とある人から「将棋棋士の出身地マップ」的なものを作って欲しいと言われまして暫く放置していたのですが、ChatGPTが出現したこともあり、「じゃあ、できるだけノーコディングでどこまでできるかやってみよう」というモチベーションになり、やってみることとしました。

1. Webアプリ全自動爆速作成を使ってみる

@hedachiさんが個人的に開発されたGPTapp(Webアプリ全自動爆速作成)がたまたま目に入ったので興味本位で使ってみることとしました。「全自動爆速作成」・・なんと素敵な響きなのでしょう。

2. プロンプトどうする?

期待するアウトプットイメージはグーグルマップにピンがいっぱい立っていて、ピンをクリックすると「棋士番号や、棋士名」が表示される感じです。で、以下のように随分と雑なプロンプトでどうなるか試してみました。

将棋棋士の出身地を日本の地図で確認できるアプリを作ってください。
仕様は以下の通りです。
日本地図上に各棋士の出身地の位置にピンを立て棋士番号を表示してください。
ピンをタップするとポップアップして棋士番号と棋士名を表示してください。
ポップアップ表示はもう1回タップすると消せるようにしてください。

3. こうなった

指示後、1分未満程度だったと思いますが、以下のコードが返ってきました。棋士番号と棋士名、出身地は実際と全然違いますが、それっぽいのが返ってきました。まあここは他の手段でなんとかしましょう。
ちなみにこのままでは惜しくもマップ表示されませんでした。

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>将棋棋士の出身地マップ</title>
	<style>
		#map {
			height: 80%;
			width: 80%;
			margin: 0 auto;
		}
	</style>
</head>
<body>
	<h1>将棋棋士の出身地マップ</h1>
	<div id="map"></div>
	
	<script>
		// 将棋棋士のデータ(出身地、棋士名、棋士番号)
		const shogiPlayers = [
			{ location: { lat: 35.6828, lng: 139.759 }, name: "羽生善治", number: 1 },
			{ location: { lat: 35.6951, lng: 139.757 }, name: "藤井聡太", number: 2 },
			{ location: { lat: 43.0642, lng: 141.3469 }, name: "佐藤康光", number: 3 },
			{ location: { lat: 35.6938, lng: 139.7032 }, name: "加藤一二三", number: 4 },
			{ location: { lat: 36.325, lng: 139.536 }, name: "渡辺明", number: 5 }
		];
		
		// 地図を表示するための関数
		function initMap() {
			const center = { lat: 38, lng: 138 }; // 地図の中心を設定
			const map = new google.maps.Map(document.getElementById("map"), {
				zoom: 5, // 地図のズームレベルを5に設定
				center: center
			});
			
			// 将棋棋士のマーカーを配置する
			for (let i = 0; i < shogiPlayers.length; i++) {
				const marker = new google.maps.Marker({
					position: shogiPlayers[i].location,
					map: map,
					title: shogiPlayers[i].name,
					label: {
						text: String(shogiPlayers[i].number),
						color: "white"
					}
				});
				
				// マーカーをクリックしたときにポップアップを表示する
				marker.addListener("click", function() {
					// 現在表示している全ての情報ウィンドウを閉じる
					for (let j = 0; j < infoWindows.length; j++) {
						infoWindows[j].close();
					}
					infoWindows = [];
					
					const infoWindow = new google.maps.InfoWindow({
						content: `<div><p>棋士番号: ${shogiPlayers[i].number}</p><p>名前: ${shogiPlayers[i].name}</p></div>`
					});
					
					infoWindow.open(map, marker);
					
					// 情報ウィンドウが閉じられたときにinfoWindows配列から削除する
					infoWindow.addListener("closeclick", function() {
						const index = infoWindows.indexOf(infoWindow);
						infoWindows.splice(index, 1);
					});
					
					infoWindows.push(infoWindow);
				});
			}
		}
		
		let infoWindows = []; // 全ての情報ウィンドウを格納する配列
		
		// Google Maps JavaScript APIを読み込む(APIキーは適宜書き換えること)
		const script = document.createElement("script");
		script.src = `https://maps.googleapis.com/maps/api/js?key=APIキー&callback=initMap`;
		script.defer = true;
		script.async = true;
		
		// HTMLの<head>要素の最後にスクリプトを追加する
		document.head.appendChild(script);
	</script>
</body>
</html>

それで、<style>のところを以下のように手修正しました。これだけでマップ表示するようになりました。

	<style>
    	html, body { height: 80%; margin: 0; padding: 0; }
    	#map { width:80%; height:500px; margin: 0 auto; }
	</style>

生成したhtmlをブラウザで表示するとこんな感じです。凄いですね、たった数行のプロンプトでここまで・・
しかしなぜに佐藤康光九段が北海道なんでしょう。まあ今はいいでしょう。

GPTappでほぼ生成したマップ

4. 緯度経度情報を入力するなんて嫌なので・・ChatGPTさんにご登場してもらう

コードを見ていただくと分かりますが大嘘出身地情報が緯度経度入力形式になっているのですね。これでは後々大変です。日本将棋棋士連盟のデータベースでは例えば「神奈川県小田原市」と記載しています。従って住所形式でここは入力する形としたいです。

		// 将棋棋士のデータ(出身地、棋士名、棋士番号)
		const shogiPlayers = [
			{ location: { lat: 35.6828, lng: 139.759 }, name: "羽生善治", number: 1 },
			{ location: { lat: 35.6951, lng: 139.757 }, name: "藤井聡太", number: 2 },
			{ location: { lat: 43.0642, lng: 141.3469 }, name: "佐藤康光", number: 3 },
			{ location: { lat: 35.6938, lng: 139.7032 }, name: "加藤一二三", number: 4 },
			{ location: { lat: 36.325, lng: 139.536 }, name: "渡辺明", number: 5 }
		];

そこで今度はChatGPTを使って先のコードを修正してもらうようにしてみました。プロンプトはこんな感じです。

以下のhtmlコードは、緯度経度情報からグーグルマップにピンを立てる仕様になっていますが、
住所情報からグーグルマップにピンを立てる仕様に変更し、
function initMap()の部分のみ表示してください。

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>将棋棋士の出身地マップ</title>
	<style>
    	html, body { height: 80%; margin: 0; padding: 0; }
    	#map { width:80%; height:500px; margin: 0 auto; }
	</style>
</head>
<body>
	<h1>将棋棋士の出身地マップ</h1>
	<div id="map"></div>
	
	<script>
		// 将棋棋士のデータ(出身地、棋士名、棋士番号)
		const shogiPlayers = [
			{ location: { lat: 35.6828, lng: 139.759 }, name: "羽生善治", number: 1 },
			{ location: { lat: 35.6951, lng: 139.757 }, name: "藤井聡太", number: 2 },
			{ location: { lat: 43.0642, lng: 141.3469 }, name: "佐藤康光", number: 3 },
			{ location: { lat: 35.6938, lng: 139.7032 }, name: "加藤一二三", number: 4 },
			{ location: { lat: 36.325, lng: 139.536 }, name: "渡辺明", number: 5 }
		];
		
		// 地図を表示するための関数
		function initMap() {
			const center = { lat: 38, lng: 138 }; // 地図の中心を設定
			const map = new google.maps.Map(document.getElementById("map"), {
				zoom: 5, // 地図のズームレベルを5に設定
				center: center
			});
			
			// 将棋棋士のマーカーを配置する
			for (let i = 0; i < shogiPlayers.length; i++) {
				const marker = new google.maps.Marker({
					position: shogiPlayers[i].location,
					map: map,
					title: shogiPlayers[i].name,
					label: {
						text: String(shogiPlayers[i].number),
						color: "white"
					}
				});
				
				// マーカーをクリックしたときにポップアップを表示する
				marker.addListener("click", function() {
					// 現在表示している全ての情報ウィンドウを閉じる
					for (let j = 0; j < infoWindows.length; j++) {
						infoWindows[j].close();
					}
					infoWindows = [];
					
					const infoWindow = new google.maps.InfoWindow({
						content: `<div><p>棋士番号: ${shogiPlayers[i].number}</p><p>名前: ${shogiPlayers[i].name}</p></div>`
					});
					
					infoWindow.open(map, marker);
					
					// 情報ウィンドウが閉じられたときにinfoWindows配列から削除する
					infoWindow.addListener("closeclick", function() {
						const index = infoWindows.indexOf(infoWindow);
						infoWindows.splice(index, 1);
					});
					
					infoWindows.push(infoWindow);
				});
			}
		}
		
		let infoWindows = []; // 全ての情報ウィンドウを格納する配列
		
		// Google Maps JavaScript APIを読み込む(APIキーは適宜書き換えること)
		const script = document.createElement("script");
		script.src = `https://maps.googleapis.com/maps/api/js?key=**&callback=initMap`;
		script.defer = true;
		script.async = true;
		
		// HTMLの<head>要素の最後にスクリプトを追加する
		document.head.appendChild(script);
	</script>
</body>
</html>

5. こうなった

こちらも1分弱程度で以下の通り返ってきました。素晴らしい。
ちなみになぜわざわざコードの一部だけ返すように指示をしたかと言うと、逆に全返し指示をするとコードが長くなって途中でChatGPTが出力を打ち切ってしまうからです。

以下は住所情報からグーグルマップにピンを立てる仕様に変更し、
function initMap()の部分のみ表示したものです。

function initMap() {
  const center = { lat: 38, lng: 138 }; // 地図の中心を設定
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 5, // 地図のズームレベルを5に設定
    center: center
  });
  
  // 住所から位置情報を取得するためのGeocoderオブジェクトを作成する
  const geocoder = new google.maps.Geocoder();
  
  // 将棋棋士のマーカーを配置する
  for (let i = 0; i < shogiPlayers.length; i++) {
    // 住所から位置情報を取得する
    geocoder.geocode({ address: shogiPlayers[i].address }, function(results, status) {
      if (status === "OK") {
        const marker = new google.maps.Marker({
          position: results[0].geometry.location,
          map: map,
          title: shogiPlayers[i].name,
          label: {
            text: String(shogiPlayers[i].number),
            color: "white"
          }
        });
        
        // マーカーをクリックしたときにポップアップを表示する
        marker.addListener("click", function() {
          // 現在表示している全ての情報ウィンドウを閉じる
          for (let j = 0; j < infoWindows.length; j++) {
            infoWindows[j].close();
          }
          infoWindows = [];
          
          const infoWindow = new google.maps.InfoWindow({
            content: `<div><p>棋士番号: ${shogiPlayers[i].number}</p><p>名前: ${shogiPlayers[i].name}</p></div>`
          });
          
          infoWindow.open(map, marker);
          
          // 情報ウィンドウが閉じられたときにinfoWindows配列から削除する
          infoWindow.addListener("closeclick", function() {
            const index = infoWindows.indexOf(infoWindow);
            infoWindows.splice(index, 1);
          });
          
          infoWindows.push(infoWindow);
        });
      } else {
        alert(`Geocode 失敗: ${status}`);
      }
    });
  }
}

GPTappのfunction initMap()コードを上記コードに入れ替えて最終的には以下のようになりました。なお当たり前ですがAPIKeyはセキュリティの関連でマスクしています。住所はGPTappでてきとうに出した緯度経度情報を忠実に地名変換している模様。

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>将棋棋士の出身地マップ</title>
	<style>
    	html, body { height: 80%; margin: 0; padding: 0; }
    	#map { width:80%; height:500px; margin: 0 auto; }
	</style>
</head>
<body>
	<h1>将棋棋士の出身地マップ</h1>
	<div id="map"></div>
	
	<script>
		// 将棋棋士のデータ(出身地、棋士名、棋士番号)
		const shogiPlayers = [
			{ address: "東京都千代田区永田町1-7-1", name: "羽生善治", number: 1 },
			{ address: "東京都千代田区霞が関3-2-2", name: "藤井聡太", number: 2 },
			{ address: "北海道札幌市中央区北1条西3丁目", name: "佐藤康光", number: 3 },
			{ address: "東京都中野区本町3-12-7", name: "加藤一二三", number: 4 },
			{ address: "群馬県太田市旭町4-6-2", name: "渡辺明", number: 5 }
		];
		
		// 地図を表示するための関数
		function initMap() {
			const center = { lat: 38, lng: 138 }; // 地図の中心を設定
			const map = new google.maps.Map(document.getElementById("map"), {
    		zoom: 5, // 地図のズームレベルを5に設定
    		center: center
  			});
  
  		// 住所から位置情報を取得するためのGeocoderオブジェクトを作成する
  			const geocoder = new google.maps.Geocoder();
  
  		// 将棋棋士のマーカーを配置する
  			for (let i = 0; i < shogiPlayers.length; i++) {
    	// 住所から位置情報を取得する
    			geocoder.geocode({ address: shogiPlayers[i].address }, function(results, status) {
      				if (status === "OK") {
        				const marker = new google.maps.Marker({
          					position: results[0].geometry.location,
          					map: map,
          					title: shogiPlayers[i].name,
          					label: {
            					text: String(shogiPlayers[i].number),
            					color: "white"
          					}
        				});
        // マーカーをクリックしたときにポップアップを表示する
        				marker.addListener("click", function() {
        // 現在表示している全ての情報ウィンドウを閉じる
          					for (let j = 0; j < infoWindows.length; j++) {
            					infoWindows[j].close();
          					}
          					infoWindows = [];
          
          					const infoWindow = new google.maps.InfoWindow({
            					content: `<div><p>棋士番号: ${shogiPlayers[i].number}</p><p>名前: ${shogiPlayers[i].name}</p></div>`
          				});
          
          				infoWindow.open(map, marker);
          
          // 情報ウィンドウが閉じられたときにinfoWindows配列から削除する
          				infoWindow.addListener("closeclick", function() {
            				const index = infoWindows.indexOf(infoWindow);
            				infoWindows.splice(index, 1);
          				});
          
          				infoWindows.push(infoWindow);
        			});
      				} else {
        				alert(`Geocode 失敗: ${status}`);
      				}
    			});
  			}
		}
		
		let infoWindows = []; // 全ての情報ウィンドウを格納する配列
		
		// Google Maps JavaScript APIを読み込む(APIキーは適宜書き換えること)
		const script = document.createElement("script");
		script.src = `https://maps.googleapis.com/maps/api/js?key=**&callback=initMap`;
		script.defer = true;
		script.async = true;
		
		// HTMLの<head>要素の最後にスクリプトを追加する
		document.head.appendChild(script);
	</script>
</body>
</html>

生成したhtmlをブラウザで表示するとこんな感じです。というか位置情報入力形式を住所に変えただけなのでGPTappで生成した結果と同じです。

出力されたマップ(当然だがGPTappと同じ結果)

6. まとめ

少なくともGoogle Maps JavaScript APIプログラミングをほぼ知らずともそれっぽいアウトプットを半日以下で出せることが分かりました。凄くないですか。
あとは棋士情報を正確に取得して反映するだけですね。別途報告できたらします。
ありがとうございました。


この記事が気に入ったらサポートをしてみませんか?