<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>deji &#8211; デジタル未来 (Dejitaru Mirai)</title>
	<atom:link href="https://dejitarumirai.com/author/deji/feed" rel="self" type="application/rss+xml" />
	<link>https://dejitarumirai.com</link>
	<description></description>
	<lastBuildDate>Sun, 06 Jul 2025 08:36:13 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.2</generator>
	<item>
		<title>Tổng hợp mã code mới nhất cho Untitled Boxing Game trên Roblox</title>
		<link>https://dejitarumirai.com/archives/4145</link>
					<comments>https://dejitarumirai.com/archives/4145#respond</comments>
		
		<dc:creator><![CDATA[deji]]></dc:creator>
		<pubDate>Tue, 15 Jul 2025 00:26:00 +0000</pubDate>
				<category><![CDATA[ニュース]]></category>
		<category><![CDATA[biểu cảm]]></category>
		<category><![CDATA[featured]]></category>
		<category><![CDATA[mã code Roblox]]></category>
		<category><![CDATA[Roblox]]></category>
		<category><![CDATA[spin miễn phí]]></category>
		<category><![CDATA[tiền mặt]]></category>
		<category><![CDATA[trò chơi đối kháng]]></category>
		<category><![CDATA[Untitled Boxing Game codes]]></category>
		<guid isPermaLink="false">https://dejitarumirai.com/?p=4145</guid>

					<description><![CDATA[Cập nhật mã code Untitled Boxing Game vào ngày 16 tháng 6 năm 2025. Sử dụng các mã code để nhận spin miễn phí, tiền mặt và các biểu cảm.]]></description>
										<content:encoded><![CDATA[<p>更新情報: 2025年6月16日に新しいUntitled Boxing Gameコードを確認しました。</p>
<p>タイトルがないにもかかわらず、多くのRobloxプレイヤーがRobloxのUntitled Boxing Gameでボクシングのスキルを磨いています。目標は簡単です: もっと練習して強くなり、ボクシングリングで相手を倒すことです。その努力をサポートするために、以下に全てのUntitled Boxing Gameコードをまとめました。これらのコードは無料のスピン、キャッシュ、エモートを提供します。スピンとキャッシュを利用すれば、簡単に強くなり、敵を数発で倒すことができます。</p>
<h2>新しいUntitled Boxing Gameコード一覧</h2>
<ul>
<li><strong>ubgliveson</strong>: 14xラッキースピン (<strong><mark style="background-color:rgba(0, 0, 0, 0)">NEW</mark></strong>)</li>
<li><strong>disjoints</strong>: 5回の無料スピン </li>
<li><strong>whitecash</strong>: 14,999キャッシュ</li>
<li><strong>joeisreal</strong>: 10回の無料スピン </li>
<li><strong>vexthegoat</strong>: 15回の無料スピン </li>
<li><strong>bringus</strong>: 10回の無料スピン </li>
<li><strong>void</strong>: 2,999キャッシュ </li>
<li><strong>lovereturns</strong>: 2,999キャッシュ</li>
<li><strong>matchmaking</strong>: 5回の無料スピン</li>
<li><strong>newyear</strong>: 2,999キャッシュ</li>
<li><strong>greenscreen</strong>: 10回の無料スピン</li>
<li><strong>jolly2</strong>: 5回の無料スピン</li>
<li><strong>morefeints</strong>: 3回の無料スピン</li>
<li><strong>avatar</strong>: 4,999キャッシュ</li>
<li><strong>fastservers</strong>: 5回のスピン</li>
<li><strong>dualemotes</strong>: 無料エモート</li>
<li><strong>freeemoteforall</strong>: 無料エモート</li>
</ul>
<h3>期限切れのUntitled Boxing Gameコード</h3>
<ul>
<li>knockdownfits</li>
<li>powerlevel</li>
<li>asura</li>
<li>bigbigcode</li>
<li>coolchanges</li>
<li>supersecret</li>
<li>sale</li>
<li>shotgunrework</li>
<li>weball</li>
<li>jumpscare</li>
<li>ubgforever</li>
<li>oneyear</li>
<li>500mil</li>
<li>animetime</li>
<li>animecrates</li>
<li>bigcode</li>
<li>kocash</li>
<li>manyfixes</li>
<li>ipposreturn</li>
<li>settings</li>
<li>activateboost</li>
<li>brazil</li>
<li>freeemote2</li>
<li>cashcashcash</li>
<li>watwatwat</li>
<li>balrog</li>
<li>chronos</li>
<li>thegames</li>
<li>beowulf</li>
<li>koanims</li>
<li>morecash</li>
<li>randomcode</li>
<li>freeemote</li>
<li>valentines</li>
<li>vegeta</li>
<li>hammer</li>
<li>freeemote1</li>
<li>delayingsome</li>
<li>yamcha</li>
<li>styletitles</li>
<li>nice</li>
<li>charge</li>
<li>jolly</li>
<li>200mil</li>
<li>250k</li>
<li>emotes</li>
<li>freedom</li>
<li>freecrates</li>
<li>pocketchange</li>
<li>teleport</li>
<li>funnycode</li>
<li>shotgun</li>
<li>turtle</li>
<li>trading</li>
<li>moretrading</li>
<li>ironfist</li>
<li>balance1</li>
</ul>
<p>もしRobloxでの格闘ゲームのファンなら、新しくリリースされたMMA Legendsというゲームをチェックすることをお勧めします。また、過去にプレイしたAsuraやKenganのような人気のある格闘ゲームもあります。新しい体験を求めるなら、Robloxコードのマスターリストでたくさん見つけることができます。</p>
<h2>Untitled Boxing Gameコードの引き換え方法</h2>
<p>以下のステップに従って、Untitled Boxing Gameのコードを引き換えてください:</p>
<ul>
<li>Robloxプレーヤーで<a href="https://www.roblox.com/games/13621938427/MAPS-untitled-boxing-game" rel="noopener nofollow" target="_blank">Untitled Boxing Game</a>を開きます。</li>
<li>左のメニューで<strong>CODESボタン</strong>をクリックします。</li>
<li>次に、ポップアップテキストボックスに有効なコードを入力します。</li>
<li><strong>REDEEMボタン</strong>をクリックして、無料報酬を受け取ります。</li>
</ul>
<figure><img decoding="async" alt="Untitled Boxing Gameでのコード引き換えオプション" src="https://dejitarumirai.com/wp-content/uploads/2025/06/Redeem-codes-option-in-Untitled-Boxing-Game.jpg"/></figure>
<h2>Untitled Boxing Gameのコードをもっと手に入れる方法</h2>
<p>Untitled Boxing Gameの最新コードを手に入れる最良の方法は、このページをブックマークすることです。Discordサーバーに参加したり、開発者をXでフォローしたりする手間を省けます。私たちは新しいコードを頻繁にチェックし、新しいアップデートがリリースされるとすぐにコードリストを更新します。</p>
<p>しかし、その方法を選ぶ場合は、公式の<a href="https://discord.gg/ubg" rel="noopener nofollow" target="_blank">drowningsome Discordサーバー</a>に参加するか、公式Xアカウント（<a href="https://twitter.com/drowningsome" rel="noopener nofollow" target="_blank">@drowningsome</a>）をフォローして、最新のUBGコードを入手してください。</p>
<h2>Untitled Boxing Gameでスピンをもっと手に入れる方法は？</h2>
<p>スピンはUBGでレベルアップするための素晴らしい方法です。コードを使用する以外にもスピンを手に入れる方法があります。デイリー報酬を集めたり、クエストを完了したりして、多くの無料スピンを手に入れることができます。</p>
<p>さらに、ゲーム内コイン（1スピンあたり2000）やRobuxを使ってスピンを購入することもできます。運が良ければ、新しいプレイヤーでも素早く強くなることができます。</p>
<p>また、もし新しいUntitled Boxing Gameコードを見逃していたら、下のコメントで教えてください。すぐに追加します。ここにいる間に、Meta Lockコードを使って自信満々のサッカー選手になったり、Blox Fruitコードで最高の海賊になったりしましょう。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://dejitarumirai.com/archives/4145/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Cập nhật mã Shindo Life mới nhất ngày 16 tháng 6, 2025</title>
		<link>https://dejitarumirai.com/archives/4161</link>
					<comments>https://dejitarumirai.com/archives/4161#respond</comments>
		
		<dc:creator><![CDATA[deji]]></dc:creator>
		<pubDate>Mon, 14 Jul 2025 23:41:00 +0000</pubDate>
				<category><![CDATA[ニュース]]></category>
		<category><![CDATA[featured]]></category>
		<category><![CDATA[Hokage]]></category>
		<category><![CDATA[Naruto]]></category>
		<category><![CDATA[RELL Coins]]></category>
		<category><![CDATA[Roblox]]></category>
		<category><![CDATA[Shindo Life codes]]></category>
		<category><![CDATA[Shinobi Life 2]]></category>
		<category><![CDATA[Spins miễn phí]]></category>
		<guid isPermaLink="false">https://dejitarumirai.com/?p=4161</guid>

					<description><![CDATA[Khám phá danh sách mã Shindo Life mới nhất để nhận RELL Coins và Spins miễn phí. Sử dụng chúng để nâng cấp kỹ năng và clan trong hành trình trở thành Hokage của bạn.]]></description>
										<content:encoded><![CDATA[<p>更新日: 2025年6月16日に新しいShindo Lifeコードを確認しました</p>
<p>RobloxでShinobi Life 2を始めてから、ゲームに夢中になり、Shindo Lifeに名前が変わってからはさらに楽しくなりました。しかし、Shindo Lifeの世界では、ナルトに似た世界で次のホカゲになるための挑戦が待っています。快適なスタートを切るために、RELLコインやボーナススピンなどの無料特典を得られる全てのアクティブなShindo Lifeコードのリストをまとめました。これらのRELLコインとスピンを使って、スキルやクランをアップグレードし、敵に簡単に立ち向かいましょう。</p>
<h2>新しいShindo Lifeコード一覧</h2>
<ul>
<li><strong>RELLbrothr3n! </strong>(<mark class="has-inline-color has-gradient-red-color"><strong>NEW</strong></mark>)</li>
<li><strong>godd00dupdate! </strong>(<mark class="has-inline-color has-gradient-red-color"><strong>NEW</strong></mark>)</li>
<li><strong>mansUPDATealreadyg0d!</strong> (<mark class="has-inline-color has-gradient-red-color"><strong>NEW</strong></mark>)</li>
<li><strong>updateDEtingMon!</strong> (<mark class="has-inline-color has-gradient-red-color"><strong>NEW</strong></mark>)</li>
<li><strong>rellseasmoviehuh!</strong> (<mark class="has-inline-color has-gradient-red-color"><strong>NEW</strong></mark>)</li>
<li><strong>RellenSparrow!</strong> (<mark class="has-inline-color has-gradient-red-color"><strong>NEW</strong></mark>)</li>
<li><strong>pr3ssdeUPDATEbotton!</strong></li>
<li><strong>nofampressopdatebotton!</strong> </li>
<li><strong>RELLseasmovie37!</strong> </li>
<li><strong>updateshindoOMG! </strong></li>
<li><strong>updateb0ttonfam!</strong> </li>
<li><strong>wenrellseasmatewen!</strong> </li>
<li><strong>marchfam2025!</strong></li>
<li><strong>fampressdeupdatebotton!</strong> </li>
<li><strong>rellseasmove3when!</strong></li>
<li><strong>Apr1lF00lc00l!</strong> </li>
<li><strong>UPopUpd4te!</strong> </li>
<li><strong>RELLtopbrothers!</strong></li>
<li><strong>updopdateop!</strong></li>
<li><strong>justupdgamefam!</strong></li>
<li><strong>DragonScammer! </strong></li>
<li><strong>RELLbestBrothers! </strong> </li>
<li><strong>Merry2024Christmas! </strong></li>
<li><strong>2025RELLmas! </strong></li>
<li><strong>HappyHolidaysfromRELL! </strong> </li>
<li><strong>FixG4me239! </strong> </li>
<li><strong>Gem239! </strong> </li>
<li><strong>2024NovCodes! </strong></li>
<li><strong>RELLbadBirthday! </strong></li>
<li><strong>NovemberVM! </strong></li>
<li><strong>PlannedConcepts! </strong></li>
<li><strong>Co0lConceptsbr0!</strong> </li>
<li><strong>siCkConceptsBr0! </strong></li>
<li><strong>NoVeMmentality! </strong></li>
<li><strong>S0back2025! </strong></li>
<li><strong>r311SeasBigUps! </strong></li>
<li><strong>RELLNindonSeas! </strong></li>
<li><strong>BigManTingsTesting! </strong></li>
<li><strong>NoMoremessingOnlyGrinding! </strong></li>
</ul>
<h3>期限切れのShindo Lifeコード</h3>
<ul>
<li>AnimatingLikeimSkitty!</li>
<li>RelaxFammity!</li>
<li>FaM2028Aidenn!</li>
<li>AidennGrunt2028!</li>
<li>GruntLifeCodes!</li>
<li>ShindoGruntC0dez!</li>
<li>gruntLifeNindon!</li>
<li>RELLSeasRealSeas!</li>
<li>RellseaCsparrow!</li>
<li>AidenFAM2028!</li>
<li>gr1ndGrindG!</li>
<li>OnlyWworking!</li>
<li>NinD0nMusicFire!</li>
<li>NindonIsPeak!</li>
<li>Nind0nWwWPeak!</li>
<li>R3LLbadmanmanW!</li>
<li>WorkDawgStopSlackng!</li>
<li>PaintinPro!</li>
<li>Nind2nWWPea!</li>
<li>R3LLradmaW!</li>
<li>SaveHairohGod!</li>
<li>CrackAhSlapMan!</li>
<li>JankSwanky!</li>
<li>HairySaviorB0B!</li>
<li>PeterPorker!</li>
<li>hairyId1!</li>
<li>hairyId2!</li>
<li>hairyId3!</li>
<li>hairyId4!</li>
<li>hairyId5!</li>
<li>RELLpeakgrind!</li>
<li>NoStallOnlyWork!</li>
<li>NinD0nTestingb4Seas!</li>
<li>ZbruushGr1nd!</li>
<li>WobawgdeSlackng!</li>
<li>SandFlightNerfYes!</li>
<li>EmberKageisL!</li>
<li>HazeNobuffs!</li>
<li>RELLCSparrow!</li>
<li>PokeshindoMon!</li>
<li>NimbusCarriedBySpecs!</li>
<li>ObelisktakingLs!</li>
<li>OneTappedHimBeastBomb!</li>
<li>RayySpecCarried!</li>
<li>AidennGruntWork!</li>
<li>ImADuneKun!</li>
<li>RELL4NewYears!</li>
<li>GUnChuckduck!</li>
<li>NINd0nUpN3xT!</li>
<li>famskillinnitbruz</li>
<li>sk1llIzzuee!</li>
</ul>
<p>ここにいる間に、他の体験のためのRobloxコードをマスターリストでチェックしてみてください。もっとアニメにインスパイアされた楽しみが欲しい場合は、Anime DefendersコードやType Soulコードを試してみてください。</p>
<h2>Shindo Lifeコードの引き換え方法</h2>
<p>Shindo Lifeのコードを手に入れたら、以下のステップバイステップの手順に従ってそれらを引き換え、報酬を獲得しましょう:</p>
<ul>
<li>Robloxプレイヤーで<a href="https://www.roblox.com/games/4616652839/Shindo-Life-237" rel="noopener nofollow" target="_blank">Shindo Life</a>を起動します。</li>
<li>コード引き換えセクションを見つけるために編集メニューに移動します。</li>
<li>右側の<strong>YOUTUBE CODE</strong>ボタンをクリックします。</li>
<li>動作するコードをテキストボックスに貼り付けて報酬を得ます。</li>
</ul>
<figure><img decoding="async" alt="Shindo Lifeコード引き換えセクション" src="https://dejitarumirai.com/wp-content/uploads/2025/06/Shindo-Life-codes-section.jpg"/></figure>
<h2>もっとShindo Lifeコードを見つけるには</h2>
<p>最新の報酬を逃さないように、アクティブなコードリストを頻繁に更新しています。そのため、このページをブックマークすることをお勧めします。しかし、<a href="https://x.com/RellGames" rel="noopener nofollow" target="_blank">公式Shindo Lifeページ</a>やXの開発者ページをフォローすることで、より多くのコードを得ることができます。これらのページは時折新しいコードを共有します。</p>
<p>もっと発表や更新情報を知りたいですか？公式の<a href="https://discord.com/invite/rellgames" rel="noopener nofollow" target="_blank">Rell Games Discordサーバー</a>やRell Games YouTubeもチェックできます。Discordサーバーでは、Shindo Lifeや開発中の新ゲームRell Seasについて詳しく学ぶことができます。</p>
<h2>Shindo Lifeコードが動作しない理由</h2>
<p>コードを入力しているときに<strong>「無効なエラー」</strong>が表示される場合があります。これは、期限切れのコードを使用した可能性があります。間違ったコードを入力すると、何も起こらないことがあります。アクティブなリストからのコードの場合、正確なコードをコピーして貼り付けてください。コードの最後にスペースを追加しても、引き換え時にエラーが表示されます。両方の手順を正しく実行した場合は、ゲームを再起動するか、Shindo Lifeのシステムが修正されるまで待ってください。</p>
<h2>Shindo Lifeで無料スピンを取得するための他の方法</h2>
<p>上記の動作するShindo Lifeコードをすべて使用して、さらにスピンが欲しいですか？スピンはShindo Lifeでのスキルセットをアップグレードするために重要です。もっと無料で手に入れたい場合は、クエストを完了し、毎日ログインして、デイリーリワードを受け取りましょう。また、特定のレベルでのレベルアップ報酬としてもスピンを獲得できます。Robuxを使いたい場合は、45 Robuxで15スピン、60 Robuxで30スピン、100 Robuxで60スピンを取得できます。</p>
<p>すべての無料特典でShindo Lifeの旅を既に始めましたか？クランを選ぶ前に、Shindo Lifeの血統ティアリストをチェックすることを忘れないでください。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://dejitarumirai.com/archives/4161/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Tổng hợp code Roblox Fisch mới nhất (Cập nhật ngày 16/06/2025)</title>
		<link>https://dejitarumirai.com/archives/4165</link>
					<comments>https://dejitarumirai.com/archives/4165#respond</comments>
		
		<dc:creator><![CDATA[deji]]></dc:creator>
		<pubDate>Mon, 14 Jul 2025 11:44:00 +0000</pubDate>
				<category><![CDATA[ニュース]]></category>
		<category><![CDATA[câu cá Roblox]]></category>
		<category><![CDATA[code Roblox Fisch]]></category>
		<category><![CDATA[featured]]></category>
		<category><![CDATA[Fisch rewards]]></category>
		<category><![CDATA[Fisch simulator]]></category>
		<category><![CDATA[mã code Fisch]]></category>
		<category><![CDATA[Roblox Fisch codes]]></category>
		<category><![CDATA[Roblox game codes]]></category>
		<guid isPermaLink="false">https://dejitarumirai.com/?p=4165</guid>

					<description><![CDATA[Khám phá danh sách các mã code Fisch mới và cách sử dụng chúng để nhận tiền mặt, mồi câu nhanh và nhiều phần thưởng hữu ích khác trong game Roblox Fisch.]]></description>
										<content:encoded><![CDATA[<p>更新日: 2025年6月16日に新しいRoblox Fisch codesを確認しました</p>
<p>現実での釣りは大好きですが、Roblox Fischほど仮想世界でその感覚を味わえるゲームは少ないです。この釣りシミュレーターでは、商店で道具をアップグレードしてより珍しい魚を釣ることができます。無料の現金やルアー速度の向上、餌などを提供するすべての有効なRoblox Fisch codesをまとめました。これらの特典を利用してロッドをアップグレードし、上級魚を捕まえるチャンスを高めましょう。</p>
<h2>新しいRoblox Fisch codes一覧</h2>
<ul>
<li><strong>Legomy</strong>: だまされやすいタイトル</li>
<li><strong>SorryReward</strong>: クラーケンの触手の餌5個と1500キャッシュ</li>
<li><strong>THEKRAKEN</strong>: 沈没船の浮きと2500キャッシュ</li>
<li><strong>CARBON</strong>: 無料のカーボン浮き</li>
<li><strong>SORRYGUYS</strong>: クラーケンの触手の餌2個と1000キャッシュ</li>
<li><strong>ATLANTEANSTORM</strong>: 1000キャッシュと絞首台のフック餌2個</li>
<li><strong>GOLDENTIDE</strong>: 2000キャッシュと即時キャッチャー2個</li>
<li><strong>NewYear</strong>: 1000キャッシュ、ホーリーベリー2個、ペパーミントワーム2個</li>
<li><strong>NorthernExpedition</strong>: 1000キャッシュ、ホーリーベリー2個、ペパーミントワーム3個</li>
</ul>
<p>ここにいる間に、Fischのセカンドシーへの行き方を確認してください。到着したら、Fischのセカンドシーマップを詳しく学びましょう。また、セカンドシーのロッドについても知識を得ることができます。</p>
<h3>期限切れのRoblox Fisch codes</h3>
<ul>
<li>FISCHMASDAY</li>
<li>MERRYFISCHMAS</li>
<li>RFG</li>
<li>NewBeginnings</li>
<li>1BVisits</li>
<li>GOODBYEFISCHMAS</li>
<li>ThankYouFollowers3</li>
<li>ThankYouFollowers2</li>
<li>Advent</li>
<li>ThankYouFollowers</li>
<li>AncientIsle</li>
<li>Prehistoric</li>
<li>TheDepths</li>
<li>100M</li>
<li>200K</li>
<li>SorryForDowntime</li>
<li>Scubaaaa</li>
<li>ThanksFor10Mil</li>
<li>FischFright2024</li>
<li>SorryforShutdown</li>
</ul>
<p>釣りに疲れたら、Type Soul codesやBlox Fruits codesでアニメを楽しんでください。また、人気のゲームをすべてまとめたRobloxゲームコードのマスタリストもありますので、便利にご利用ください。</p>
<h2>Roblox Fisch codesを引き換える方法</h2>
<p>最も珍しい魚を釣るのは難しいかもしれませんが、最新のRoblox Fisch codesを引き換えるのは簡単です。手順は以下の通りです:</p>
<ul>
<li>Robloxアプリで<a href="https://www.roblox.com/games/16732694052/Fisch" rel="noopener nofollow" target="_blank">Fisch</a>を起動します。</li>
<li>画面上部の<strong>メニューボタン</strong>をクリックします。</li>
<li>メニューをスクロールして<strong>[Codes]</strong>セクションを見つけます。</li>
<li>「Type Code Here」エリアに有効なコードを入力し、Enterキーを押します。</li>
</ul>
<figure><img decoding="async" alt="Roblox Fisch codesの引き換えオプション" src="https://dejitarumirai.com/wp-content/uploads/2025/06/Redeem-Fisch-codes-option.jpg"/></figure>
<h2>Roblox Fisch codesをもっと手に入れる方法</h2>
<p>最新のコードを手に入れるには、私たちとつながっていることが最善策です。このページをブックマークして、新しいRoblox Fisch codesを逃さないようにしてください。常に有効なコードを探し、期限切れのものを排除しています。別の方法として、開発者の公式ソーシャルをフォローして、新しいコードが共有されているか確認することができます。</p>
<p>最初に確認する理想的な場所は公式の<a href="https://discord.com/invite/cuKz5SK3md" rel="noopener nofollow" target="_blank">Fisch Discordサーバー</a>です。このサーバーでは、発表、サブ発表、更新の3つの異なるチャンネルで新しいコードを見つけることができます。また、@WoozyNate XアカウントやFisching Robloxグループで最新の更新情報を見つけることができます。</p>
<h2>Fischで報酬を得る他の方法</h2>
<p>これらのコード以外にも、ゲームから追加の無料報酬を得ることができます。初めてFischに参加すると、参加ボーナスとして<strong>200キャッシュ</strong>を受け取ります。また、クエストを完了し続けることで多くのキャッシュを得ることができます。</p>
<p>ただし、Fischの開発者は、特定のタスクを完了することでゲーム内のリソースを獲得できるイベントを時折開催します。これらの報酬は、多くのロッドをアンロックし、ゲーム内で珍しい魚を捕まえる可能性を高めることができます。</p>
<p>これらの有効なRoblox Fisch codesを使って、最高の釣り人になれます。釣りの旅を始めましたか？ コメントで教えてください。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://dejitarumirai.com/archives/4165/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>最新のスポンジボブタワーディフェンスコードをチェック！</title>
		<link>https://dejitarumirai.com/archives/4153</link>
					<comments>https://dejitarumirai.com/archives/4153#respond</comments>
		
		<dc:creator><![CDATA[deji]]></dc:creator>
		<pubDate>Mon, 14 Jul 2025 04:39:00 +0000</pubDate>
				<category><![CDATA[ニュース]]></category>
		<category><![CDATA[15ウルトラ]]></category>
		<category><![CDATA[featured]]></category>
		<guid isPermaLink="false">https://dejitarumirai.com/?p=4153</guid>

					<description><![CDATA[スポンジボブタワーディフェンスの最新コードを紹介します。これらのコードを使って、ジェムや経験値のブースターを無料で手に入れましょう。]]></description>
										<content:encoded><![CDATA[<p>更新: 2025年6月15日に新しいスポンジボブタワーディフェンスコードが追加されました。</p>
<p>スポンジボブのキャラクターを集めて使う戦略ゲームをプレイするなんて夢にも思いませんでした。しかし、スポンジボブTDがそれを変えます。ただし、ゲームをプレイするのはカニバーガーを作るほど簡単ではありません。そこで、私たちはジェムやXPの無料ブースターを提供するすべての有効なスポンジボブタワーディフェンスコードをまとめました。これらの無料報酬を使用して、最強のスポンジボブチームを作りましょう。</p>
<h2>新しいスポンジボブタワーディフェンスコード一覧</h2>
<ul>
<li><strong>GiveMeNosferatu </strong>(<mark class="has-inline-color has-gradient-red-color"><strong>NEW</strong></mark>)</li>
<li><strong>IWantBunkerBoys </strong>(<mark class="has-inline-color has-gradient-red-color"><strong>NEW</strong></mark>)</li>
<li><strong>CRAFTINGISHEREYAY </strong>(<mark class="has-inline-color has-gradient-red-color"><strong>NEW</strong></mark>)</li>
<li><strong>TeachMeTheCraft</strong> (<mark class="has-inline-color has-gradient-red-color"><strong>NEW</strong></mark>)</li>
<li><strong>TAKECOVERBB </strong>(<mark class="has-inline-color has-gradient-red-color"><strong>NEW</strong></mark>)</li>
<li><strong>GEMSFORHUGS </strong>(<mark class="has-inline-color has-gradient-red-color"><strong>NEW</strong></mark>)</li>
<li><strong>BOOSTMYCRAFT</strong> </li>
</ul>
<h3>期限切れのスポンジボブTDコード</h3>
<ul>
<li>CANNEDBREADISGOOD</li>
<li>UPD22CHESTSPLS</li>
<li>HASHINTHECHEST</li>
<li>HashGoesByeBye</li>
<li>FuseMyUnitsWithCoins</li>
<li>GrowASponge</li>
<li>ThatsAlotofChests</li>
<li>GIVEMEDRAGONCAPSULES</li>
<li>MedievalRaider</li>
<li>TIERSOFTHEKINGDOM</li>
<li>NOTMONDAYSUNDAY</li>
<li>BRINGMETOTIERS</li>
<li>MYTHICTIERSBRO</li>
<li>UPD18isGoated</li>
<li>MAGICLADY</li>
<li>BETTERTHANTHEREST</li>
<li>EscapeTheDepths</li>
<li>RockBottom101</li>
<li>BasketofGoodies</li>
<li>EasterBunnySwag</li>
<li>EGGHUNTBB2025</li>
<li>ThatsSoManyLikesWowWow</li>
<li>CALLOFTHECONCH</li>
<li>AFKISBACK</li>
<li>WORMFOODYUM</li>
<li>Update15Yay</li>
<li>FUNonaTuesday</li>
<li>AChallenge2Open</li>
<li>UnitRefinement</li>
<li>CrateOfPossibilities</li>
<li>FactionGrind4Real</li>
<li>StreamLoyalist</li>
<li>CreamoftheCrop</li>
<li>OnlytheBest</li>
<li>DelayisOkay</li>
<li>PICKASIDE</li>
<li>200MilliPlaysWoah</li>
<li>OPCode4RealReal</li>
<li>OPCodeVeryOP</li>
<li>FoolMeTwice</li>
<li>WStreamChat</li>
<li>IsItPossible</li>
<li>XMarksTheSpot</li>
<li>SummonMeASecretPLS</li>
<li>AcceptingTheChallenge</li>
<li>EDUCATEDCHALLENGER</li>
<li>DENNISTHEMENACE</li>
<li>BugCrushers</li>
<li>ThanksForSupporting</li>
<li>DoubleIt</li>
<li>LetsRide</li>
<li>PriatesLife4Me</li>
<li>SLEEPYPATRICK</li>
<li>KrabsKash</li>
<li>MagmaPLS</li>
<li>Grind4Real</li>
<li>StacksonStacks</li>
<li>TheTruth</li>
<li>THEHUNTBEGINS</li>
<li>WPatchChat</li>
<li>BREAKINGNEWS</li>
<li>1MillionLikesOP</li>
<li>MerchantCash</li>
<li>MostOPUnit</li>
<li>FinalBubblePus</li>
<li>WEEKENDGRIND</li>
<li>UPD10YAY</li>
<li>TREASURECHESTS10</li>
<li>BUBBLESDOLPHIN</li>
<li>SECRETCHESTSSOON</li>
<li>NewDayNewGrind</li>
<li>Raid4Loot</li>
<li>Saturdayis4SBTD</li>
<li>BuffPatch</li>
<li>LiveforUpdate9</li>
<li>100KontheCord</li>
<li>SummonMeASecret</li>
<li>CompetitiveReady</li>
<li>SHOWMETHEREWARDS</li>
<li>ELITEBUBBLE</li>
<li>500KFeelingOkay</li>
<li>SundaeFunday</li>
<li>BubblePop</li>
<li>SaturdayAllDay</li>
<li>100MPlayedSB</li>
<li>BubbleBowlTime</li>
<li>ZachMadeAPromise</li>
<li>Hard</li>
<li>Nightmare</li>
<li>NextStopOneMillion</li>
<li>STARTERGENIUS</li>
<li>SundayFUNDay2</li>
<li>HEARTBOOSTER</li>
<li>750KLikesThanks</li>
<li>SATURDAYGRIND</li>
<li>VDayUpdate</li>
<li>YTLOYALIST</li>
<li>VDayReveal</li>
<li>TradeChatYay</li>
<li>TraitsPls</li>
<li>Goldeneye</li>
<li>Spatula9000</li>
<li>MidasTouch</li>
<li>GoldenTraitRoll4U</li>
<li>ImReadyImReady6</li>
<li>DownTime</li>
<li>ThisIsWhatWeLive4</li>
<li>WhatATimetoBeLive</li>
<li>LookAtAllThemFishies</li>
<li>EXPKRABBYKREW</li>
<li>ObeyTheConch</li>
<li>LoyalKrabbyKrewSub</li>
<li>600KMillionAnchovies</li>
<li>550KAllTheWay</li>
<li>ONTHATGRIND</li>
<li>iWATCHEDTHEVIDEO</li>
<li>MassiveUpdate4</li>
<li>KRABBYKREWYT</li>
<li>PiratesBooty</li>
<li>450KHipHipHooray</li>
<li>VaultedYummies</li>
<li>900GemsPLS</li>
<li>FUUUTURE</li>
<li>400KNoWay</li>
<li>TrinketsAPlenty</li>
<li>Sorry4Bugs</li>
<li>ShowMeTheUpdate</li>
<li>500KAnchovies</li>
<li>QuarterMillion</li>
<li>ThatWasFast</li>
<li>SummonTime</li>
<li>SecretHunter</li>
<li>OPCodeForReal</li>
<li>BoostJuice</li>
<li>100KGoofyGoobers</li>
<li>ImReadyImReady</li>
<li>OneUp</li>
<li>GemsOnGems</li>
<li>NowThisIsOP</li>
<li>SandysDojo</li>
<li>25KHooray</li>
<li>XmasUnderDaSea</li>
</ul>
<p>新しいコードを待っている方には、ゲームが特定の「いいね」や訪問数のマイルストーンに達するたびに新しい無料アイテムが約束されています。その間、Jujutsu InfiniteやFischをRobloxで試して新たな挑戦を楽しんでみてください。その他の体験については、Robloxコードマスターリストで最高のゲームをチェックしてください。</p>
<h2>スポンジボブタワーディフェンスコードの引き換え方法</h2>
<p>このゲームのコードはレベル10が必要ですので、早くレベルアップしましょう。資格を得たら、スポンジボブタワーディフェンスのコードを引き換える手順は以下の通りです：</p>
<ul>
<li><a href="https://www.roblox.com/games/123662243100680/SpongeBob-Tower-Defense-Release/" rel="noopener nofollow" target="_blank">スポンジボブタワーディフェンス</a>をRobloxで起動します。</li>
<li>左メニューから<strong>コード</strong>オプションを選択します。</li>
<li>有効なコードを「ここにコードを入力」エリアに入力します。</li>
<li><strong>引き換え</strong>ボタンをクリックして報酬を受け取ります。</li>
</ul>
<figure><img decoding="async" alt="スポンジボブタワーディフェンスコードの引き換えオプション" src="https://dejitarumirai.com/wp-content/uploads/2025/06/SpongeBob-Tower-Defense-codes-redeem-option.jpg"/></figure>
<h2>スポンジボブタワーディフェンスコードをさらに入手する方法</h2>
<p>新しい無料報酬を見つけるために頻繁にスカベンジャーハントを行っています。そのため、このページをブックマークして、常に有効なスポンジボブTDコードの最新情報を得ることをお勧めします。コードが使えなくなった場合は、期限切れリストに移動します。</p>
<p>探偵スキルを試したい方は、開発者のXアカウント（<a href="https://x.com/WonderWorksRB" rel="noopener nofollow" target="_blank">@WonderWorksRB</a>）をフォローすることもできます。また、<a href="https://www.roblox.com/communities/34990762/Krabby-Krew#!/about/" rel="noopener nofollow" target="_blank">Krabby Krew Robloxグループ</a>でスポンジボブタワーディフェンスのコードをさらに探すことができます。さらに、<a href="https://discord.com/invite/krustykrew" rel="noopener nofollow" target="_blank">Krabby Krew Discord</a>に参加することも可能です。スポンジボブTDの公式Trelloはありません。</p>
<p>多くの最高のRobloxゲームとは異なり、ここでは正確なコードを入力しないと報酬を得ることができません。タイプミスやスペースがあると「無効なコード」というエラーメッセージが表示されます。心配しないで、私たちのページから直接コードをコピーして貼り付ければ問題はありません。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://dejitarumirai.com/archives/4153/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Cập nhật mã Anime Adventures mới nhất: Ngày 16 tháng 6, 2025</title>
		<link>https://dejitarumirai.com/archives/4141</link>
					<comments>https://dejitarumirai.com/archives/4141#respond</comments>
		
		<dc:creator><![CDATA[deji]]></dc:creator>
		<pubDate>Sun, 13 Jul 2025 03:13:00 +0000</pubDate>
				<category><![CDATA[ニュース]]></category>
		<category><![CDATA[anime]]></category>
		<category><![CDATA[Anime Adventures codes]]></category>
		<category><![CDATA[cập nhật mã]]></category>
		<category><![CDATA[featured]]></category>
		<category><![CDATA[mã Anime Adventures]]></category>
		<category><![CDATA[phần thưởng miễn phí]]></category>
		<category><![CDATA[Roblox]]></category>
		<category><![CDATA[trò chơi phòng thủ tháp]]></category>
		<guid isPermaLink="false">https://dejitarumirai.com/?p=4141</guid>

					<description><![CDATA[Anime Adventures là một trong những trò chơi phòng thủ tháp phổ biến nhất trên Roblox. Sử dụng các mã mới nhất để nhận phần thưởng miễn phí như đá quý và tài nguyên trong trò chơi.]]></description>
										<content:encoded><![CDATA[<p>更新日: 2025年6月16日に新しいAnime Adventuresコードを確認しました</p>
<p>Anime Adventuresは、Robloxで最も人気のあるタワーディフェンスゲームの一つです。このゲームでは、アニメの世界からお気に入りのヒーローや悪役を召喚できます。特に初心者にとってランクを上げるのは難しいかもしれませんが、最新のAnime Adventures codesを使うことで、ジェムやスター、その他のゲーム内リソースを無料で手に入れることができます。これらのリソースを活用して、ユニットをアップグレードしたり、ゲーム内で最強のアニメキャラクターを引き当てたりしましょう。</p>
<h2>有効なAnime Adventuresコード一覧</h2>
<ul>
<li><strong>APRILFOOLS</strong> (<mark class="has-inline-color has-gradient-red-color"><strong>NEW</strong></mark>)</li>
</ul>
<p>これらのコードでより多くのジェムを手に入れたら、私たちのAnime Adventuresティアリストを確認して、どのユニットを自分のアーセナルに加えるべきかを見てみましょう。また、AA traitsティアリストを読むことをお勧めします。これにより、ユニットに適した能力を付与できます。</p>
<h3>期限切れのAnime Adventuresコード</h3>
<ul>
<li>UPDATESOON5189</li>
<li>DUNGEONS</li>
<li>UPDATE20RELEASE</li>
<li>UPD20INCOMING</li>
<li>ASSASSIN (レベル20が必要)</li>
<li>UPDSOON (レベル20が必要)</li>
<li>MILLIONFAVES (レベル20が必要)</li>
<li>2BILLIONAA (レベル50が必要)</li>
<li>SHUTDOWNCODE1230</li>
<li>MERRYCHRISTMAS2</li>
<li>MERRYCHRISTMAS</li>
<li>HOLIDAYS2024</li>
<li>HOLIDAY2023</li>
<li>UNLEASHFUSESOON</li>
<li>AMEGAKURE</li>
<li>SACREDPLANET</li>
<li>STRAYDOGS</li>
<li>HAPPYHALLOWEEN</li>
<li>HOLYGRAIL</li>
<li>HALLOWEENUPDATESOON</li>
<li>REASON2FIGHT</li>
<li>MORIOH</li>
<li>UNBREAKABLE</li>
<li>NEWCODE0819</li>
<li>OVERLORD</li>
<li>SuperTierMagicSoon</li>
<li>SUMMER2023</li>
<li>ANNIVERSARY</li>
<li>BILLION</li>
<li>Cxrsed</li>
<li>FictioNTheFirst</li>
<li>SubToKelvingts</li>
<li>TOADBOIGAMING</li>
<li>KingLuffy</li>
<li>SubToBlamspot</li>
<li>subtomaokuma</li>
<li>noclyps</li>
<li>TOURNAMENTUIFIX</li>
<li>AINCRAD</li>
<li>MADOKA</li>
<li>DRESSROSA</li>
<li>ENTERTAINMENT</li>
<li>HAPPYEASTER</li>
<li>GOLDEN</li>
<li>GOLDENSHUTDOWN</li>
<li>SINS2</li>
<li>SINS</li>
<li>UCHIHA</li>
<li>VIGILANTE</li>
<li>HERO</li>
<li>CLOUD</li>
<li>CHAINSAW</li>
<li>NEWYEAR2023</li>
<li>CHRISTMAS2022</li>
<li>GRAVITY</li>
<li>SERVERFIX</li>
<li>HUNTER</li>
<li>QUESTFIX</li>
<li>HOLLOW</li>
<li>MUGENTRAIN</li>
<li>GHOUL</li>
<li>FIRSTRAIDS</li>
<li>DATAFIX</li>
<li>MARINEFORD</li>
<li>RELEASE</li>
<li>CHALLENGEFIX</li>
<li>GINYUFIX</li>
<li>TWOMILLION</li>
</ul>
<p>新しいコードを待っている間に、私たちのRobloxゲームコードマスターリストをチェックして、Jujutsu Infiniteを含むすべてのゲームを楽しんでください。アニメタワーディフェンスゲームが好きなら、Anime Vanguards、Anime Realms、Anime Defendersも試してみてください。</p>
<h2>Anime Adventuresコードの引き換え方法</h2>
<p>Anime Adventuresのコードを手に入れたら、引き換えは簡単です。以下のステップに従って引き換えましょう：</p>
<ul>
<li><a href="https://www.roblox.com/games/8304191830/CHRISTMAS-RERELEASE-AA/" rel="noopener nofollow" target="_blank">Anime Adventures</a>ゲームをRobloxで起動します。</li>
<li>ゲーム内の<strong>Codes</strong>セクションに向かいます。</li>
<li>星がある青い円の中に立ちます。</li>
<li>プロンプトにコードを入力し、<strong>Redeem</strong>をクリックします。</li>
</ul>
<figure><img decoding="async" alt="Anime Adventuresのコード引き換えセクション" src="https://dejitarumirai.com/wp-content/uploads/2025/06/Anime-Adventures-codes-redeem-section.jpg"/></figure>
<h2>もっとAnime Adventuresコードを入手する方法</h2>
<p>この象徴的なRobloxアニメTDゲームの最新コードを手に入れるには、私たちのページが最適です。しかし、新しいコードを探すなら公式のSNSもチェックしてみてください。公式の<a href="https://discord.com/invite/adventures/" rel="noopener nofollow" target="_blank">Anime Adventures Discord</a>に参加して、最新のニュースや無料報酬を得るためにアナウンスチャンネルを確認しましょう。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://dejitarumirai.com/archives/4141/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>オセロ オンライン</title>
		<link>https://dejitarumirai.com/archives/4242</link>
					<comments>https://dejitarumirai.com/archives/4242#respond</comments>
		
		<dc:creator><![CDATA[deji]]></dc:creator>
		<pubDate>Sun, 06 Jul 2025 08:36:13 +0000</pubDate>
				<category><![CDATA[ゲーム]]></category>
		<guid isPermaLink="false">https://dejitarumirai.com/?p=4242</guid>

					<description><![CDATA[オンラインオセロ（リバーシ）  [&#8230;]]]></description>
										<content:encoded><![CDATA[<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>オンラインオセロ（リバーシ）</title>
    
    <!-- Tailwind CSS -->
    <script src="https://cdn.tailwindcss.com"></script>
    
    <!-- Google Fonts: Noto Sans JP -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;500;700&display=swap" rel="stylesheet">

    <style>
        body {
            font-family: 'Noto Sans JP', sans-serif;
            background-color: #111827; /* bg-gray-900 */
            color: #f0f0f0;
        }
        .board {
            display: grid;
            grid-template-columns: repeat(8, 1fr);
            grid-template-rows: repeat(8, 1fr);
            width: 100%;
            max-width: 640px;
            aspect-ratio: 1 / 1;
            background-color: #047857; /* emerald-700 */
            border: 8px solid #4a3a2a;
            border-radius: 8px;
            box-shadow: 0 10px 20px rgba(0,0,0,0.4);
            padding: 5px;
            gap: 5px;
        }
        .square {
            display: flex;
            align-items: center;
            justify-content: center;
            background-color: #059669; /* emerald-600 */
            border-radius: 4px;
            cursor: pointer;
            transition: background-color 0.2s;
        }
        .square:hover {
            background-color: #047857;
        }

        .piece {
            width: 85%;
            height: 85%;
            border-radius: 50%;
            box-shadow: inset 0 2px 4px rgba(0,0,0,0.4), 0 2px 3px rgba(0,0,0,0.3);
            transform: scale(0);
            animation: place-piece 0.3s ease-out forwards;
        }
        .piece.black { background-color: #1f2937; } /* gray-800 */
        .piece.white { background-color: #f9fafb; } /* gray-50 */

        @keyframes place-piece {
            from { transform: scale(0); }
            to { transform: scale(1); }
        }

        .valid-move-indicator {
            width: 40%;
            height: 40%;
            border-radius: 50%;
            background-color: rgba(255, 255, 255, 0.3);
            pointer-events: none;
        }
        
        .board-disabled {
            pointer-events: none;
            opacity: 0.8;
        }
        .modal { transition: opacity 0.25s ease; }
    </style>
</head>
<body class="flex items-center justify-center min-h-screen p-4">

    <div class="w-full max-w-6xl mx-auto">
        <header class="text-center mb-6">
            <h1 class="text-4xl md:text-5xl font-bold text-white">オセロ（リバーシ）</h1>
            <p class="text-gray-400 mt-2">相手の石を裏返して勝利しよう！</p>
        </header>

        <!-- Lobby Section -->
        <div id="lobby" class="bg-gray-800 p-8 rounded-2xl shadow-lg border border-gray-700 max-w-md mx-auto">
            <div class="mb-4">
                <label for="playerName" class="block mb-2 text-sm font-medium text-gray-300">あなたの名前</label>
                <input type="text" id="playerName" class="w-full text-sm rounded-lg p-2.5 bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-blue-500 focus:border-blue-500" placeholder="名前を入力してください" required>
            </div>
            <button id="createGameBtn" class="w-full text-white bg-emerald-600 hover:bg-emerald-700 focus:ring-4 focus:outline-none focus:ring-emerald-800 font-medium rounded-lg text-sm px-5 py-3 text-center mb-3">新しいルームを作成</button>
            <div class="relative flex py-3 items-center">
                <div class="flex-grow border-t border-gray-600"></div>
                <span class="flex-shrink mx-4 text-gray-400">または</span>
                <div class="flex-grow border-t border-gray-600"></div>
            </div>
            <div class="flex gap-2">
                <input type="text" id="joinGameId" class="w-full text-sm rounded-lg p-2.5 bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-blue-500 focus:border-blue-500" placeholder="ルームID（6桁）を入力">
                <button id="joinGameBtn" class="text-white bg-blue-600 hover:bg-blue-700 focus:ring-4 focus:outline-none focus:ring-blue-800 font-medium rounded-lg text-sm px-5 py-3">ルームに参加</button>
            </div>
             <div class="mt-4 text-center text-xs text-gray-500">
                あなたのユーザーID: <span id="userIdDisplay" class="font-mono">読み込み中...</span>
            </div>
        </div>

        <!-- Game Section -->
        <div id="game-container" class="hidden w-full">
            <div class="flex flex-col lg:flex-row gap-6 items-start justify-center">
                <!-- Game Info Panel -->
                <div class="w-full lg:w-80 bg-gray-800 p-5 rounded-xl shadow-lg border border-gray-700 flex-shrink-0 order-last lg:order-first">
                    <h3 class="text-xl font-semibold mb-3 text-white">ゲーム情報</h3>
                    <div class="mb-4">
                        <label class="block text-sm font-medium text-gray-400">ルームID:</label>
                        <div class="flex items-center gap-2 mt-1">
                            <input readonly id="gameIdDisplay" class="w-full bg-gray-700 font-mono text-lg p-2 rounded-md border border-gray-600 text-center tracking-widest"/>
                            <button id="copyGameIdBtn" class="p-2 bg-gray-600 hover:bg-gray-500 rounded-md text-gray-300" title="IDをコピー">
                                <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg>
                            </button>
                        </div>
                    </div>

                    <div id="playerInfo" class="space-y-3 text-sm"></div>
                    <p id="game-status" class="mt-4 text-center font-semibold text-lg p-3 rounded-lg bg-gray-700 text-gray-200"></p>
                    
                    <button id="resetGameBtn" class="w-full mt-4 text-white bg-yellow-600 hover:bg-yellow-700 focus:ring-4 focus:outline-none focus:ring-yellow-800 font-medium rounded-lg text-sm px-5 py-3 text-center hidden">もう一度プレイ</button>
                    <button id="leaveGameBtn" class="w-full mt-2 text-white bg-gray-600 hover:bg-gray-500 focus:ring-4 focus:outline-none focus:ring-gray-800 font-medium rounded-lg text-sm px-5 py-3 text-center">ルームを退出</button>
                </div>
                
                <!-- Game Board -->
                <div id="board" class="board">
                    <!-- Squares will be generated by JS -->
                </div>
            </div>
        </div>
    </div>

    <!-- Message Modal -->
    <div id="message-modal" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center p-4 z-50 hidden">
        <div class="bg-gray-800 rounded-xl shadow-2xl p-8 max-w-sm text-center border border-gray-700">
            <h2 id="modal-title" class="text-2xl font-bold mb-4"></h2>
            <p id="modal-body" class="text-gray-300 mb-6"></p>
            <button id="modal-close-btn" class="w-full text-white bg-blue-600 hover:bg-blue-700 font-medium rounded-lg text-sm px-5 py-3">閉じる</button>
        </div>
    </div>

    <!-- Firebase SDK -->
    <script type="module">
        // Import functions from Firebase SDKs
        import { initializeApp } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-app.js";
        import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-auth.js";
        import { getFirestore, doc, getDoc, setDoc, updateDoc, onSnapshot } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-firestore.js";
        import { setLogLevel } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-firestore.js";

        // --- CONFIG ---
        const firebaseConfig = typeof __firebase_config !== 'undefined' 
            ? JSON.parse(__firebase_config)
            : {
                // Fallback configuration
                apiKey: "AIzaSyBL3USs4_BgCBM1_eFrOA0Htmjj2FWa5XM",
                authDomain: "app-and-game.firebaseapp.com",
                projectId: "app-and-game",
                storageBucket: "app-and-game.firebasestorage.app",
                messagingSenderId: "670250047171",
                appId: "1:670250047171:web:ca90d4df93674be6fef476",
                measurementId: "G-4KR5Q5RCQV"
            };
        const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id';
        const initialAuthToken = typeof __initial_auth_token !== 'undefined' ? __initial_auth_token : null;

        const app = initializeApp(firebaseConfig);
        const db = getFirestore(app);
        const auth = getAuth(app);
        setLogLevel('debug');

        // --- DOM ELEMENTS ---
        const lobbyEl = document.getElementById('lobby');
        const gameContainerEl = document.getElementById('game-container');
        const boardEl = document.getElementById('board');
        const gameStatusEl = document.getElementById('game-status');
        const playerInfoEl = document.getElementById('playerInfo');
        const createGameBtn = document.getElementById('createGameBtn');
        const joinGameBtn = document.getElementById('joinGameBtn');
        const resetGameBtn = document.getElementById('resetGameBtn');
        const leaveGameBtn = document.getElementById('leaveGameBtn');
        const copyGameIdBtn = document.getElementById('copyGameIdBtn');
        const userIdDisplay = document.getElementById('userIdDisplay');
        const gameIdDisplay = document.getElementById('gameIdDisplay');
        const modal = document.getElementById('message-modal');
        const modalTitle = document.getElementById('modal-title');
        const modalBody = document.getElementById('modal-body');
        const modalCloseBtn = document.getElementById('modal-close-btn');

        // --- GAME STATE & CONSTANTS ---
        const BOARD_SIZE = 8;
        let userId = null;
        let playerName = '';
        let currentGameId = null;
        let playerSymbol = null; // 'B' for Black, 'W' for White
        let unsubscribeGame = null;
        let isHost = false;

        // --- AUTHENTICATION ---
        onAuthStateChanged(auth, async (user) => {
            if (user) {
                userId = user.uid;
                userIdDisplay.textContent = userId;
            } else {
                try {
                    if (initialAuthToken) {
                        await signInWithCustomToken(auth, initialAuthToken);
                    } else {
                        await signInAnonymously(auth);
                    }
                } catch (error) {
                    console.error("ログインエラー:", error);
                    showMessage("エラー", "ユーザーを認証できませんでした。ページを再読み込みしてください。");
                }
            }
        });

        // --- UI FUNCTIONS ---
        function showMessage(title, body) {
            modalTitle.textContent = title;
            modalBody.textContent = body;
            modal.classList.remove('hidden');
        }
        function showGameView(gameId) {
            currentGameId = gameId;
            gameIdDisplay.value = gameId;
            lobbyEl.classList.add('hidden');
            gameContainerEl.classList.remove('hidden');
        }
        function showLobbyView() {
            gameContainerEl.classList.add('hidden');
            lobbyEl.classList.remove('hidden');
            if (unsubscribeGame) {
                unsubscribeGame();
                unsubscribeGame = null;
            }
            currentGameId = null;
            playerSymbol = null;
            isHost = false;
        }

        // --- OTHELLO GAME LOGIC ---

        function getValidMoves(board, player) {
            const validMoves = [];
            const opponent = player === 'B' ? 'W' : 'B';
            const directions = [
                [-1, -1], [-1, 0], [-1, 1],
                [0, -1],           [0, 1],
                [1, -1], [1, 0], [1, 1]
            ];

            for (let r = 0; r < BOARD_SIZE; r++) {
                for (let c = 0; c < BOARD_SIZE; c++) {
                    if (board[r][c] !== null) continue;

                    let isValid = false;
                    for (const [dr, dc] of directions) {
                        let row = r + dr;
                        let col = c + dc;
                        let hasOpponentPieces = false;

                        while (row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE && board[row][col] === opponent) {
                            hasOpponentPieces = true;
                            row += dr;
                            col += dc;
                        }

                        if (hasOpponentPieces && row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE && board[row][col] === player) {
                            isValid = true;
                            break;
                        }
                    }
                    if (isValid) {
                        validMoves.push({ row: r, col: c });
                    }
                }
            }
            return validMoves;
        }

        function getFlipsForMove(board, startRow, startCol, player) {
            const opponent = player === 'B' ? 'W' : 'B';
            const directions = [
                [-1, -1], [-1, 0], [-1, 1],
                [0, -1],           [0, 1],
                [1, -1], [1, 0], [1, 1]
            ];
            const piecesToFlip = [];

            for (const [dr, dc] of directions) {
                let row = startRow + dr;
                let col = startCol + dc;
                const potentialFlips = [];

                while (row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE && board[row][col] === opponent) {
                    potentialFlips.push({ row, col });
                    row += dr;
                    col += dc;
                }

                if (row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE && board[row][col] === player) {
                    piecesToFlip.push(...potentialFlips);
                }
            }
            return piecesToFlip;
        }

        // --- FIREBASE & GAME FLOW ---

        function getGameDocRef(gameId) {
            return doc(db, `artifacts/${appId}/public/data/othello-games/${gameId}`);
        }

        function createInitialBoard() {
            const board = Array(BOARD_SIZE).fill(null).map(() => Array(BOARD_SIZE).fill(null));
            board[3][3] = 'W';
            board[3][4] = 'B';
            board[4][3] = 'B';
            board[4][4] = 'W';
            return board;
        }

        function calculateScores(board) {
            let blackScore = 0;
            let whiteScore = 0;
            for (let r = 0; r < BOARD_SIZE; r++) {
                for (let c = 0; c < BOARD_SIZE; c++) {
                    if (board[r][c] === 'B') blackScore++;
                    if (board[r][c] === 'W') whiteScore++;
                }
            }
            return { B: blackScore, W: whiteScore };
        }

        async function generateUniqueGameId() {
            let gameId;
            let attempts = 0;
            const maxAttempts = 20;
            while (attempts < maxAttempts) {
                gameId = Math.floor(100000 + Math.random() * 900000).toString();
                const docSnap = await getDoc(getGameDocRef(gameId));
                if (!docSnap.exists()) return gameId;
                attempts++;
            }
            throw new Error("ユニークなルームIDの生成に失敗しました。");
        }

        async function createNewGame() {
            playerName = document.getElementById('playerName').value.trim();
            if (!playerName) {
                showMessage("エラー", "名前を入力してください。");
                return;
            }
            if (!userId) {
                showMessage("エラー", "ユーザーIDがまだ利用できません。しばらくお待ちください。");
                return;
            }

            createGameBtn.disabled = true;
            createGameBtn.textContent = '作成中...';

            try {
                const newGameId = await generateUniqueGameId();
                const gameDocRef = getGameDocRef(newGameId);
                const initialBoard = createInitialBoard();
                const newGame = {
                    board: JSON.stringify(initialBoard),
                    players: { p1: { id: userId, name: playerName } }, // p1 is Black ('B')
                    currentPlayer: 'B',
                    status: 'waiting',
                    hostId: userId,
                    scores: { B: 2, W: 2 },
                    winner: null,
                    createdAt: new Date().toISOString(),
                };
                await setDoc(gameDocRef, newGame);
                
                isHost = true;
                playerSymbol = 'B';
                listenToGameUpdates(newGameId);
                showGameView(newGameId);

            } catch (error) {
                console.error("ルーム作成エラー: ", error);
                showMessage("エラー", "ルームを作成できませんでした。もう一度お試しください。");
            } finally {
                createGameBtn.disabled = false;
                createGameBtn.textContent = '新しいルームを作成';
            }
        }

        async function joinExistingGame() {
            playerName = document.getElementById('playerName').value.trim();
            if (!playerName) {
                showMessage("エラー", "名前を入力してください。");
                return;
            }
            const gameIdToJoin = document.getElementById('joinGameId').value.trim();
            if (!gameIdToJoin) {
                showMessage("エラー", "ルームIDを入力してください。");
                return;
            }

            joinGameBtn.disabled = true;
            const gameDocRef = getGameDocRef(gameIdToJoin);
            
            try {
                const gameSnap = await getDoc(gameDocRef);
                if (!gameSnap.exists()) {
                    showMessage("エラー", "このIDのルームは見つかりませんでした。");
                    return;
                }

                const gameData = gameSnap.data();
                if (gameData.players.p2 && gameData.players.p1.id !== userId) {
                    showMessage("エラー", "このルームは満員です。");
                    return;
                }
                
                if (!gameData.players.p2 && gameData.players.p1.id !== userId) {
                    await updateDoc(gameDocRef, {
                        'players.p2': { id: userId, name: playerName },
                        status: 'active'
                    });
                    playerSymbol = 'W';
                } else {
                    playerSymbol = gameData.players.p1.id === userId ? 'B' : 'W';
                }
                
                isHost = gameData.hostId === userId;
                listenToGameUpdates(gameIdToJoin);
                showGameView(gameIdToJoin);

            } catch (error) {
                console.error("ルーム参加エラー: ", error);
                showMessage("エラー", "ルームに参加できませんでした。IDを確認してください。");
            } finally {
                joinGameBtn.disabled = false;
            }
        }
        
        async function onSquareClick(row, col, isValidMove) {
            if (!isValidMove) return;

            const gameDocRef = getGameDocRef(currentGameId);
            const gameSnap = await getDoc(gameDocRef);
            if (!gameSnap.exists()) return;

            const gameData = gameSnap.data();
            const board = JSON.parse(gameData.board);
            const currentPlayer = gameData.currentPlayer;

            if (currentPlayer !== playerSymbol) return;

            const flips = getFlipsForMove(board, row, col, currentPlayer);
            board[row][col] = currentPlayer;
            flips.forEach(p => { board[p.row][p.col] = currentPlayer; });

            let nextPlayer = currentPlayer === 'B' ? 'W' : 'B';
            let nextPlayerValidMoves = getValidMoves(board, nextPlayer);
            
            if (nextPlayerValidMoves.length === 0) {
                nextPlayer = currentPlayer;
                nextPlayerValidMoves = getValidMoves(board, nextPlayer);
            }
            
            const newScores = calculateScores(board);
            let newStatus = 'active';
            let winner = null;

            if (nextPlayerValidMoves.length === 0) {
                newStatus = 'finished';
                if (newScores.B > newScores.W) winner = 'B';
                else if (newScores.W > newScores.B) winner = 'W';
                else winner = 'draw';
            }

            await updateDoc(gameDocRef, {
                board: JSON.stringify(board),
                currentPlayer: nextPlayer,
                scores: newScores,
                status: newStatus,
                winner: winner
            });
        }

        async function resetCurrentGame() {
            if (!isHost || !currentGameId) return;
            const gameDocRef = getGameDocRef(currentGameId);
            const initialBoard = createInitialBoard();
            await updateDoc(gameDocRef, {
                board: JSON.stringify(initialBoard),
                currentPlayer: 'B',
                status: 'active',
                scores: { B: 2, W: 2 },
                winner: null
            });
        }

        // --- RENDERING ---

        function renderBoard(gameData) {
            const { board: boardStr, currentPlayer, status } = gameData;
            const board = JSON.parse(boardStr);
            const isMyTurn = currentPlayer === playerSymbol && status === 'active';
            
            boardEl.innerHTML = '';
            boardEl.classList.toggle('board-disabled', !isMyTurn);
            
            const validMoves = isMyTurn ? getValidMoves(board, playerSymbol) : [];

            for (let r = 0; r < BOARD_SIZE; r++) {
                for (let c = 0; c < BOARD_SIZE; c++) {
                    const squareEl = document.createElement('div');
                    squareEl.className = 'square';
                    
                    const piece = board[r][c];
                    if (piece) {
                        const pieceEl = document.createElement('div');
                        pieceEl.className = `piece ${piece === 'B' ? 'black' : 'white'}`;
                        squareEl.appendChild(pieceEl);
                    }

                    const isValidMove = validMoves.some(move => move.row === r && move.col === c);
                    if (isValidMove) {
                        const indicator = document.createElement('div');
                        indicator.className = 'valid-move-indicator';
                        squareEl.appendChild(indicator);
                    }

                    squareEl.addEventListener('click', () => onSquareClick(r, c, isValidMove));
                    boardEl.appendChild(squareEl);
                }
            }
        }

        function updateGameInfo(gameData) {
            const { players, status, currentPlayer, scores, winner } = gameData;
            const p1 = players.p1; // Black
            const p2 = players.p2; // White

            playerInfoEl.innerHTML = `
                <div class="flex items-center justify-between p-3 rounded-lg transition-colors ${currentPlayer === 'B' && status === 'active' ? 'bg-gray-600' : 'bg-gray-700'}">
                    <div class="flex items-center gap-3">
                        <div class="w-6 h-6 rounded-full bg-gray-800 border-2 border-gray-500"></div>
                        <span class="font-semibold text-white">${p1.name} ${p1.id === userId ? "(あなた)" : ""}</span>
                    </div>
                    <span class="font-bold text-xl">${scores.B}</span>
                </div>
            `;

            if (p2) {
                 playerInfoEl.innerHTML += `
                    <div class="flex items-center justify-between p-3 rounded-lg transition-colors ${currentPlayer === 'W' && status === 'active' ? 'bg-gray-600' : 'bg-gray-700'}">
                        <div class="flex items-center gap-3">
                            <div class="w-6 h-6 rounded-full bg-gray-50 border-2 border-gray-400"></div>
                            <span class="font-semibold text-white">${p2.name} ${p2.id === userId ? "(あなた)" : ""}</span>
                        </div>
                        <span class="font-bold text-xl">${scores.W}</span>
                    </div>
                 `;
            } else {
                 playerInfoEl.innerHTML += `<div class="p-3 text-center text-gray-400 border border-dashed rounded-lg border-gray-600">対戦相手を待っています...</div>`;
            }
            
            let statusText = '';
            let statusClass = 'bg-gray-700 text-gray-200';
            if (status === 'waiting') {
                statusText = 'プレイヤーを待っています...';
            } else if (status === 'active') {
                const currentName = currentPlayer === 'B' ? p1.name : (p2 ? p2.name : '');
                statusText = `${currentName}の番です`;
                if (currentPlayer === playerSymbol) {
                    statusText = "あなたの番です！";
                    statusClass = 'bg-blue-600 text-white';
                }
            } else if (status === 'finished') {
                if (winner === 'draw') {
                    statusText = "引き分けです！";
                } else {
                    const winnerName = winner === 'B' ? p1.name : p2.name;
                    statusText = `${winnerName}の勝利です！`;
                }
                statusClass = 'bg-yellow-500 text-black font-bold';
            }
            gameStatusEl.textContent = statusText;
            gameStatusEl.className = `mt-4 text-center font-semibold text-lg p-3 rounded-lg ${statusClass}`;
            
            resetGameBtn.classList.toggle('hidden', status !== 'finished' || !isHost);
        }

        function listenToGameUpdates(gameId) {
            if (unsubscribeGame) unsubscribeGame();
            const gameDocRef = getGameDocRef(gameId);
            unsubscribeGame = onSnapshot(gameDocRef, (docSnap) => {
                if (docSnap.exists()) {
                    const gameData = docSnap.data();
                    renderBoard(gameData);
                    updateGameInfo(gameData);
                } else {
                    showMessage("お知らせ", "このゲームルームは閉鎖されたか、存在しません。");
                    showLobbyView();
                }
            });
        }

        // --- EVENT LISTENERS ---
        createGameBtn.addEventListener('click', createNewGame);
        joinGameBtn.addEventListener('click', joinExistingGame);
        leaveGameBtn.addEventListener('click', showLobbyView);
        resetGameBtn.addEventListener('click', resetCurrentGame);
        modalCloseBtn.addEventListener('click', () => modal.classList.add('hidden'));
        
        copyGameIdBtn.addEventListener('click', () => {
            const gameId = gameIdDisplay.value;
            const textArea = document.createElement("textarea");
            textArea.value = gameId;
            document.body.appendChild(textArea);
            textArea.select();
            try {
                document.execCommand('copy');
                showMessage("成功", `ルームIDをコピーしました: ${gameId}`);
            } catch (err) {
                showMessage("エラー", "IDをコピーできませんでした。");
            }
            document.body.removeChild(textArea);
        });

    </script>
</body>
</html>
]]></content:encoded>
					
					<wfw:commentRss>https://dejitarumirai.com/archives/4242/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>チェス オンライン</title>
		<link>https://dejitarumirai.com/archives/4239</link>
					<comments>https://dejitarumirai.com/archives/4239#respond</comments>
		
		<dc:creator><![CDATA[deji]]></dc:creator>
		<pubDate>Sun, 06 Jul 2025 08:11:56 +0000</pubDate>
				<category><![CDATA[ゲーム]]></category>
		<guid isPermaLink="false">https://dejitarumirai.com/?p=4239</guid>

					<description><![CDATA[オンラインチェス (Fires [&#8230;]]]></description>
										<content:encoded><![CDATA[<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>オンラインチェス (Firestore)</title>
    
    <!-- Tailwind CSS -->
    <script src="https://cdn.tailwindcss.com"></script>
    
    <!-- Chess.js for game logic -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/chess.js/0.10.3/chess.min.js"></script>
    
    <!-- Google Fonts: Noto Sans JP -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;500;700&display=swap" rel="stylesheet">

    <style>
        body {
            font-family: 'Noto Sans JP', sans-serif;
            background-color: #1a1a1a;
            color: #f0f0f0;
        }
        .board {
            display: grid;
            grid-template-columns: repeat(8, 1fr);
            grid-template-rows: repeat(8, 1fr);
            width: 100%;
            max-width: 640px;
            aspect-ratio: 1 / 1;
            border: 4px solid #4a3a2a;
            border-radius: 8px;
            box-shadow: 0 10px 20px rgba(0,0,0,0.4);
        }
        .square {
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: clamp(20px, 6vmin, 48px);
            user-select: none;
        }
        .square.light { background-color: #f0d9b5; }
        .square.dark { background-color: #b58863; }
        
        .piece { cursor: grab; }
        .piece:active { cursor: grabbing; }

        /* Styling for highlights */
        .selected {
            background-color: rgba(34, 197, 94, 0.7) !important; /* green-500 with opacity */
        }
        .last-move {
            background-color: rgba(245, 158, 11, 0.5) !important; /* amber-500 with opacity */
        }
        .possible-move-dot {
            width: 30%;
            height: 30%;
            background-color: rgba(40, 40, 40, 0.4);
            border-radius: 50%;
            pointer-events: none; /* Make sure it doesn't block clicks on the square */
        }
        .in-check {
             background-color: rgba(239, 68, 68, 0.6) !important; /* red-500 with opacity */
        }
        
        .board-disabled {
            pointer-events: none;
            opacity: 0.8;
        }
        .modal { transition: opacity 0.25s ease; }
    </style>
</head>
<body class="flex items-center justify-center min-h-screen p-4">

    <div class="w-full max-w-6xl mx-auto">
        <header class="text-center mb-6">
            <h1 class="text-4xl md:text-5xl font-bold text-white">オンラインチェス</h1>
            <p class="text-gray-400 mt-2">友達と知恵を競い合おう</p>
        </header>

        <!-- Lobby Section -->
        <div id="lobby" class="bg-gray-800 p-8 rounded-2xl shadow-lg border border-gray-700 max-w-md mx-auto">
            <div class="mb-4">
                <label for="playerName" class="block mb-2 text-sm font-medium text-gray-300">あなたの名前</label>
                <input type="text" id="playerName" class="w-full text-sm rounded-lg p-2.5 bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-blue-500 focus:border-blue-500" placeholder="名前を入力してください" required>
            </div>
            <button id="createGameBtn" class="w-full text-white bg-emerald-600 hover:bg-emerald-700 focus:ring-4 focus:outline-none focus:ring-emerald-800 font-medium rounded-lg text-sm px-5 py-3 text-center mb-3">新しいルームを作成</button>
            <div class="relative flex py-3 items-center">
                <div class="flex-grow border-t border-gray-600"></div>
                <span class="flex-shrink mx-4 text-gray-400">または</span>
                <div class="flex-grow border-t border-gray-600"></div>
            </div>
            <div class="flex gap-2">
                <input type="text" id="joinGameId" class="w-full text-sm rounded-lg p-2.5 bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-blue-500 focus:border-blue-500" placeholder="ルームID (6桁) を入力">
                <button id="joinGameBtn" class="text-white bg-blue-600 hover:bg-blue-700 focus:ring-4 focus:outline-none focus:ring-blue-800 font-medium rounded-lg text-sm px-5 py-3">ルームに参加</button>
            </div>
             <div class="mt-4 text-center text-xs text-gray-500">
                あなたのユーザーID: <span id="userIdDisplay" class="font-mono">読み込み中...</span>
            </div>
        </div>

        <!-- Game Section -->
        <div id="game-container" class="hidden w-full">
            <div class="flex flex-col lg:flex-row gap-6 items-start justify-center">
                <!-- Game Info Panel -->
                <div class="w-full lg:w-80 bg-gray-800 p-5 rounded-xl shadow-lg border border-gray-700 flex-shrink-0 order-last lg:order-first">
                    <h3 class="text-xl font-semibold mb-3 text-white">対局情報</h3>
                    <div class="mb-4">
                        <label class="block text-sm font-medium text-gray-400">ルームID:</label>
                        <div class="flex items-center gap-2 mt-1">
                            <input readonly id="gameIdDisplay" class="w-full bg-gray-700 font-mono text-lg p-2 rounded-md border border-gray-600 text-center tracking-widest"/>
                            <button id="copyGameIdBtn" class="p-2 bg-gray-600 hover:bg-gray-500 rounded-md text-gray-300" title="IDをコピー">
                                <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg>
                            </button>
                        </div>
                    </div>

                    <div id="playerInfo" class="space-y-3 text-sm"></div>
                    <p id="game-status" class="mt-4 text-center font-semibold text-lg p-3 rounded-lg bg-gray-700 text-gray-200"></p>
                    
                    <div id="captured-pieces-white" class="mt-4 text-2xl"></div>
                    <div id="captured-pieces-black" class="mt-4 text-2xl"></div>

                    <button id="resetGameBtn" class="w-full mt-4 text-white bg-yellow-600 hover:bg-yellow-700 focus:ring-4 focus:outline-none focus:ring-yellow-800 font-medium rounded-lg text-sm px-5 py-3 text-center hidden">もう一度プレイ</button>
                    <button id="leaveGameBtn" class="w-full mt-2 text-white bg-gray-600 hover:bg-gray-500 focus:ring-4 focus:outline-none focus:ring-gray-800 font-medium rounded-lg text-sm px-5 py-3 text-center">ルームを退出</button>
                </div>
                
                <!-- Game Board -->
                <div id="board" class="board">
                    <!-- Squares will be generated by JS -->
                </div>
            </div>
        </div>
    </div>

    <!-- Message Modal -->
    <div id="message-modal" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center p-4 z-50 hidden">
        <div class="bg-gray-800 rounded-xl shadow-2xl p-8 max-w-sm text-center border border-gray-700">
            <h2 id="modal-title" class="text-2xl font-bold mb-4"></h2>
            <p id="modal-body" class="text-gray-300 mb-6"></p>
            <button id="modal-close-btn" class="w-full text-white bg-blue-600 hover:bg-blue-700 font-medium rounded-lg text-sm px-5 py-3">閉じる</button>
        </div>
    </div>

    <!-- Firebase SDK -->
    <script type="module">
        import { initializeApp } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-app.js";
        import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-auth.js";
        import { getFirestore, doc, getDoc, setDoc, updateDoc, onSnapshot } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-firestore.js";
        import { setLogLevel } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-firestore.js";

        // --- CONFIG ---
        const firebaseConfig = typeof __firebase_config !== 'undefined' 
            ? JSON.parse(__firebase_config)
            : {
                apiKey: "AIzaSyBL3USs4_BgCBM1_eFrOA0Htmjj2FWa5XM",
                authDomain: "app-and-game.firebaseapp.com",
                projectId: "app-and-game",
                storageBucket: "app-and-game.firebasestorage.app",
                messagingSenderId: "670250047171",
                appId: "1:670250047171:web:ca90d4df93674be6fef476",
                measurementId: "G-4KR5Q5RCQV"
            };
        const appId = typeof __app_id !== 'undefined' ? __app_id : firebaseConfig.projectId;
        const initialAuthToken = typeof __initial_auth_token !== 'undefined' ? __initial_auth_token : null;

        const app = initializeApp(firebaseConfig);
        const db = getFirestore(app);
        const auth = getAuth(app);
        setLogLevel('debug');

        // --- DOM ELEMENTS ---
        const lobbyEl = document.getElementById('lobby');
        const gameContainerEl = document.getElementById('game-container');
        const boardEl = document.getElementById('board');
        const gameStatusEl = document.getElementById('game-status');
        const playerInfoEl = document.getElementById('playerInfo');
        const createGameBtn = document.getElementById('createGameBtn');
        const joinGameBtn = document.getElementById('joinGameBtn');
        const resetGameBtn = document.getElementById('resetGameBtn');
        const leaveGameBtn = document.getElementById('leaveGameBtn');
        const copyGameIdBtn = document.getElementById('copyGameIdBtn');
        const userIdDisplay = document.getElementById('userIdDisplay');
        const gameIdDisplay = document.getElementById('gameIdDisplay');
        const modal = document.getElementById('message-modal');
        const modalTitle = document.getElementById('modal-title');
        const modalBody = document.getElementById('modal-body');
        const modalCloseBtn = document.getElementById('modal-close-btn');

        // --- GAME STATE ---
        let userId = null;
        let playerName = '';
        let currentGameId = null;
        let playerColor = null; // 'w' or 'b'
        let unsubscribeGame = null;
        let chess = new Chess();
        let selectedSquare = null;
        let isHost = false;

        const pieceUnicode = {
            'P': '♙', 'R': '♖', 'N': '♘', 'B': '♗', 'Q': '♕', 'K': '♔',
            'p': '♟', 'r': '♜', 'n': '♞', 'b': '♝', 'q': '♛', 'k': '♚'
        };

        // --- AUTHENTICATION ---
        onAuthStateChanged(auth, async (user) => {
            if (user) {
                userId = user.uid;
                userIdDisplay.textContent = userId;
            } else {
                try {
                    if (initialAuthToken) {
                        await signInWithCustomToken(auth, initialAuthToken);
                    } else {
                        await signInAnonymously(auth);
                    }
                } catch (error) {
                    console.error("ログインエラー:", error);
                    showMessage("エラー", "ユーザー認証に失敗しました。ページを再読み込みしてください。");
                }
            }
        });

        // --- UI FUNCTIONS ---
        function showMessage(title, body) {
            modalTitle.textContent = title;
            modalBody.textContent = body;
            modal.classList.remove('hidden');
        }
        function showGameView(gameId) {
            currentGameId = gameId;
            gameIdDisplay.value = gameId;
            lobbyEl.classList.add('hidden');
            gameContainerEl.classList.remove('hidden');
        }
        function showLobbyView() {
            gameContainerEl.classList.add('hidden');
            lobbyEl.classList.remove('hidden');
            if (unsubscribeGame) {
                unsubscribeGame();
                unsubscribeGame = null;
            }
            currentGameId = null;
            playerColor = null;
            isHost = false;
        }

        // --- GAME LOGIC ---
        function getGameDocRef(gameId) {
            return doc(db, `artifacts/${appId}/public/data/chess-games/${gameId}`);
        }

        function renderBoard(fen, lastMove, playerColorToMove) {
            chess.load(fen);
            boardEl.innerHTML = '';
            boardEl.classList.toggle('board-disabled', playerColor !== playerColorToMove || chess.game_over());

            const squares = chess.SQUARES;
            const isFlipped = playerColor === 'b';

            for (let i = 0; i < squares.length; i++) {
                const squareIndex = isFlipped ? (squares.length - 1 - i) : i;
                const squareName = squares[squareIndex];

                const squareEl = document.createElement('div');
                
                const rank = parseInt(squareName.charAt(1), 10);
                const file = squareName.charCodeAt(0) - 'a'.charCodeAt(0);
                squareEl.className = `square ${(rank + file) % 2 === 0 ? 'light' : 'dark'}`;
                squareEl.dataset.square = squareName;

                const piece = chess.get(squareName);
                if (piece) {
                    const pieceEl = document.createElement('span');
                    pieceEl.className = 'piece';
                    
                    let fenChar = piece.type;
                    if (piece.color === 'w') {
                        fenChar = fenChar.toUpperCase();
                    }
                    pieceEl.textContent = pieceUnicode[fenChar];
                    pieceEl.style.color = piece.color === 'w' ? '#FFFFFF' : '#000000';
                    squareEl.appendChild(pieceEl);
                }
                
                if (lastMove && (squareName === lastMove.from || squareName === lastMove.to)) {
                    squareEl.classList.add('last-move');
                }
                
                if (chess.in_check() && piece && piece.type === 'k' && piece.color === chess.turn()) {
                    squareEl.classList.add('in-check');
                }

                squareEl.addEventListener('click', () => onSquareClick(squareName));
                boardEl.appendChild(squareEl);
            }
        }
        
        function updateGameInfo(gameData) {
            const { players, status, turn } = gameData;
            const p1 = players.p1; // White
            const p2 = players.p2; // Black

            playerInfoEl.innerHTML = '';
            const p1_html = `<div class="flex items-center justify-between p-3 rounded-lg transition-colors ${turn === 'w' ? 'bg-green-800' : 'bg-gray-700'}">
                <span class="font-semibold text-white">先手 (白): ${p1.name}</span>
                <span class="font-mono text-xs text-gray-400">${p1.id === userId ? "(あなた)" : ""}</span>
            </div>`;
            playerInfoEl.insertAdjacentHTML('beforeend', p1_html);

            if (p2) {
                 const p2_html = `<div class="flex items-center justify-between p-3 rounded-lg transition-colors ${turn === 'b' ? 'bg-green-800' : 'bg-gray-700'}">
                    <span class="font-semibold text-white">後手 (黒): ${p2.name}</span>
                    <span class="font-mono text-xs text-gray-400">${p2.id === userId ? "(あなた)" : ""}</span>
                 </div>`;
                 playerInfoEl.insertAdjacentHTML('beforeend', p2_html);
            } else {
                 playerInfoEl.insertAdjacentHTML('beforeend', `<div class="p-3 text-center text-gray-400 border border-dashed rounded-lg border-gray-600">対戦相手を待っています...</div>`);
            }
            
            let statusText = '';
            let statusClass = 'bg-gray-700 text-gray-200';
            switch(status) {
                case 'waiting':
                    statusText = 'プレイヤーを待っています...';
                    break;
                case 'active':
                    statusText = turn === 'w' ? "先手 (白) の番です" : "後手 (黒) の番です";
                    if ((turn === 'w' && playerColor === 'w') || (turn === 'b' && playerColor === 'b')) {
                        statusText = "あなたの番です！";
                        statusClass = 'bg-blue-600 text-white';
                    }
                    break;
                case 'checkmate':
                    const winner = turn === 'b' ? '先手 (白)' : '後手 (黒)';
                    statusText = `チェックメイト！ ${winner} の勝ちです！`;
                    statusClass = 'bg-yellow-500 text-black font-bold';
                    break;
                case 'stalemate':
                    statusText = 'ステールメイト！';
                    statusClass = 'bg-yellow-500 text-black font-bold';
                    break;
                case 'draw':
                    statusText = '千日手で引き分け';
                    statusClass = 'bg-yellow-500 text-black font-bold';
                    break;
            }
            gameStatusEl.textContent = statusText;
            gameStatusEl.className = `mt-4 text-center font-semibold text-lg p-3 rounded-lg ${statusClass}`;
            
            resetGameBtn.classList.toggle('hidden', status === 'active' || status === 'waiting' || !isHost);
        }

        async function generateUniqueGameId() {
            let gameId;
            let attempts = 0;
            const maxAttempts = 20;
            while (attempts < maxAttempts) {
                gameId = Math.floor(100000 + Math.random() * 900000).toString();
                const docSnap = await getDoc(getGameDocRef(gameId));
                if (!docSnap.exists()) return gameId;
                attempts++;
            }
            throw new Error("ユニークなルームIDの生成に失敗しました。");
        }

        async function createNewGame() {
            playerName = document.getElementById('playerName').value.trim();
            if (!playerName) {
                showMessage("エラー", "名前を入力してください。");
                return;
            }
            if (!userId) {
                showMessage("エラー", "ユーザーIDがまだ利用できません。少々お待ちください。");
                return;
            }

            createGameBtn.disabled = true;
            createGameBtn.textContent = '作成中...';

            try {
                const newGameId = await generateUniqueGameId();
                const gameDocRef = getGameDocRef(newGameId);
                const newGame = {
                    fen: 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1',
                    players: { p1: { id: userId, name: playerName } }, // p1 is White
                    turn: 'w',
                    status: 'waiting',
                    hostId: userId,
                    lastMove: null,
                    createdAt: new Date().toISOString(),
                };
                await setDoc(gameDocRef, newGame);
                
                isHost = true;
                playerColor = 'w';
                listenToGameUpdates(newGameId);
                showGameView(newGameId);

            } catch (error) {
                console.error("ルーム作成エラー: ", error);
                showMessage("エラー", "ルームを作成できませんでした。もう一度お試しください。");
            } finally {
                createGameBtn.disabled = false;
                createGameBtn.textContent = '新しいルームを作成';
            }
        }

        async function joinExistingGame() {
            playerName = document.getElementById('playerName').value.trim();
            if (!playerName) {
                showMessage("エラー", "名前を入力してください。");
                return;
            }
            const gameIdToJoin = document.getElementById('joinGameId').value.trim();
            if (!gameIdToJoin) {
                showMessage("エラー", "ルームIDを入力してください。");
                return;
            }

            joinGameBtn.disabled = true;
            const gameDocRef = getGameDocRef(gameIdToJoin);
            
            try {
                const gameSnap = await getDoc(gameDocRef);
                if (!gameSnap.exists()) {
                    showMessage("エラー", "このIDのルームは見つかりませんでした。");
                    return;
                }

                const gameData = gameSnap.data();
                if (gameData.players.p2 && gameData.players.p1.id !== userId) {
                    showMessage("エラー", "このルームは満員です。");
                    return;
                }
                
                if (!gameData.players.p2 && gameData.players.p1.id !== userId) {
                    await updateDoc(gameDocRef, {
                        'players.p2': { id: userId, name: playerName },
                        status: 'active'
                    });
                    playerColor = 'b';
                } else {
                    playerColor = gameData.players.p1.id === userId ? 'w' : 'b';
                }
                
                isHost = gameData.hostId === userId;
                listenToGameUpdates(gameIdToJoin);
                showGameView(gameIdToJoin);

            } catch (error) {
                console.error("ルーム参加エラー: ", error);
                showMessage("エラー", "ルームに参加できませんでした。IDを確認してください。");
            } finally {
                joinGameBtn.disabled = false;
            }
        }

        function listenToGameUpdates(gameId) {
            if (unsubscribeGame) unsubscribeGame();
            const gameDocRef = getGameDocRef(gameId);
            unsubscribeGame = onSnapshot(gameDocRef, (docSnap) => {
                if (docSnap.exists()) {
                    const gameData = docSnap.data();
                    renderBoard(gameData.fen, gameData.lastMove, gameData.turn);
                    updateGameInfo(gameData);
                } else {
                    showMessage("お知らせ", "対局ルームが閉鎖されたか、存在しません。");
                    showLobbyView();
                }
            });
        }
        
        function clearHighlights() {
            document.querySelectorAll('.square').forEach(s => {
                s.classList.remove('selected');
                const dot = s.querySelector('.possible-move-dot');
                if (dot) dot.remove();
            });
        }

        async function onSquareClick(squareName) {
            const piece = chess.get(squareName);

            if (selectedSquare) {
                const move = {
                    from: selectedSquare,
                    to: squareName,
                    promotion: 'q'
                };
                
                const result = chess.move(move);
                
                if (result) {
                    let newStatus = 'active';
                    if (chess.in_checkmate()) newStatus = 'checkmate';
                    else if (chess.in_stalemate()) newStatus = 'stalemate';
                    else if (chess.in_draw()) newStatus = 'draw';

                    const gameDocRef = getGameDocRef(currentGameId);
                    await updateDoc(gameDocRef, {
                        fen: chess.fen(),
                        turn: chess.turn(),
                        status: newStatus,
                        lastMove: { from: result.from, to: result.to }
                    });
                }
                
                clearHighlights();
                selectedSquare = null;

            } else {
                if (piece && piece.color === playerColor) {
                    selectedSquare = squareName;
                    clearHighlights();
                    document.querySelector(`[data-square="${squareName}"]`).classList.add('selected');
                    
                    const moves = chess.moves({ square: squareName, verbose: true });
                    moves.forEach(move => {
                        const moveSquare = document.querySelector(`[data-square="${move.to}"]`);
                        const dot = document.createElement('div');
                        dot.className = 'possible-move-dot';
                        moveSquare.appendChild(dot);
                    });
                }
            }
        }
        
        async function resetCurrentGame() {
            if (!isHost || !currentGameId) return;
            const gameDocRef = getGameDocRef(currentGameId);
            await updateDoc(gameDocRef, {
                fen: 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1',
                turn: 'w',
                status: 'active',
                lastMove: null
            });
        }

        // --- EVENT LISTENERS ---
        createGameBtn.addEventListener('click', createNewGame);
        joinGameBtn.addEventListener('click', joinExistingGame);
        leaveGameBtn.addEventListener('click', showLobbyView);
        resetGameBtn.addEventListener('click', resetCurrentGame);
        modalCloseBtn.addEventListener('click', () => modal.classList.add('hidden'));
        
        copyGameIdBtn.addEventListener('click', () => {
            const gameId = gameIdDisplay.value;
            const textArea = document.createElement("textarea");
            textArea.value = gameId;
            document.body.appendChild(textArea);
            textArea.select();
            try {
                document.execCommand('copy');
                showMessage("成功", `ルームIDをコピーしました: ${gameId}`);
            } catch (err) {
                showMessage("エラー", "IDをコピーできませんでした。");
            }
            document.body.removeChild(textArea);
        });

    </script>
</body>
</html>
]]></content:encoded>
					
					<wfw:commentRss>https://dejitarumirai.com/archives/4239/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>新しいFruit Battlegroundsコードを6月14日2025年に追加しました</title>
		<link>https://dejitarumirai.com/archives/4157</link>
					<comments>https://dejitarumirai.com/archives/4157#respond</comments>
		
		<dc:creator><![CDATA[deji]]></dc:creator>
		<pubDate>Sun, 06 Jul 2025 04:48:00 +0000</pubDate>
				<category><![CDATA[ニュース]]></category>
		<category><![CDATA[15ウルトラ]]></category>
		<category><![CDATA[featured]]></category>
		<category><![CDATA[Fruit Battlegrounds codes]]></category>
		<category><![CDATA[One Piece]]></category>
		<category><![CDATA[Roblox]]></category>
		<guid isPermaLink="false">https://dejitarumirai.com/?p=4157</guid>

					<description><![CDATA[Fruit Battlegroundsでのグラインドが難しい場合、私たちが助けます。新しいFruit Battlegroundsコードを使用して、無料のジェムを獲得し、新しいデビルフルーツを手に入れましょう。]]></description>
										<content:encoded><![CDATA[<p>更新日: 2025年6月14日に新しいFruit Battlegroundsコードを追加しました</p>
<p>Fruit Battlegroundsでの進行が厳しくなり、無料の報酬を手に入れたい場合は、私たちがサポートします。多くのRobloxゲームがOne Pieceに触発されている中、このゲームは悪魔の実を楽しむ素晴らしい方法です。新しい悪魔の実を購入して敵と戦いレベルアップするだけでなく、強力なフルーツを手に入れる別の方法もあります。私たちのFruit Battlegrounds codesのリストを使って、新しい悪魔の実を得るためにスピンできる無料のジェムを獲得しましょう。</p>
<h2>新しいFruit Battlegrounds Codes</h2>
<ul>
<li><strong>LOL960K!</strong>: 500ジェム (<strong><mark class="has-inline-color has-gradient-red-color">NEW</mark></strong>)</li>
</ul>
<h3>期限切れのFruit Battlegrounds Codes</h3>
<ul>
<li>950KOMGGG!</li>
<li>940KHAPPYDAYZ</li>
<li>930KINS4NITY</li>
<li>HYPEE920K!</li>
<li>WOWZER910</li>
<li>OMG9HUNDRED!</li>
<li>MAGNIFICENT890K!!</li>
<li>BIGDAY</li>
<li>ANTICIPATION</li>
<li>IAMLEOPARD</li>
<li>BIGUPDATE20</li>
<li>860KHYPEE</li>
<li>WORLDWAR2025</li>
<li>FREEBOTAGAIN</li>
<li>NEWYEAR2025!!</li>
<li>FREEBOOT!</li>
<li>840MENTAL</li>
<li>WINTER2024!</li>
<li>OMGUPDATE19!</li>
<li>COOKEDPASTRY!</li>
<li>830KBRO!</li>
<li>SPLENDID820</li>
<li>810TIME!</li>
<li>BIG8HUNDO!</li>
<li>SHINE790K</li>
<li>GLITTER780K</li>
<li>4BUNDANCY</li>
<li>OMGREBOOTAGAIN</li>
<li>NANAP0CALYPSE!</li>
<li>770KWOW!</li>
<li>SORRY4DELAY</li>
<li>NEWBOUNTYERA!</li>
<li>HOWLINGFALL!</li>
<li>LVLBUFFHYPE</li>
<li>ICEW0LF</li>
<li>SM4LLFRY</li>
<li>760KISKRAZY</li>
<li>750KINSANE!</li>
<li>HAHA740K!</li>
<li>730EXPLODE</li>
<li>RIGHT720</li>
<li>710KOMG!!</li>
<li>BAM700K</li>
<li>SCORCHINGSUMMER</li>
<li>BIGB1RD</li>
<li>3LAPSED!</li>
<li>UNLOCK690K!</li>
<li>SORRYMOBILE</li>
<li>POW680K!</li>
<li>LETSGOO130K</li>
<li>650ISMADD!</li>
<li>AYO640K!</li>
<li>JEEZ630</li>
<li>WOWZER620!</li>
<li>TRUEMENACE</li>
<li>ITSTIME!!</li>
<li>MOSTH4TED</li>
<li>TRUEMENACE</li>
<li>THXFOR610!!</li>
<li>DAHUNT2024</li>
<li>OMG600K!!!</li>
<li>HIGH590</li>
<li>SPR34DL0V3</li>
<li>VALENTINES2024</li>
<li>POS1T1V1TY</li>
<li>580FLAMES</li>
<li>570FAVS</li>
<li>N3WW0RLD!</li>
<li>ILOV3C4NDY</li>
<li>HYPEWHOLECAKE</li>
<li>LAGFIXX</li>
<li>CLEANREB00T</li>
<li>YOOO560</li>
<li>550POGG</li>
<li>540DAYUM</li>
<li>530GYAT</li>
<li>SHEEESH520!!</li>
<li>WINTAH2023</li>
<li>LAVAPARTY</li>
<li>KOLDKRAZE!</li>
</ul>
<p>ここにいる間に、他の人気ゲームの動作中のコードを入手するために、Robloxコードのマスターリストをチェックすることをお勧めします。Anime Vanguards、Blox Fruits、Anime Fruit Worldなどのゲームの新しいコードを見つけることができます。</p>
<h2>Fruit Battlegrounds Codesの引き換え方法</h2>
<p>最新のFruit Battlegrounds codesを引き換えるための手順は以下の通りです:</p>
<ul>
<li>Robloxプレイヤーで<a href="https://www.roblox.com/games/9224601490/LIGHT-V2-RANKED-Fruit-Battlegrounds" rel="noopener nofollow" target="_blank">Fruit Battlegrounds</a>を開きます。</li>
<li>メインメニューで<strong>スピンフルーツオプション</strong>をクリックします。</li>
<li>部屋の中央にある<strong>宝箱</strong>をクリックします。</li>
<li>左下にある<strong>コードセクション</strong>を見つけます。</li>
<li>有効なコードを入力し、<strong>引き換え</strong>ボタンをクリックします。</li>
</ul>
<figure><img decoding="async" alt="redeem codes for fruit battlegrounds" src="https://dejitarumirai.com/wp-content/uploads/2025/06/redeem-codes-for-fruit-battlegrounds.jpg"/></figure>
<p>さらに、ホイールをスピンしてより良いフルーツにアクセスしたい場合は、Robloxプレミアムを取得することができます。画面下部の<strong>引き換えセクション</strong>で購入ボタンをクリックすることで、プレミアムメンバーシップを取得できます。これにより、Fruit Battlegroundsで<strong>20%の運気向上</strong>が得られます。</p>
<h2>Fruit Battlegroundsのコードをもっと得る方法</h2>
<p>私たちはコードリストを頻繁に更新しているので、新しいFruit Battlegrounds codesにアクセスする最良の方法は、私たちのページをブックマークし、アップデートが行われた際に再訪することです。</p>
<p>しかし、自分で最新のコードを探す予定がある場合は、開発者POPOが運営する<a href="https://discord.com/invite/popo" rel="noopener nofollow" target="_blank">Fruit Battlegrounds Discordサーバー</a>をフォローしてください。コードは通常、Discordの「<strong>fb-updates</strong>」チャンネルで共有されます。</p>
<h2>Fruit Battlegroundsとは？</h2>
<p>Fruit Battlegroundsは、One Pieceのアニメ・マンガシリーズに触発されたアドベンチャーゲームです。Fruit Battlegroundsの主な武器は<strong>悪魔の実</strong>で、ルフィが使うゴムゴムの実のようなものです。これらのフルーツを手に入れるには、コードから得たジェムを使ってホイールをスピンする必要があります。</p>
<p>強力なフルーツがあれば、ゲームを簡単に進め、敵の大群を素早く倒すことができます。Fruit Battlegroundsのコードは無料でジェムを手に入れるための理想的な方法です。ボスを倒したり、新しい称号を獲得することで、さらにジェムを手に入れることも可能です。AFKの場合は、AFKワールドに入り、そこでの滞在時間に応じて無料のジェムを獲得できます。</p>
<p>コードが機能しない場合は、以下のコメントでお知らせください。すぐにコードリストから削除します。また、見逃しているコードがあれば、以下のコメントで共有してください。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://dejitarumirai.com/archives/4157/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>ラッキーホイールオンライン</title>
		<link>https://dejitarumirai.com/archives/4236</link>
					<comments>https://dejitarumirai.com/archives/4236#respond</comments>
		
		<dc:creator><![CDATA[deji]]></dc:creator>
		<pubDate>Sat, 05 Jul 2025 15:50:59 +0000</pubDate>
				<category><![CDATA[ゲーム]]></category>
		<guid isPermaLink="false">https://dejitarumirai.com/?p=4236</guid>

					<description><![CDATA[ラッキーホイールオンライン ラ [&#8230;]]]></description>
										<content:encoded><![CDATA[<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ラッキーホイールオンライン</title>
    
    <!-- Tailwind CSS -->
    <script src="https://cdn.tailwindcss.com"></script>
    
    <!-- Google Fonts -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Be+Vietnam+Pro:wght@400;500;700;900&family=Noto+Sans+JP:wght@400;500;700&display=swap" rel="stylesheet">

    <style>
        body {
            font-family: 'Noto Sans JP', 'Be Vietnam Pro', sans-serif;
            background-color: #111827; /* bg-gray-900 */
            color: #D1D5DB; /* text-gray-300 */
        }
        #wheel-container {
            position: relative;
            width: 100%;
            max-width: 450px;
            aspect-ratio: 1 / 1;
            margin: 0 auto;
        }
        #wheel-canvas {
            width: 100%;
            height: 100%;
            transition: transform 6s cubic-bezier(0.2, 0.8, 0.2, 1);
        }
        #pointer {
            position: absolute;
            top: -15px;
            left: 50%;
            transform: translateX(-50%);
            width: 0;
            height: 0;
            border-left: 25px solid transparent;
            border-right: 25px solid transparent;
            border-top: 40px solid #f59e0b; /* amber-500 */
            z-index: 10;
        }
        .dark-input {
            background-color: #374151; border-color: #4B5563; color: #F9FAFB;
        }
        .dark-input::placeholder { color: #6B7280; }
        .dark-input:focus { --tw-ring-color: #14b8a6; border-color: #14b8a6; }
        .modal { transition: opacity 0.25s ease; }
    </style>
</head>
<body class="flex items-center justify-center min-h-screen p-4">

    <div class="w-full max-w-6xl mx-auto">
        <!-- Header -->
        <header class="text-center mb-8">
            <h1 class="text-4xl md:text-5xl font-black text-transparent bg-clip-text bg-gradient-to-r from-teal-400 to-blue-500">ラッキーホイールオンライン</h1>
            <p class="text-gray-400 mt-2 text-lg">エキサイティングな瞬間を一緒に分かち合おう！</p>
        </header>

        <!-- Lobby Section -->
        <div id="lobby" class="bg-gray-800 p-8 rounded-2xl shadow-lg border border-gray-700 max-w-md mx-auto">
            <div class="mb-4">
                <label for="playerName" class="block mb-2 text-sm font-medium text-gray-300">あなたの名前</label>
                <input type="text" id="playerName" class="dark-input w-full text-sm rounded-lg p-2.5" placeholder="名前を入力してください" required>
            </div>
            <button id="createRoomBtn" class="w-full text-white bg-emerald-600 hover:bg-emerald-700 focus:ring-4 focus:outline-none focus:ring-emerald-800 font-medium rounded-lg text-sm px-5 py-3 text-center mb-3">新しいルームを作成</button>
            <div class="relative flex py-3 items-center">
                <div class="flex-grow border-t border-gray-600"></div>
                <span class="flex-shrink mx-4 text-gray-400">または</span>
                <div class="flex-grow border-t border-gray-600"></div>
            </div>
            <div class="flex gap-2">
                <input type="text" id="joinRoomId" class="dark-input w-full text-sm rounded-lg p-2.5" placeholder="ルームID (6桁) を入力">
                <button id="joinRoomBtn" class="text-white bg-blue-600 hover:bg-blue-700 focus:ring-4 focus:outline-none focus:ring-blue-800 font-medium rounded-lg text-sm px-5 py-3">ルームに参加</button>
            </div>
             <div class="mt-4 text-center text-xs text-gray-500">
                あなたのユーザーID: <span id="userIdDisplay" class="font-mono">読み込み中...</span>
            </div>
        </div>

        <!-- Game Section -->
        <main id="game-container" class="hidden">
            <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
                <!-- Left Panel: Info & Players -->
                <div class="lg:col-span-1 bg-gray-800 p-6 rounded-2xl shadow-lg border border-gray-700">
                    <h2 class="text-2xl font-bold mb-4 text-white">ルーム情報</h2>
                    <div class="mb-4">
                        <label class="block text-sm font-medium text-gray-400">ルームID (友達と共有):</label>
                        <div class="flex items-center gap-2 mt-1">
                            <input readonly id="roomIdDisplay" class="w-full bg-gray-700 font-mono text-lg p-2 rounded-md border border-gray-600 text-center tracking-widest text-gray-50"/>
                            <button id="copyRoomIdBtn" class="p-2 bg-gray-600 hover:bg-gray-500 rounded-md text-gray-300" title="IDをコピー">
                                <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg>
                            </button>
                        </div>
                    </div>
                    <div class="mb-4">
                        <h3 class="text-lg font-bold mb-2 text-white">参加者 (<span id="player-count">0</span>/20)</h3>
                        <ul id="player-list" class="space-y-2 text-gray-300 max-h-60 overflow-y-auto pr-2">
                            <!-- Player list will be populated here -->
                        </ul>
                    </div>
                     <button id="leaveRoomBtn" class="w-full mt-4 bg-gray-600 hover:bg-gray-500 text-white font-bold py-2 px-4 rounded-lg transition">
                        ルームを退出
                    </button>
                </div>

                <!-- Middle Panel: Wheel -->
                <div class="lg:col-span-1 bg-gray-800 p-6 rounded-2xl shadow-lg border border-gray-700 flex flex-col items-center justify-center">
                    <div id="wheel-container">
                        <div id="pointer"></div>
                        <canvas id="wheel-canvas" width="450" height="450"></canvas>
                    </div>
                    <button id="spin-btn" class="mt-6 bg-gradient-to-br from-teal-500 to-blue-600 text-white font-bold py-4 px-12 rounded-xl text-xl transition-all transform hover:scale-105 shadow-lg hover:shadow-blue-500/50 disabled:opacity-50 disabled:cursor-not-allowed">
                        スピン!
                    </button>
                    <div id="result-display" class="mt-4 text-center h-12"></div>
                </div>

                <!-- Right Panel: Customization (Host only) -->
                <div id="host-controls" class="lg:col-span-1 bg-gray-800 p-6 rounded-2xl shadow-lg border border-gray-700 hidden">
                    <h2 class="text-2xl font-bold mb-4 text-center text-white">ホイールをカスタマイズ</h2>
                    <p class="text-sm text-center text-gray-400 mb-4">ホストのみがホイールを変更できます。</p>
                    
                    <div class="space-y-4">
                         <button id="use-players-btn" class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-4 rounded-lg transition">
                            プレイヤーリストを使用
                        </button>
                        <div>
                            <label for="custom-items-input" class="block mb-2 text-sm font-medium text-gray-300">または、オプションを入力 (1行に1つ):</label>
                            <textarea id="custom-items-input" rows="8" class="block p-2.5 w-full text-sm text-gray-200 bg-gray-700 rounded-lg border border-gray-600 focus:ring-teal-500 focus:border-teal-500"></textarea>
                        </div>
                        <button id="update-wheel-btn" class="w-full bg-green-600 hover:bg-green-700 text-white font-bold py-3 px-4 rounded-lg transition">
                            ホイールを更新
                        </button>
                    </div>
                </div>
            </div>
        </main>
    </div>

    <!-- Message Modal -->
    <div id="message-modal" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center p-4 z-50 hidden">
        <div class="bg-gray-800 rounded-xl shadow-2xl p-8 max-w-sm text-center border border-gray-700">
            <h2 id="modal-title" class="text-2xl font-bold mb-4"></h2>
            <p id="modal-body" class="text-gray-300 mb-6"></p>
            <button id="modal-close-btn" class="w-full text-white bg-blue-600 hover:bg-blue-700 font-medium rounded-lg text-sm px-5 py-3">閉じる</button>
        </div>
    </div>

    <!-- Firebase SDK -->
    <script type="module">
        import { initializeApp } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-app.js";
        import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-auth.js";
        import { getFirestore, doc, getDoc, setDoc, updateDoc, onSnapshot, arrayUnion, arrayRemove } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-firestore.js";
        import { setLogLevel } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-firestore.js";

        const firebaseConfig = typeof __firebase_config !== 'undefined' 
            ? JSON.parse(__firebase_config)
            : {
                apiKey: "AIzaSyBL3USs4_BgCBM1_eFrOA0Htmjj2FWa5XM",
                authDomain: "app-and-game.firebaseapp.com",
                projectId: "app-and-game",
                storageBucket: "app-and-game.firebasestorage.app",
                messagingSenderId: "670250047171",
                appId: "1:670250047171:web:ca90d4df93674be6fef476",
                measurementId: "G-4KR5Q5RCQV"
            };
        const appId = typeof __app_id !== 'undefined' ? __app_id : firebaseConfig.projectId;
        const initialAuthToken = typeof __initial_auth_token !== 'undefined' ? __initial_auth_token : null;

        const app = initializeApp(firebaseConfig);
        const db = getFirestore(app);
        const auth = getAuth(app);
        setLogLevel('debug');

        // --- DOM ELEMENTS ---
        const lobbyEl = document.getElementById('lobby');
        const gameContainerEl = document.getElementById('game-container');
        const canvas = document.getElementById('wheel-canvas');
        const ctx = canvas.getContext('2d');
        const spinBtn = document.getElementById('spin-btn');
        const resultDisplay = document.getElementById('result-display');
        const customItemsInput = document.getElementById('custom-items-input');
        const updateWheelBtn = document.getElementById('update-wheel-btn');
        const usePlayersBtn = document.getElementById('use-players-btn');
        const createRoomBtn = document.getElementById('createRoomBtn');
        const joinRoomBtn = document.getElementById('joinRoomBtn');
        const leaveRoomBtn = document.getElementById('leaveRoomBtn');
        const copyRoomIdBtn = document.getElementById('copyRoomIdBtn');
        const userIdDisplay = document.getElementById('userIdDisplay');
        const roomIdDisplay = document.getElementById('roomIdDisplay');
        const playerListEl = document.getElementById('player-list');
        const playerCountEl = document.getElementById('player-count');
        const hostControlsEl = document.getElementById('host-controls');
        const modal = document.getElementById('message-modal');
        const modalTitle = document.getElementById('modal-title');
        const modalBody = document.getElementById('modal-body');
        const modalCloseBtn = document.getElementById('modal-close-btn');

        // --- GAME STATE ---
        let currentRoomId = null;
        let unsubscribeRoom = null;
        let isHost = false;
        let isSpinning = false;
        let lastKnownSpinTime = null;
        const colors = ["#ef4444", "#f97316", "#eab308", "#84cc16", "#22c55e", "#14b8a6", "#06b6d4", "#3b82f6", "#8b5cf6", "#d946ef", "#ec4899", "#78716c"];

        // --- AUTHENTICATION ---
        onAuthStateChanged(auth, async (user) => {
            if (user) {
                userIdDisplay.textContent = user.uid;
            } else {
                try {
                    if (initialAuthToken) {
                        await signInWithCustomToken(auth, initialAuthToken);
                    } else {
                        await signInAnonymously(auth);
                    }
                } catch (error) {
                    console.error("ログインエラー:", error);
                    showMessage("エラー", "ユーザー認証に失敗しました。ページを再読み込みしてください。");
                }
            }
        });

        // --- UI FUNCTIONS ---
        function showMessage(title, body) {
            modalTitle.textContent = title;
            modalBody.textContent = body;
            modal.classList.remove('hidden');
        }
        function showLobbyView() {
            gameContainerEl.classList.add('hidden');
            lobbyEl.classList.remove('hidden');
            if (unsubscribeRoom) {
                unsubscribeRoom();
                unsubscribeRoom = null;
            }
            currentRoomId = null;
            isHost = false;
        }
        function showGameView(roomId) {
            currentRoomId = roomId;
            roomIdDisplay.value = roomId;
            lobbyEl.classList.add('hidden');
            gameContainerEl.classList.remove('hidden');
        }

        // --- WHEEL DRAWING ---
        function drawWheel(segments) {
            const numSegments = segments ? segments.length : 0;
            if (numSegments === 0) {
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                return;
            };
            const anglePerSegment = (2 * Math.PI) / numSegments;
            const centerX = canvas.width / 2;
            const centerY = canvas.height / 2;
            const radius = canvas.width / 2 - 10;

            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.font = '16px "Noto Sans JP", sans-serif';
            
            segments.forEach((segment, i) => {
                const startAngle = i * anglePerSegment;
                ctx.beginPath();
                ctx.moveTo(centerX, centerY);
                ctx.arc(centerX, centerY, radius, startAngle, startAngle + anglePerSegment);
                ctx.closePath();
                ctx.fillStyle = colors[i % colors.length];
                ctx.fill();
                ctx.strokeStyle = '#4b5563';
                ctx.lineWidth = 3;
                ctx.stroke();

                ctx.save();
                ctx.translate(centerX, centerY);
                ctx.rotate(startAngle + anglePerSegment / 2);
                ctx.textAlign = "right";
                ctx.fillStyle = "#ffffff";
                ctx.font = 'bold 14px "Noto Sans JP"';
                let text = segment.length > 15 ? segment.substring(0, 14) + '...' : segment;
                ctx.fillText(text, radius - 15, 0);
                ctx.restore();
            });
        }

        // --- FIREBASE & GAME LOGIC ---
        async function createNewRoom() {
            const localPlayerName = document.getElementById('playerName').value.trim();
            if (!localPlayerName) {
                showMessage("エラー", "名前を入力してください。");
                return;
            }
            if (!auth.currentUser) {
                showMessage("エラー", "ユーザーが認証されていません。しばらく待ってからもう一度お試しください。");
                return;
            }
            const currentUserId = auth.currentUser.uid;

            createRoomBtn.disabled = true;
            createRoomBtn.textContent = '作成中...';

            try {
                let newRoomId;
                let roomExists = true;
                while (roomExists) {
                    newRoomId = Math.floor(100000 + Math.random() * 900000).toString();
                    const roomDocRef = doc(db, `artifacts/${appId}/public/data/lucky-wheel-sessions/${newRoomId}`);
                    const docSnap = await getDoc(roomDocRef);
                    roomExists = docSnap.exists();
                }

                const newRoomData = {
                    hostId: currentUserId,
                    players: [{ id: currentUserId, name: localPlayerName }],
                    wheelItems: [localPlayerName],
                    status: 'waiting',
                    currentRotation: 0,
                    targetRotation: 0,
                    result: '',
                    lastSpinTimestamp: null,
                    createdAt: new Date().toISOString()
                };

                await setDoc(doc(db, `artifacts/${appId}/public/data/lucky-wheel-sessions/${newRoomId}`), newRoomData);
                isHost = true;
                listenToRoomUpdates(newRoomId);
            } catch (error) {
                console.error("ルーム作成エラー: ", error);
                showMessage("エラー", "ルームを作成できませんでした。もう一度お試しください。");
            } finally {
                createRoomBtn.disabled = false;
                createRoomBtn.textContent = '新しいルームを作成';
            }
        }

        async function joinExistingRoom() {
            const localPlayerName = document.getElementById('playerName').value.trim();
            if (!localPlayerName) {
                showMessage("エラー", "名前を入力してください。");
                return;
            }
            const roomIdToJoin = document.getElementById('joinRoomId').value.trim();
            if (!roomIdToJoin) {
                showMessage("エラー", "ルームIDを入力してください。");
                return;
            }
            if (!auth.currentUser) {
                showMessage("エラー", "ユーザーが認証されていません。しばらく待ってからもう一度お試しください。");
                return;
            }
            const currentUserId = auth.currentUser.uid;

            joinRoomBtn.disabled = true;
            const roomDocRef = doc(db, `artifacts/${appId}/public/data/lucky-wheel-sessions/${roomIdToJoin}`);
            
            try {
                const docSnap = await getDoc(roomDocRef);
                if (!docSnap.exists()) {
                    showMessage("エラー", "このIDのルームは見つかりませんでした。");
                    return;
                }

                const roomData = docSnap.data();
                if (roomData.players.length >= 20 && !roomData.players.some(p => p.id === currentUserId)) {
                    showMessage("エラー", "このルームは満員です。");
                    return;
                }
                if (!roomData.players.some(p => p.id === currentUserId)) {
                    await updateDoc(roomDocRef, {
                        players: arrayUnion({ id: currentUserId, name: localPlayerName })
                    });
                }
                isHost = (roomData.hostId === currentUserId);
                listenToRoomUpdates(roomIdToJoin);
            } catch (error) {
                console.error("ルーム参加エラー: ", error);
                showMessage("エラー", "ルームに参加できませんでした。IDを確認してください。");
            } finally {
                joinRoomBtn.disabled = false;
            }
        }

        async function leaveCurrentRoom() {
            if (!currentRoomId || !auth.currentUser) return;
            const currentUserId = auth.currentUser.uid;
            const roomDocRef = doc(db, `artifacts/${appId}/public/data/lucky-wheel-sessions/${currentRoomId}`);
            try {
                const docSnap = await getDoc(roomDocRef);
                if (docSnap.exists()) {
                    const roomData = docSnap.data();
                    const playerToRemove = roomData.players.find(p => p.id === currentUserId);
                    if (playerToRemove) {
                         await updateDoc(roomDocRef, {
                            players: arrayRemove(playerToRemove)
                        });
                    }
                }
            } catch (error) {
                console.error("ルーム退出エラー: ", error);
            } finally {
                showLobbyView();
            }
        }

        function listenToRoomUpdates(roomId) {
            showGameView(roomId);
            const roomDocRef = doc(db, `artifacts/${appId}/public/data/lucky-wheel-sessions/${roomId}`);
            unsubscribeRoom = onSnapshot(roomDocRef, (docSnap) => {
                if (!docSnap.exists()) {
                    showMessage("お知らせ", "ルームが閉鎖されたか、存在しません。");
                    showLobbyView();
                    return;
                }
                const roomData = docSnap.data();
                const currentUserId = auth.currentUser ? auth.currentUser.uid : null;
                isHost = (roomData.hostId === currentUserId);
                
                // Update player list
                playerListEl.innerHTML = '';
                roomData.players.forEach(p => {
                    const li = document.createElement('li');
                    li.className = `p-2 rounded-md flex justify-between items-center ${p.id === roomData.hostId ? 'bg-yellow-900/50' : 'bg-gray-700'}`;
                    li.innerHTML = `<span>${p.name}</span> ${p.id === roomData.hostId ? '<span class="text-xs font-bold text-yellow-400">ホスト</span>' : ''}`;
                    playerListEl.appendChild(li);
                });
                playerCountEl.textContent = roomData.players.length;

                // Update wheel
                drawWheel(roomData.wheelItems);

                // Update host controls
                hostControlsEl.classList.toggle('hidden', !isHost);
                spinBtn.disabled = !isHost || isSpinning || !roomData.wheelItems || roomData.wheelItems.length < 2;
                
                // Handle spin animation
                if (roomData.lastSpinTimestamp && roomData.lastSpinTimestamp !== lastKnownSpinTime) {
                    isSpinning = true;
                    lastKnownSpinTime = roomData.lastSpinTimestamp;
                    spinBtn.disabled = true;
                    resultDisplay.innerHTML = '';
                    canvas.style.transform = `rotate(${roomData.targetRotation}deg)`;

                    setTimeout(() => {
                        isSpinning = false;
                        spinBtn.disabled = !isHost;
                        if (roomData.result) {
                            resultDisplay.innerHTML = `<p class="text-xl font-bold text-amber-400 animate-pulse">結果: <span class="text-2xl">${roomData.result}</span></p>`;
                        }
                    }, 6000);
                }
            });
        }
        
        async function handleSpin() {
            if (!isHost || !currentRoomId || isSpinning) return;
            
            const roomDocRef = doc(db, `artifacts/${appId}/public/data/lucky-wheel-sessions/${currentRoomId}`);
            const docSnap = await getDoc(roomDocRef);
            if (!docSnap.exists()) return;
            const roomData = docSnap.data();

            if (!roomData.wheelItems || roomData.wheelItems.length < 2) {
                showMessage("エラー", "スピンするには少なくとも2つのオプションが必要です。");
                return;
            }

            const randomSpins = Math.floor(Math.random() * 6) + 8;
            const randomAngle = Math.random() * 360;
            const currentRotation = roomData.currentRotation || 0;
            const targetRotation = currentRotation + (randomSpins * 360) + randomAngle;

            const finalAngle = targetRotation % 360;
            const winningAngle = (270 - finalAngle + 360) % 360;
            const anglePerSegment = 360 / roomData.wheelItems.length;
            const winningIndex = Math.floor(winningAngle / anglePerSegment);
            const winner = roomData.wheelItems[winningIndex];

            await updateDoc(roomDocRef, {
                targetRotation: targetRotation,
                currentRotation: finalAngle,
                lastSpinTimestamp: new Date().getTime(),
                result: winner
            });
        }

        async function updateWheelItems(newItems) {
            if (!isHost || !currentRoomId) return;
            const roomDocRef = doc(db, `artifacts/${appId}/public/data/lucky-wheel-sessions/${currentRoomId}`);
            await updateDoc(roomDocRef, {
                wheelItems: newItems
            });
        }

        // --- EVENT LISTENERS ---
        createRoomBtn.addEventListener('click', createNewRoom);
        joinRoomBtn.addEventListener('click', joinExistingRoom);
        leaveRoomBtn.addEventListener('click', leaveCurrentRoom);
        
        updateWheelBtn.addEventListener('click', () => {
             const items = customItemsInput.value.split('\n').map(item => item.trim()).filter(item => item !== '');
             if (items.length < 2) {
                 showMessage("注意", "少なくとも2つのオプションを入力してください。");
                 return;
             }
             updateWheelItems(items);
        });

        usePlayersBtn.addEventListener('click', async () => {
            if (!isHost || !currentRoomId) return;
            const roomDocRef = doc(db, `artifacts/${appId}/public/data/lucky-wheel-sessions/${currentRoomId}`);
            const docSnap = await getDoc(roomDocRef);
            if(docSnap.exists()){
                const players = docSnap.data().players;
                if(players.length < 2){
                    showMessage("注意", "ルームには少なくとも2人のプレイヤーが必要です。");
                    return;
                }
                const playerNames = players.map(p => p.name);
                updateWheelItems(playerNames);
            }
        });

        spinBtn.addEventListener('click', handleSpin);
        
        copyRoomIdBtn.addEventListener('click', () => {
            const gameId = roomIdDisplay.value;
            const textArea = document.createElement("textarea");
            textArea.value = gameId;
            document.body.appendChild(textArea);
            textArea.select();
            try {
                document.execCommand('copy');
                showMessage("成功", `ルームIDをコピーしました: ${gameId}`);
            } catch (err) {
                showMessage("エラー", "IDをコピーできませんでした。");
            }
            document.body.removeChild(textArea);
        });
        
        modalCloseBtn.addEventListener('click', () => modal.classList.add('hidden'));

    </script>
</body>
</html>
]]></content:encoded>
					
					<wfw:commentRss>https://dejitarumirai.com/archives/4236/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>五目並べ 2人</title>
		<link>https://dejitarumirai.com/archives/4233</link>
					<comments>https://dejitarumirai.com/archives/4233#respond</comments>
		
		<dc:creator><![CDATA[deji]]></dc:creator>
		<pubDate>Sat, 05 Jul 2025 15:09:41 +0000</pubDate>
				<category><![CDATA[ゲーム]]></category>
		<guid isPermaLink="false">https://dejitarumirai.com/?p=4233</guid>

					<description><![CDATA[五目並べオンライン 五目並べオ [&#8230;]]]></description>
										<content:encoded><![CDATA[<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>五目並べオンライン</title>
    
    <!-- Tailwind CSS for styling -->
    <script src="https://cdn.tailwindcss.com"></script>
    
    <!-- Google Fonts: Inter -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Noto+Sans+JP:wght@400;500;700&display=swap" rel="stylesheet">

    <style>
        /* Custom styles for Dark Mode */
        body {
            font-family: 'Noto Sans JP', 'Inter', sans-serif;
            background-color: #111827; /* bg-gray-900 */
            color: #D1D5DB; /* text-gray-300 */
        }
        h1, h2, h3 {
            color: #F9FAFB; /* text-gray-50 */
        }
        /* Piece styles (colors kept for visibility) */
        .cell .piece-x {
            color: #10B981; /* emerald-500 */
            font-weight: bold;
            font-size: clamp(1rem, 2.5vw, 2rem);
            line-height: 1;
        }
        .cell .piece-o {
            color: #EF4444; /* red-500 */
            font-weight: bold;
            font-size: clamp(1rem, 2.5vw, 2rem);
            line-height: 1;
        }
        /* Hover effect for cells */
        .cell:not(.occupied):hover {
            background-color: #374151; /* bg-gray-700 */
        }
        /* Disabled board state */
        .board-disabled {
            pointer-events: none;
            opacity: 0.6;
        }
        /* Modal styles */
        .modal {
            transition: opacity 0.25s ease;
        }
        /* Custom input styles for dark mode */
        .dark-input {
            background-color: #374151; /* bg-gray-700 */
            border-color: #4B5563; /* border-gray-600 */
            color: #F9FAFB; /* text-gray-50 */
        }
        .dark-input::placeholder {
            color: #6B7280; /* placeholder-gray-500 */
        }
        .dark-input:focus {
            --tw-ring-color: #3B82F6; /* ring-blue-500 */
            border-color: #3B82F6; /* border-blue-500 */
        }
    </style>
</head>
<body class="flex items-center justify-center min-h-screen p-4">

    <div class="w-full max-w-4xl mx-auto">
        <h1 class="text-4xl font-bold text-center mb-2">五目並べオンライン</h1>
        <p class="text-center text-gray-400 mb-6">先に五つ並べた方の勝ちです</p>

        <!-- Lobby Section -->
        <div id="lobby" class="bg-gray-800 p-8 rounded-xl shadow-lg border border-gray-700 max-w-md mx-auto">
            <div class="mb-4">
                <label for="playerName" class="block mb-2 text-sm font-medium text-gray-300">あなたの名前</label>
                <input type="text" id="playerName" class="dark-input text-sm rounded-lg block w-full p-2.5" placeholder="名前を入力してください" required>
            </div>
            <button id="createGameBtn" class="w-full text-white bg-emerald-600 hover:bg-emerald-700 focus:ring-4 focus:outline-none focus:ring-emerald-800 font-medium rounded-lg text-sm px-5 py-3 text-center mb-3">新しいルームを作成</button>
            <div class="relative flex py-3 items-center">
                <div class="flex-grow border-t border-gray-600"></div>
                <span class="flex-shrink mx-4 text-gray-400">または</span>
                <div class="flex-grow border-t border-gray-600"></div>
            </div>
            <div class="flex gap-2">
                <input type="text" id="joinGameId" class="dark-input text-sm rounded-lg block w-full p-2.5" placeholder="ルームID (6桁) を入力">
                <button id="joinGameBtn" class="text-white bg-blue-600 hover:bg-blue-700 focus:ring-4 focus:outline-none focus:ring-blue-800 font-medium rounded-lg text-sm px-5 py-3">ルームに参加</button>
            </div>
             <div class="mt-4 text-center text-xs text-gray-500">
                あなたのユーザーID: <span id="userIdDisplay" class="font-mono">読み込み中...</span>
            </div>
        </div>

        <!-- Game Section -->
        <div id="game-container" class="hidden w-full">
            <div class="flex flex-col lg:flex-row gap-6 items-start justify-center">
                <!-- Game Info Panel -->
                <div class="w-full lg:w-72 bg-gray-800 p-4 rounded-xl shadow-lg border border-gray-700 flex-shrink-0">
                    <h3 class="text-lg font-semibold mb-3">ゲーム情報</h3>
                    <p class="text-sm text-gray-400">ルームID:</p>
                    <div class="flex items-center gap-2 mb-3">
                        <input readonly id="gameIdDisplay" class="w-full bg-gray-700 font-mono text-lg p-2 rounded-md border border-gray-600 text-center tracking-widest text-gray-50"/>
                        <button id="copyGameIdBtn" class="p-2 bg-gray-700 hover:bg-gray-600 rounded-md text-gray-300">
                            <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg>
                        </button>
                    </div>

                    <div id="playerInfo" class="space-y-2 text-sm"></div>
                    <p id="turn-indicator" class="mt-4 text-center font-semibold text-lg p-3 rounded-lg bg-gray-700 text-gray-300"></p>
                    <button id="resetGameBtn" class="w-full mt-4 text-white bg-red-600 hover:bg-red-700 focus:ring-4 focus:outline-none focus:ring-red-800 font-medium rounded-lg text-sm px-5 py-3 text-center hidden">もう一度プレイ</button>
                     <button id="leaveGameBtn" class="w-full mt-2 text-white bg-gray-600 hover:bg-gray-500 focus:ring-4 focus:outline-none focus:ring-gray-700 font-medium rounded-lg text-sm px-5 py-3 text-center">ルームを退出</button>
                </div>
                <!-- Game Board -->
                <div id="board" class="grid w-full aspect-square bg-gray-800 rounded-xl shadow-lg border border-gray-700" style="grid-template-columns: repeat(15, minmax(0, 1fr)); grid-template-rows: repeat(15, minmax(0, 1fr));">
                    <!-- Cells will be generated by JS -->
                </div>
            </div>
        </div>
    </div>

    <!-- Message Modal -->
    <div id="message-modal" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center p-4 z-50 hidden">
        <div class="bg-gray-800 rounded-xl shadow-2xl p-8 max-w-sm text-center border border-gray-700">
            <h2 id="modal-title" class="text-2xl font-bold mb-4"></h2>
            <p id="modal-body" class="text-gray-300 mb-6"></p>
            <button id="modal-close-btn" class="w-full text-white bg-blue-600 hover:bg-blue-700 focus:ring-4 focus:outline-none focus:ring-blue-800 font-medium rounded-lg text-sm px-5 py-3">閉じる</button>
        </div>
    </div>

    <!-- Firebase SDK -->
    <script type="module">
        // Import functions from Firebase SDKs
        import { initializeApp } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-app.js";
        import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-auth.js";
        import { getFirestore, doc, getDoc, setDoc, updateDoc, onSnapshot, collection } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-firestore.js";
        import { setLogLevel } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-firestore.js";

        // PASTE YOUR FIREBASE CONFIGURATION THAT YOU COPIED IN STEP 3 HERE
        const firebaseConfig = {
            apiKey: "AIzaSyBL3USs4_BgCBM1_eFrOA0Htmjj2FWa5XM",
            authDomain: "app-and-game.firebaseapp.com",
            projectId: "app-and-game",
            storageBucket: "app-and-game.firebasestorage.app",
            messagingSenderId: "670250047171",
            appId: "1:670250047171:web:ca90d4df93674be6fef476",
            measurementId: "G-4KR5Q5RCQV"
        };
        // The lines below are kept the same or slightly adjusted
        const appId = firebaseConfig.projectId; // Use projectId as the identifier
        const initialAuthToken = null; // Not needed for local setup

        const app = initializeApp(firebaseConfig);
        const db = getFirestore(app);
        const auth = getAuth(app);
        setLogLevel('debug');

        // --- DOM ELEMENTS ---
        const lobbyEl = document.getElementById('lobby');
        const gameContainerEl = document.getElementById('game-container');
        const boardEl = document.getElementById('board');
        const turnIndicatorEl = document.getElementById('turn-indicator');
        const playerInfoEl = document.getElementById('playerInfo');
        const createGameBtn = document.getElementById('createGameBtn');
        const joinGameBtn = document.getElementById('joinGameBtn');
        const resetGameBtn = document.getElementById('resetGameBtn');
        const leaveGameBtn = document.getElementById('leaveGameBtn');
        const copyGameIdBtn = document.getElementById('copyGameIdBtn');
        const userIdDisplay = document.getElementById('userIdDisplay');
        const gameIdDisplay = document.getElementById('gameIdDisplay');
        const modal = document.getElementById('message-modal');
        const modalTitle = document.getElementById('modal-title');
        const modalBody = document.getElementById('modal-body');
        const modalCloseBtn = document.getElementById('modal-close-btn');

        // --- GAME STATE ---
        const BOARD_SIZE = 15;
        let userId = null;
        let playerName = '';
        let currentGameId = null;
        let playerSymbol = null;
        let unsubscribeGame = null;
        let gameActive = false;

        // --- AUTHENTICATION ---
        onAuthStateChanged(auth, async (user) => {
            if (user) {
                userId = user.uid;
                userIdDisplay.textContent = userId;
                enableLobby();
            } else {
                try {
                    if (initialAuthToken) {
                        await signInWithCustomToken(auth, initialAuthToken);
                    } else {
                        await signInAnonymously(auth);
                    }
                } catch (error) {
                    console.error("Error signing in:", error);
                    showMessage("エラー", "ユーザー認証に失敗しました。ページを再読み込みしてください。");
                }
            }
        });

        // --- UI FUNCTIONS ---
        function enableLobby() {
            createGameBtn.disabled = false;
            joinGameBtn.disabled = false;
            createGameBtn.textContent = '新しいルームを作成';
        }
        
        function showMessage(title, body) {
            modalTitle.textContent = title;
            modalBody.textContent = body;
            modal.classList.remove('hidden');
        }

        function hideMessage() {
            modal.classList.add('hidden');
        }

        function showGameView() {
            lobbyEl.classList.add('hidden');
            gameContainerEl.classList.remove('hidden');
        }

        function showLobbyView() {
            gameContainerEl.classList.add('hidden');
            lobbyEl.classList.remove('hidden');
            if (unsubscribeGame) {
                unsubscribeGame();
                unsubscribeGame = null;
            }
            currentGameId = null;
            playerSymbol = null;
            gameActive = false;
        }

        // --- GAME LOGIC ---

        function renderBoard(boardState, currentPlayer) {
            boardEl.innerHTML = '';
            boardEl.classList.toggle('board-disabled', !gameActive || currentPlayer !== playerSymbol);

            for (let r = 0; r < BOARD_SIZE; r++) {
                for (let c = 0; c < BOARD_SIZE; c++) {
                    const cell = document.createElement('div');
                    cell.className = 'cell flex items-center justify-center w-full h-full border border-gray-700 cursor-pointer transition-colors duration-150';
                    cell.dataset.row = r;
                    cell.dataset.col = c;

                    const piece = boardState[r][c];
                    if (piece) {
                        cell.classList.add('occupied');
                        const pieceEl = document.createElement('span');
                        pieceEl.className = piece === 'X' ? 'piece-x' : 'piece-o';
                        pieceEl.textContent = piece;
                        cell.appendChild(pieceEl);
                    } else {
                        cell.addEventListener('click', () => handleCellClick(r, c));
                    }
                    boardEl.appendChild(cell);
                }
            }
        }
        
        function updateGameInfo(gameData) {
            playerInfoEl.innerHTML = '';
            const p1 = gameData.players.p1;
            const p2 = gameData.players.p2;

            const p1_html = `<div class="flex items-center justify-between p-2 rounded-lg transition-colors ${gameData.currentPlayer === 'X' ? 'bg-emerald-900/50 text-emerald-300' : 'bg-gray-800'}"><span>(X) ${p1.name}</span><span class="font-mono text-xs text-gray-500">${p1.id.substring(0,6)}..</span></div>`;
            playerInfoEl.insertAdjacentHTML('beforeend', p1_html);

            if (p2) {
                 const p2_html = `<div class="flex items-center justify-between p-2 rounded-lg transition-colors ${gameData.currentPlayer === 'O' ? 'bg-red-900/50 text-red-300' : 'bg-gray-800'}"><span>(O) ${p2.name}</span><span class="font-mono text-xs text-gray-500">${p2.id.substring(0,6)}..</span></div>`;
                 playerInfoEl.insertAdjacentHTML('beforeend', p2_html);
            } else {
                 playerInfoEl.insertAdjacentHTML('beforeend', `<div class="p-2 text-center text-gray-500 border border-dashed border-gray-600 rounded-lg">プレイヤー2を待っています...</div>`);
            }

            if (gameData.status === 'active') {
                if (gameData.currentPlayer === playerSymbol) {
                    turnIndicatorEl.textContent = "あなたの番です！";
                    turnIndicatorEl.className = 'mt-4 text-center font-semibold text-lg p-3 rounded-lg bg-emerald-600 text-white';
                } else {
                    turnIndicatorEl.textContent = "相手の番です...";
                    turnIndicatorEl.className = 'mt-4 text-center font-semibold text-lg p-3 rounded-lg bg-red-600 text-white';
                }
            } else if (gameData.status === 'waiting') {
                turnIndicatorEl.textContent = "他のプレイヤーを待っています...";
                turnIndicatorEl.className = 'mt-4 text-center font-semibold text-lg p-3 rounded-lg bg-gray-700 text-gray-300';
            } else if (gameData.status.startsWith('win')) {
                 const winnerSymbol = gameData.status.split('_')[1];
                 const winner = winnerSymbol === 'X' ? gameData.players.p1 : gameData.players.p2;
                 turnIndicatorEl.textContent = `${winner.name} (${winnerSymbol}) の勝ちです！`;
                 turnIndicatorEl.className = 'mt-4 text-center font-semibold text-lg p-3 rounded-lg bg-yellow-500 text-yellow-900';
            } else if (gameData.status === 'draw') {
                turnIndicatorEl.textContent = "引き分けです！";
                turnIndicatorEl.className = 'mt-4 text-center font-semibold text-lg p-3 rounded-lg bg-gray-600 text-gray-200';
            }
        }
        
        async function generateUniqueGameId() {
            let gameId;
            let attempts = 0;
            const maxAttempts = 20; // Prevent infinite loops

            while (attempts < maxAttempts) {
                gameId = Math.floor(100000 + Math.random() * 900000).toString();
                const gameDocRef = doc(db, `artifacts/${appId}/public/data/caro-games`, gameId);
                const docSnap = await getDoc(gameDocRef);

                if (!docSnap.exists()) {
                    return gameId; // Found an unused ID
                }
                attempts++;
            }
            throw new Error("Failed to generate a unique game ID.");
        }

        async function createNewGame() {
            playerName = document.getElementById('playerName').value.trim();
            if (!playerName) {
                showMessage("エラー", "名前を入力してください。");
                return;
            }
            if (!userId) {
                showMessage("エラー", "ユーザーIDを取得できませんでした。もう一度お試しください。");
                return;
            }

            createGameBtn.disabled = true;
            createGameBtn.textContent = '作成中...';

            const initialBoard = Array(BOARD_SIZE).fill(null).map(() => Array(BOARD_SIZE).fill(null));
            
            try {
                const newGameId = await generateUniqueGameId();
                const gameDocRef = doc(db, `artifacts/${appId}/public/data/caro-games`, newGameId);

                await setDoc(gameDocRef, {
                    board: JSON.stringify(initialBoard),
                    players: { p1: { id: userId, name: playerName } },
                    currentPlayer: 'X',
                    status: 'waiting',
                    createdAt: new Date().toISOString(),
                });

                currentGameId = newGameId;
                playerSymbol = 'X';
                listenForGameUpdates(currentGameId);
                showGameView();
                gameIdDisplay.value = currentGameId;

            } catch (error) {
                console.error("Error creating game: ", error);
                showMessage("エラー", "ゲームルームを作成できませんでした。もう一度お試しください。");
                createGameBtn.disabled = false;
                createGameBtn.textContent = '新しいルームを作成';
            }
        }

        async function joinExistingGame() {
            playerName = document.getElementById('playerName').value.trim();
            if (!playerName) {
                showMessage("エラー", "名前を入力してください。");
                return;
            }
            
            const gameIdToJoin = document.getElementById('joinGameId').value.trim();
            if (!gameIdToJoin) {
                showMessage("エラー", "ルームIDを入力してください。");
                return;
            }

            joinGameBtn.disabled = true;
            const gameDocRef = doc(db, `artifacts/${appId}/public/data/caro-games`, gameIdToJoin);
            
            try {
                const gameSnap = await getDoc(gameDocRef);
                if (!gameSnap.exists()) {
                    showMessage("エラー", "このIDのルームは見つかりませんでした。");
                    joinGameBtn.disabled = false;
                    return;
                }

                const gameData = gameSnap.data();
                if (gameData.players.p2 && gameData.players.p1.id !== userId && gameData.players.p2.id !== userId) {
                    showMessage("エラー", "このルームは満員です。");
                    joinGameBtn.disabled = false;
                    return;
                }
                
                if (!gameData.players.p2 && gameData.players.p1.id !== userId) {
                    await updateDoc(gameDocRef, {
                        'players.p2': { id: userId, name: playerName },
                        status: 'active'
                    });
                }
                
                currentGameId = gameIdToJoin;
                playerSymbol = gameData.players.p1.id === userId ? 'X' : 'O';
                listenForGameUpdates(currentGameId);
                showGameView();
                gameIdDisplay.value = currentGameId;

            } catch (error) {
                console.error("Error joining game: ", error);
                showMessage("エラー", "ルームに参加できませんでした。IDを確認してください。");
            } finally {
                joinGameBtn.disabled = false;
            }
        }

        function listenForGameUpdates(gameId) {
            if (unsubscribeGame) unsubscribeGame();
            const gameDocRef = doc(db, `artifacts/${appId}/public/data/caro-games`, gameId);
            unsubscribeGame = onSnapshot(gameDocRef, (docSnap) => {
                if (docSnap.exists()) {
                    const gameData = docSnap.data();
                    const boardState = JSON.parse(gameData.board);
                    
                    gameActive = gameData.status === 'active';
                    resetGameBtn.classList.toggle('hidden', gameData.status === 'active' || gameData.status === 'waiting');

                    renderBoard(boardState, gameData.currentPlayer);
                    updateGameInfo(gameData);
                } else {
                    showMessage("お知らせ", "ゲームルームが閉鎖されたか、存在しません。");
                    showLobbyView();
                }
            });
        }

        async function handleCellClick(row, col) {
            if (!gameActive || !currentGameId) return;

            const gameDocRef = doc(db, `artifacts/${appId}/public/data/caro-games`, currentGameId);
            const gameSnap = await getDoc(gameDocRef);
            if (!gameSnap.exists()) return;

            const gameData = gameSnap.data();
            const boardState = JSON.parse(gameData.board);

            if (gameData.currentPlayer === playerSymbol && boardState[row][col] === null) {
                boardState[row][col] = playerSymbol;
                
                let newStatus = 'active';
                let nextPlayer = playerSymbol === 'X' ? 'O' : 'X';

                if (checkWin(boardState, playerSymbol)) {
                    newStatus = `win_${playerSymbol}`;
                    gameActive = false;
                } else if (checkDraw(boardState)) {
                    newStatus = 'draw';
                    gameActive = false;
                }

                await updateDoc(gameDocRef, {
                    board: JSON.stringify(boardState),
                    currentPlayer: nextPlayer,
                    status: newStatus
                });
            }
        }
        
        async function resetGame() {
            if (!currentGameId) return;
            const initialBoard = Array(BOARD_SIZE).fill(null).map(() => Array(BOARD_SIZE).fill(null));
            const gameDocRef = doc(db, `artifacts/${appId}/public/data/caro-games`, currentGameId);
            
            await updateDoc(gameDocRef, {
                board: JSON.stringify(initialBoard),
                currentPlayer: 'X',
                status: 'active'
            });
        }

        function checkWin(board, player) {
            for (let r = 0; r < BOARD_SIZE; r++) {
                for (let c = 0; c < BOARD_SIZE; c++) {
                    // Check horizontal
                    if (c <= BOARD_SIZE - 5) {
                        if (board[r][c] === player && board[r][c+1] === player && board[r][c+2] === player && board[r][c+3] === player && board[r][c+4] === player) return true;
                    }
                    // Check vertical
                    if (r <= BOARD_SIZE - 5) {
                        if (board[r][c] === player && board[r+1][c] === player && board[r+2][c] === player && board[r+3][c] === player && board[r+4][c] === player) return true;
                    }
                    // Check diagonal (down-right)
                    if (r <= BOARD_SIZE - 5 && c <= BOARD_SIZE - 5) {
                        if (board[r][c] === player && board[r+1][c+1] === player && board[r+2][c+2] === player && board[r+3][c+3] === player && board[r+4][c+4] === player) return true;
                    }
                    // Check diagonal (up-right)
                    if (r >= 4 && c <= BOARD_SIZE - 5) {
                        if (board[r][c] === player && board[r-1][c+1] === player && board[r-2][c+2] === player && board[r-3][c+3] === player && board[r-4][c+4] === player) return true;
                    }
                }
            }
            return false;
        }

        function checkDraw(board) {
            return board.every(row => row.every(cell => cell !== null));
        }

        // --- EVENT LISTENERS ---
        createGameBtn.addEventListener('click', createNewGame);
        joinGameBtn.addEventListener('click', joinExistingGame);
        resetGameBtn.addEventListener('click', resetGame);
        leaveGameBtn.addEventListener('click', showLobbyView);
        modalCloseBtn.addEventListener('click', hideMessage);
        
        copyGameIdBtn.addEventListener('click', () => {
            const gameId = gameIdDisplay.value;
            const textArea = document.createElement("textarea");
            textArea.value = gameId;
            document.body.appendChild(textArea);
            textArea.select();
            try {
                document.execCommand('copy');
                showMessage("成功", `ルームIDをコピーしました: ${gameId}`);
            } catch (err) {
                showMessage("エラー", "IDをコピーできませんでした。");
            }
            document.body.removeChild(textArea);
        });

    </script>
</body>
</html>
]]></content:encoded>
					
					<wfw:commentRss>https://dejitarumirai.com/archives/4233/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
