遊びながらPythonを学べるゲーム「農家は Replace() されました」の、骨を収穫するプログラムについて考えてみました。恐竜になってリンゴを食べ成長させ、Bone(骨)を多くの骨を収穫します。
本記事はネタばれが含まれています。ルールや考え方について知りたい場合はこちらを見てください。
収穫の条件
恐竜になる
change_hat(Hats.Dinosaur_Hat)
恐竜ハットを被ると恐竜ドローンになります。ドローンがリンゴの上に移動すると、自動的にリンゴを食べます。リンゴを食べると尻尾が1ブロック分延びます。
収穫
恐竜ハットから他のハットに変更すると、骨が収穫できます。収穫量は、尻尾の長さをnとすると、nの2乗した分になります。
プログラム
基本的な考え方
- x、y が(0、0)の位置から開始
- 恐竜ハットを被る
- 決められた方法で動く
- 尻尾にぶつかって動けなくなる
- 他のハットに被りなおして骨を収穫
(3)の「決められた方法で動く」については、次の「動作」に書いてあります。
動作
今いる場所から直接リンゴのある場所に取りに移動すると、伸びた尻尾が次第に邪魔になって最終的に中途半端な長さの状態で移動できなくなります。
ある程度、尻尾が伸びてくるとリンゴの場所に関係なく、干渉しないように規則的な動作させる必要があります。今回のプログラムは、最初から規則的な動作をさせて、リンゴは「偶然」採る形にしました。
農場のサイズが偶数と奇数で、若干動きが変わります。農場のサイズは、4ブロック以上である必要があります。
共通動作
(0、0)からスタートして北方向に移動し、北端で東に1ブロック移動する。
偶数

本図の矢印の切れ目とプログラムは一致していません。
共通動作の後、「東→東端→南→西端の1ブロック前(※1)」の動作をしたら「南」へ1ブロック移動。(※1)の動作を繰り返す。
奇数

本図の矢印の切れ目とプログラムは一致していません。
共通動作の後、「東→東端→南→西端の1ブロック前(※1)」の動作をしたら「南」へ移動。(※1)の動作を繰り返す。
但し、最後の3ブロックは、図のように下から3ブロックの行で東端に移動、残りの下2ブロックで南北の動きをしながら西に移動(※2)する。(※2)を繰り返す。
2周目以降、スタート地点の(0、0)を通らなくなるので、(0、0)の位置にリンゴが配置された時だけ、(※2)の動作の最後を(1、1)を通らずに(0、0)を通るようにする。
プログラム
サボテンのソートや迷路攻略のプログラムに比べて、少し長くなっていますが、ひとつずつのグループはとてもシンプルです。
# 農場のサイズ 4以上で
set_world_size(21)
clear()
change_hat(Hats.Dinosaur_Hat)
v = get_world_size()
h_mv_bl_01 = v - 2
h_mv_grp_01 = get_world_size() // 2
h_mv_time = 0
h_mv_bl_11 = v - 3
h_mv_grp_11 = h_mv_bl_11 // 2
ws_even_or_odd = get_world_size() % 2
odd_last_mv = 0
def v_move(v):
if can_move(North) == True or can_move(East) == True:
for i in range(v):
move(North)
move(East)
else:
change_hat(Hats.Gray_Hat)
def h_move_01(h_mv_grp_01, h_mv_bl_01):
global h_mv_time
if can_move(East) == True or can_move(South) == True or can_move(West):
for i in range(h_mv_grp_01 - 1):
for i in range(h_mv_bl_01):
move(East)
move(South)
for i in range(h_mv_bl_01):
move(West)
move(South)
h_mv_time = h_mv_time + 1
else:
change_hat(Hats.Gray_Hat)
def h_move_02(h_mv_bl_01):
global h_mv_time
if can_move(East) == True or can_move(South) == True or can_move(West):
for i in range(h_mv_bl_01):
move(East)
move(South)
for i in range(h_mv_bl_01):
move(West)
move(West)
h_mv_time = 0
else:
change_hat(Hats.Gray_Hat)
def h_move_11(h_mv_bl_01):
global h_mv_time
if can_move(East) == True:
for i in range(h_mv_bl_01):
move(East)
move(South)
else:
change_hat(Hats.Gray_Hat)
def h_move_12(h_mv_grp_01):
global h_mv_time
global odd_last_mv
if can_move(South) == True or can_move(West) == True or can_move(North):
if odd_last_mv == 0:
for i in range(h_mv_grp_01):
move(South)
move(West)
move(North)
move(West)
odd_last_mv = 1
elif odd_last_mv == 1:
move(South)
for i in range(get_world_size()):
move(West)
odd_last_mv = 0
h_mv_time =0
else:
change_hat(Hats.Gray_Hat)
while True:
#next_x, next_y = measure()
pos_x, pos_y = get_pos_x(),get_pos_y()
if pos_x == 0:
v_move(v)
if ws_even_or_odd == 0:
if h_mv_time < h_mv_grp_01 - 1:
h_move_01(h_mv_grp_01, h_mv_bl_01)
elif h_mv_grp_01 - 1 <= h_mv_time:
h_move_02(h_mv_bl_01)
elif ws_even_or_odd == 1:
if h_mv_time < h_mv_grp_11:
h_move_01(h_mv_grp_01, h_mv_bl_01)
elif h_mv_grp_11 <= h_mv_time:
h_move_11(h_mv_bl_01)
h_move_12(h_mv_grp_01)農場サイズが奇数の時、(0、0)を通るようにするのは、次のリンゴの位置を確認するコードが上手く動作しないので、n回目とn+1回目で動きを変えて対処しました。
動画
注意:動画の動きと上記のプログラムは、必ずしも完全に一致しているわけではありません。動作が異なっていても、上記のプログラムがベースになっています。
改善点
その1
小中規模サイズの農場だとこのプログラムで問題ありませんが、大規模サイズの農場だと、序盤から中盤にかけて無駄な時間が多いです。
その2
ひととおり動作して骨を収穫したあと、制御できずに暴走しています。しっかり制御して、再び恐竜ハットを被って、骨の収穫動作に入るようにしたいです。(動画のおまけ)

コメント