コグノスケ


2026年5月3日

農家はREPLACE()されました、を9割クリア

目次: ゲーム

大昔にちょっとだけやって中断していたゲーム「農家はREPLACE()されました」を9割位までクリアしました。


「農家はREPLACE()されました」を9割位までクリア

実績の残り2個はランキングに載れ的なやつで、やる気が起きなかったのでこれにておしまいです。

全体的な流れ

序盤は適当にループを回して、文法系を全開放(list, dict, set_world_sizeなど)、迷路までの作物、複数ドローンを開放します。中盤は各種作物に最適化して組んだプログラムを動かす&放置&資源がたまったらレベルを適宜開放、を繰り返します。実装したらやることがなくなっちゃう。

プログラムは最大レベル(農場サイズ32x32、ドローン32機)に合わせて決め打ち実装した方が効率的で速いです。が、中盤は農場サイズやドローン数が少なく、32x32決め打ち実装だと動かなくて辛いです。個人的には農場サイズやドローン数が可変にできるように実装した方がゲーム進行的には楽でした。

カボチャとサボテンの実装を紹介します。一応、カボチャマスターとサボテンマスターは取れるはず、たぶん。

実装紹介(カボチャ)

各ドローンは1機1行を担当します。西から東の一方向にスキャンし続け、割れたカボチャがあったら植え直し、一列全部がきれいなカボチャになったらドローンの処理おしまいです。これを全行に対して実行します。

最初のドローンは北に移動しながらドローンを複製できるだけ複製して、複製の上限に達したら自分も1行担当します。全面カボチャになって、ドローンが最初のドローン1機だけになったら収穫します。

カボチャの実装

def cond():
	a = num_items(Items.Power) > MIN_POWER
	b = num_items(Items.Carrot) > MIN_CARROT
	c = num_items(Items.Pumpkin) < MAX_PUMPKIN
	return a and b and c


def get_pline():
	pline = 0
	for i in range(get_world_size()):
		if get_entity_type() == Entities.Pumpkin:
			pline += 1
		move(North)
	return pline


def drone():
	plist = []
	pnum = 0
	for i in range(get_world_size()):
		plist.append(False)
	while True:
		if get_entity_type() == Entities.Grass:
			till()

		if get_entity_type() == Entities.Pumpkin and can_harvest():
			if not plist[get_pos_x()]:
				plist[get_pos_x()] = True
				pnum += 1
				if pnum == get_world_size():
					return
		else:
			plant(Entities.Pumpkin)
			if get_water() < 0.5:
				use_item(Items.Water)
		move(East)


def pumpkin():
	clear()
	while cond():
		if not spawn_drone(drone):
			drone()
			if get_pline() == get_world_size():
				while num_drones() > 1:
					pass
				harvest()
		move(North)

動作を見たらすぐ気づかれますが、効率は良くないです。特に最初のドローンがスキャンする処理が長引くと、複数ドローンが出せない時間も長引いてしまいボトルネックになります。

実装紹介(サボテン)

全面にサボテンを植えて、東北側に大きなサボテン、南西側に小さなサボテンを集めるようにソートし、収穫します。ヒントにある通り、行ごとにソート、列ごとにソートの順に実行すれば全面ソート済みになります。

コードはこんな感じ。もっと短くできそうですけど気にしない。

サボテンの実装

def move_to(x, y):
	ws = get_world_size()
	dirx = East
	if (x - get_pos_x() + ws) % ws > (ws / 2):
		dirx = West
	diry = North
	if (y - get_pos_y() + ws) % ws > (ws / 2):
		diry = South
	while get_pos_x() != x:
		move(dirx)
	while get_pos_y() != y:
		move(diry)


def cond():
	a = num_items(Items.Power) > MIN_POWER
	b = num_items(Items.Pumpkin) > MIN_PUMPKIN
	c = num_items(Items.Cactus) < MAX_CACTUS
	return a and b and c


def is_ready(l):
	for i in range(get_world_size()):
		if l[i] == -1:
			return False
	return True


def is_sorted(l):
	for i in range(get_world_size() - 1):
		if l[i] > l[i + 1]:
			return False
	return True


def get_west_x():
	return (get_pos_x() - 1 + get_world_size()) % get_world_size()
def get_east_x():
	return (get_pos_x() + 1 + get_world_size()) % get_world_size()
def get_south_y():
	return (get_pos_y() - 1 + get_world_size()) % get_world_size()
def get_north_y():
	return (get_pos_y() + 1 + get_world_size()) % get_world_size()


def swap_item(l, a, b, dir):
	t = l[a]
	l[a] = l[b]
	l[b] = t
	swap(dir)


def plant_water():
	if get_entity_type() == Entities.Grass:
		till()
	plant(Entities.Cactus)
	if get_water() < 0.5:
		use_item(Items.Water)


def drone_x(st):
	move_to(0, st)
	xlist = []
	for i in range(get_world_size()):
		xlist.append(-1)

	while cond() and not is_ready(xlist):
		plant_water()
		xlist[get_pos_x()] = measure()
		move(East)

	move_to(0, st)
	vmax = get_world_size() - 1
	while cond():
		if is_sorted(xlist):
			return
		for i in range(vmax):
			if get_pos_x() > 0 and xlist[get_west_x()] > xlist[get_pos_x()]:
				swap_item(xlist, get_west_x(), get_pos_x(), West)
			move(East)
		for i in range(vmax):
			if get_pos_x() < get_world_size() - 1 and xlist[get_east_x()] < xlist[get_pos_x()]:
				swap_item(xlist, get_east_x(), get_pos_x(), East)
			move(West)
		move(East)
		vmax -= 2


def drone_y(st):
	move_to(st, 0)
	ylist = []
	for i in range(get_world_size()):
		ylist.append(-1)

	while cond() and not is_ready(ylist):
		ylist[get_pos_y()] = measure()
		move(North)

	vmax = get_world_size() - 1
	while cond():
		if is_sorted(ylist):
			return
		for i in range(vmax):
			if get_pos_y() > 0 and ylist[get_south_y()] > ylist[get_pos_y()]:
				swap_item(ylist, get_south_y(), get_pos_y(), South)
			move(North)
		for i in range(vmax):
			if get_pos_y() < get_world_size() - 1 and ylist[get_north_y()] < ylist[get_pos_y()]:
				swap_item(ylist, get_north_y(), get_pos_y(), North)
			move(South)
		move(North)
		vmax -= 2


def area(func, start, end):
	for i in range(start, end):
		spawn_drone(func, i + 1)
	func(start)
	while num_drones() > 1:
		pass


def cactus():
	clear()
	while cond():
		for i in range(0, get_world_size() - 1, max_drones()):
			area(drone_x, i, min(get_world_size() - 1, i + max_drones() - 1))
		for i in range(0, get_world_size() - 1, max_drones()):
			area(drone_y, i, min(get_world_size() - 1, i + max_drones() - 1))
		harvest()

ソートアルゴリズムは何でも良いですが、このゲームの大きな制約が2つあって、

  • 隣接するサボテン同士しか交換できない
  • ドローンの移動が遅い

おそらくバブルソート系のアルゴリズムを選択せざるを得ないでしょう。上記の実装ではシェイカーソートを使いました。シェイカーソートの存在は知ってましたが、実用的じゃないので実装したことなかったです。改めて実装してみるとなかなか新鮮でした。

編集者:すずき(2026/06/24 01:09)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2026年5月16日

「かに」で終わる形容動詞

Xで50音順に「かに」で終わる形容動詞(正確には連用形ですが)を並べている人がいて、面白そうなので自分もやってみました。

やってみるとわかるんですけど、かなり難しいです。ぱっと思いつく範囲では半分も埋まりませんでした。圧倒的敗北を喫して悔しかったので辞書を解禁して調べました。が、それでも敗北しました……。以下が戦いの結果です。複数ある場合は2〜3つくらい書いてます。

「かに」で終わる形容動詞の連用形
あ→明らかに、艶やかに
い→如何に、居丈高(いたけだか)に
う→麗(うら)らかに
え→
お→厳かに、穏やかに
か→軽やかに
き→煌(きら)びやかに
く→
け→絢爛豪華に
こ→腰高に、事細かに

さ→ささやかに
し→静かに、しなやかに
す→健やかに、速やかに
せ→背高に
そ→
た→確かに
ち→
つ→慎ましやかに、詳(つまび)らかに
て→
と→年若に、ど真ん中に

な→和やかに、なだらかに
に→賑やかに、俄かに
ぬ→
ね→根明に
の→長閑(のどか)に、伸びやかに
は→華やかに、遥かに、晴れやかに
ひ→密かに、秘めやかに
ふ→ふくよかに、不束(ふつつか)に
へ→
ほ→朗らかに

ま→実(まこと)しやかに、間近(まぢか)に、円(まろ)やかに
み→身近に、雅やかに
む→睦(むつ)まやかに
め→目近(めぢか)に
も→物静かに、物柔らかに
や→安らかに、吝(やぶさ)かに
ゆ→豊かに、緩やかに
よ→

ら→
り→
る→
れ→
ろ→
わ→わずかに、割高に

文語を採用するともう少し埋まりそうでしたが、なんだか負けた気分なので文語は外してます。

まず、ら行が全滅なことに驚きました。しかしまあ、ら行と「ぬ」「へ」「よ」はこれらの文字で始まる単語自体が少なそうで、該当する形容動詞がなくてもさほど不思議ではないです。しかし「え」「く」「そ」「ち」「て」は意外でした。本当にないのかなあ?私の探し方が悪いだけかもしれません。

たぶん「かに」で終わる形容動詞で全て埋めるのは不可能なんじゃなかろうか?うーん??

編集者:すずき(2026/05/21 02:14)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2026年5月22日

ZephyrのOut-of-treeアプリケーションその1 - 概要

目次: Zephyr

Zephyr RTOSはツリー内にアプリケーションを持ちます(以降、In-treeアプリケーションと呼びます)。zephyr/sample以下にサンプルアプリがあります。別の場所に自分のアプリケーションを足すこともできます。FreeRTOSもアプリケーションの横にカーネルのソースコードを置く形でした。RTOSだと普通なんでしょうね。

ZephyrのIn-treeアプリケーションのサンプル
zephyr
|-- LICENSES
|-- arch
|-- boards
|-- build
|-- cmake
|-- doc
|-- drivers
|-- dts
|-- include
|-- kernel
|-- lib
|-- misc
|-- modules
|-- samples    ★アプリケーションのサンプルはここにある★
|-- scripts
|-- share
|-- snippets
|-- soc
|-- submanifests
|-- subsys
`-- tests

In-treeアプリケーションは簡単に追加できて便利ですが、LinuxやUnixに慣れた人はアプリケーションとカーネルコードが混ざることに違和感を感じるでしょう。小さめなFreeRTOSならまだしも、でかいZephyrを常にアプリの横に置かれるのは邪魔です。

ご安心ください、Zephyrはアプリとカーネルを別のディレクトリに置くことができます(以降、Out-of-treeアプリケーションと呼びます)。便利ですね。

続きはまた今度。

編集者:すずき(2026/06/23 02:20)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2026年5月24日

JTSA Unlimited大会参加2026

目次: 射的

JTSA Unlimitedの大会に参加しました。

「水」ステージが大失敗、「木」もダメダメでした。他は結構良かったです。結果は72.1秒(前回は75.69秒)でした(総合78位/111人、LM 10位/17人)。60秒台はなかなか遠いです。


JTSA Unlimited練習会+大会の記録

練習会の記録を見ても60秒台がほぼ出ないので75〜70秒くらいが実力ですが、去年よりは70秒台前半が出る回数が多いかなあ……?最近はあまり上達している感がありませんが、今後もゆるゆると続けていきます。

編集者:すずき(2026/05/28 01:34)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2026年5月28日

ZephyrのOut-of-treeアプリケーションその2 - westの準備

目次: Zephyr

Zephyrのアプリケーションをビルドするには、Zephyrをビルドできる環境が必要です。最初はPython環境のセットアップを行います。

なんで初手がPythonかというと、ZephyrのツリーをダウンロードしたりビルドするときにwestというPython製のツールを実行するためです。基本的にはGetting Started Guideにあるとおりです。

私の環境はDebian Testingなのでcmake(> 3.20.5), Python(> 3.12), Devicetree compiler(> 1.4.6)のバージョンを満たしています。

Ubuntu 24.04 LTSのツールバージョン
$ cmake --version
cmake version 3.28.3

$ python3 --version
Python 3.12.3

$ dtc --version
Version: DTC 1.7.0

Ubuntu 24.04 LTSも問題ありません。もし古めのディストリビューションを使っている場合は上記の3ツールの最小バージョンを満たしているかチェックしてください。

westのインストール
$ sudo apt install --no-install-recommends git cmake ninja-build gperf \
  ccache dfu-util device-tree-compiler wget python3-dev python3-venv python3-tk \
  xz-utils file make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1

$ mkdir work_dir
$ cd work_dir
$ python3 -m venv .venv
$ source .venv/bin/activate

$ pip install west

Getting Started Guideには続きがありますが、In-treeアプリケーションをビルドするわけではないので今は実行しなくて良いです。以上がうまくいっていたら、ディレクトリはこうなっているはずです。

作業ディレクトリの状態
work_dir
`-- .venv

続きはまた今度。

編集者:すずき(2026/06/23 02:29)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2026年5月31日

ZephyrのOut-of-treeアプリケーションその3 - Zephyr SDKのインストール

目次: Zephyr

前回はPythonとwestの準備をしました。今回はZephyrをビルドするツールzephyr-sdkをインストールします。基本的にはZephyr SDKにあるとおりです。westを使える方はwestで良いですが詰みやすい(※)ので、インストーラを使う方法も知っておいて損はないでしょう。

SDKのバージョンは何でも良い訳ではなくZephyr Version Compatibilityにある通り、SDKのバージョンによってサポートしているZephyrのバージョンが違うのでご注意ください。

今回はSDK 1.0系とZephyr 4.4.0を使いましたが、特に理由はないので必要に応じて適切なバージョンを選んでください。

Zephyr-SDKのインストール
$ mkdir work_dir
$ cd work_dir

$ tar xf zephyr-sdk-1.0.1_linux-x86_64_minimal.tar.xz
$ cd zephyr-sdk-1.0.1

Install GNU toolchain [y/n]? y

Install GNU toolchains for all targets [y/n]? y
→ この問いにnと答えると、アーキテクチャごとに要るか/要らないかを聞かれるので、
要るものだけにyと答えると時間節約になります。

Install LLVM toolchain [y/n]? y

Install host tools [y/n]? y

Register Zephyr SDK CMake package [y/n]? y

Create symbolic links for old Zephyr bisectability [y/n]? y
→ 以前はSDK直下にアーキテクチャのディレクトリ(例: x86_64-zephyr-elf)がありましたが、
llvmが導入されてgnu/以下に移動しました。
昔のディレクトリ構造を期待する古いZephyrを使うなら、yと答えてシンボリックリンクを作っておいたほうが良いです。

基本は全部yと答えれば良いはずです。インストール時間を短くしたい人は"Install GNU toolchains for all targets"にnと答えて要るものだけに絞りましょう。

(※)west sdk installでもインストールできますが、westだと何が起きたのか全くわかりません。成功するうちは良いものの、いざ失敗するとどうしようもなくなります。

Zephyr SDKをローカルディレクトリに置く場合

Zephyr SDKを/optや/usr/localなどに置く場合はZephyrのビルドシステムが勝手にSDKを探してくれます。もし別の場所に置きたい場合はもうひと手間必要です。ホームディレクトリに下記の.zephyrrc設定ファイルを作ります。

設定ファイル~/.zephyrrc

export ZEPHYR_TOOLCHAIN_VARIANT=zephyr
export ZEPHYR_SDK_INSTALL_DIR=/home/ubuntu/work_dir/zephyr-sdk-1.0.1

設定を反映させるため、zephyrのディレクトリにあるzephyr-env.shをsourceで取り込みます。

設定の反映
$ cd work_dir/zephyr
$ source zephyr-env.sh

先ほど作った設定ファイルの内容が環境変数に反映されていれば成功です。

設定の確認
$ env | grep -i zephyr

ZEPHYR_BASE=/home/ubuntu/work_dir/zephyr
PWD=/home/ubuntu/work_dir/zephyr
ZEPHYR_TOOLCHAIN_VARIANT=zephyr
ZEPHYR_SDK_INSTALL_DIR=/home/ubuntu/work_dir/zephyr-sdk-1.0.1
PATH=/home/ubuntu/work_dir/zephyr/scripts:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

注意点は、シェルを終了させると環境変数が消えてしまうことです。したがってシェルを立ち上げる度に、

再びビルド環境を使うときの手順
$ cd work_dir
$ source .venv/bin/activate
$ cd zephyr
$ source zephyr-env.sh

を実行する必要がありまして面倒です……。手間なく設定する方法がありそうなので、ご存じの方は教えてくださいませ。以上がうまくいっていたら、ディレクトリはこうなっているはずです。

作業ディレクトリの状態
work_dir
|-- .venv
`-- zephyr-sdk-1.0.1

またセットアップだけで話が終わってしまいました。Zephyrは本題に至るまでが遠いです。次こそアプリを作ります。

編集者:すずき(2026/06/24 01:08)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 2025年
open/close 2026年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報