
for those about to code はじめに 農家は Replace() されましたはプログラム学習に良いソフトだけど、初心者には基本的な説明がかなり不足していて、説明する人がそばにいないとなかなか前進できない感じなので、とりあえず書きます。 harvest 1.右上の+マークでコードを書く画面を開く。 2.そのウインドウでhaと打ち込むと予測でharvestと表示されるのでEnterキーを押す。 3.Shiftキーを押しながら数字の8と9のキーで()を入力する。 4.Enterキーを押して改行する。 コードf0 harvest() ポイント 英語入力でないとダメ 小文字でないとダメ 勝手に間隔や余計な文字を入れない これで命令文が完成したので、三角の再生ボタンを押すたびにコードが実行されて、harvest()の収穫命令が1回実行される。 5回収穫したら、右上の上矢印2つの昇進アイコンを押して、whileをアンロックする。すると、whileループがどういったものか説明文が出るので適当に読む。 また、画面右上のiアイコンを押せば、今利用可能な命令文を見ることができる。コードを書く上で、その命令文がどういった動きをするのかを理解することはとても重要なことなので、定期的に読み返そう。ただし、コンピュータ相手とはいえ、所詮は言語なので、真剣に読んで100%覚えていくスタイルだとまったく進まないので、ぼーっと生きてないとダメ。英語でhelloと話しかけられたら、helloと何も考えずに返す。Hから始まり、エロが続くとは何事か!と5歳児の様に考えるとダメな大人になるのでお勧めしない。言語学習は原理や理論ではなく、従順さが一番。 while f0のコードのharvest()の部分をコピペして harvest() harvest() harvest() harvest() harvest() 5つharvest()を書いて三角実行すると、5回収穫できる。けど見た目が明らかにアホみたいなので、whileループの繰り返し命令を使って書き直す。また、コードは上から下に順番に実行されるので、 do_a_flip() harvest() harvest() と書くと、フリップをした後に、2回収穫をして、 harvest() do_a_flip() harvest() と書くと、収穫をして、フリップをして、収穫をする命令になる。 コード while True: harvest() ポイント whileは小文字 TrueのTは大文字 間にはスペースを1ついれる :はコロンで、;セミコロンではダメ。 先人が書いてる見たまんまを黙って書く。勝手に小文字と大文字を変えたりしたら、それだけで上手く動かない。while True:でEnter改行すると、自動的にtabキーを押した間隔が挿入されるので、whileの下はTabの空白がある状態でharvest()と書く。pythonの言語では、この間隔インデントが重要な扱いになっていて、インデントがあるとそれらの命令文がwhileループに属した命令になる。pythonはC言語とか他の言語と比べ、あまり{かっこつけない}で、インデントで済ますためインデント欠落はバグに直結するので注意しよう。 例えば、 while True: harvest() do_a_flip() だと、収穫してフリップをするの2つの動作を繰り返すが、 while True: harvest() do_a_flip() とすると、whileループのインデントにはharvest()しか含まれてないので、収穫のみを繰り返し、フリップの命令文までは到達できない。 とりあえず50のワラを回収したら右上の昇進アイコンから、スピード20と拡大30をアンロックしよう。 move これまで書いたコード画面は全部Xで閉じて、+マークでコード画面を開きなおし、 コードf0 move(North) と書こう。押すたびに北に1歩移動する。 もう一度+マークからコードウインドウを開いて、 f1 move(South) f2 move(East) f3 move(West) 同じように+を押して4つのコードを書いて十字キーの様にウインドウをドラッグして並べれば、コントローラの様にドローンを動かせる。 f4 harvest() も追加して十字キーの右側に配置すれば、最強コントローラの完成。それぞれの再生ボタンを押せば、自由自在にドローンへ命令が出せる。 ポイント 小文字と大文字は書き分けないと上手く動かないバグになる。 土地が狭くて、東西には移動できないから、50収穫してBushをアンロックしよう。Bushをアンロックしたら+マークから f5 clear() の命令ボタンを追加配置しよう。この命令は北に行ったり、何か別のものを植えていても、農場を初期化し、(0,0)の原点座標に移動する命令になる。 f6 plant(Entities.Bush) ポイント 同じく、小文字と大文字、.と,の間違いも注意。 ここまでの7つのコードウインドウをコントローラの様に並べて、ドローンを自由に動かしてみる。ブッシュを植えると、ゆっくりと成長して、成長し終わった後にharvest()を実行すると、木が収穫できる。Bushを収穫すると、勝手に草が生えるので、Bushを実行して植えなおす。Bushは成長途中で収穫すると、木が手に入らない。また、北の端まで行って、さらに北に行くと、下に戻るルールだと理解できる。 アホみたいなコントローラを作ったが、コードは書いて、実行して、動きを観察することがとても重要。だからこそ、新しい命令をアンロックしたら作ったコントローラに命令を追加して動かしてみる。このアホみたいな基本操作コントローラを作ることで、自分が何をするか、どう動くかを理解することができる。

grassとbush まじめなコードを書くために+を押して画面追加。 コードgrass clear() while True: harvest() move(North) これで、収穫と移動を繰り返す自動命令になる。コードを実行すると、コードは上から下に流れていくので、まずclear()が実行され初期化される。その後はwhileループに突入してwhile以下のインデントが実行されるので、whileの前に書かれたclear()はループ実行されない。つまり、clear()が実行され、harvest()、move(North)が実行された後は、whileのはじめに戻り、harvest()、move(North)の部分だけが繰り返し実行される。 さらに+でコードを追加 コードbush clear() while True: if can_harvest(): harvest() plant(Entities.Bush) move(North) _はアンダーバーで、キーボード右下のshiftの横のキーをshiftを押しながら押すと入力できる。コードに余計な余白スペースが入ると処理が変わってしまい、バグが発生するので、プログラムではアンダーバーをスペースの代わりに多用することになる。これで、Bushが成長し終わってなければ収穫せず、成長し終わっていたら収穫し、再度植え付け北に移動する命令になる。ここでインデントに注意してコードを見てほしい。whileの下は全部インデントがあるので、全部whileのループに属した命令文であり、繰り返される。さらにインデントが追加されている部分は、 if can_harvest(): harvest() となっていて、ifの命令文にはインデントがあるharvest()だけが属している。can_harvest()で収穫可能なまで育ち切ったか確認をして、もし収穫できるなら、harvest()で収穫しろ。できてもできなくても、下のplant()で植える命令へ、下へ下へとコードが順次実行されていく。 説明文を加えると、 コードbush clear() #他のコードを実行していた場合用に初期状態にする while True: #繰り返せ if can_harvest(): #収穫できるなら harvest() #収穫しろ plant(Entities.Bush) #ブッシュを植えろ move(North) #北に移動しろ ポイント #のあとの入力文は説明文のメモ書きとして無視される。他人が書いたコードは意味が分からないし、自分が書いたコードでも明日になれば意味が分からなくなっているので、#をつけて何をしたくてこうしたのかメモを残しておくのが望ましい。 position 木を20集めて、拡大3x3をアンロック 草を150と木を10貯めて、1+1をアンロック さらに草を100集めて、(x,y)をアンロック これで東西にも移動できるようになった。さて、ここで突然だけど日常生活で今どこにいるの?と聞かれたら何と答えるだろうか?どこどこ駅の近くだとか、何々町だとか、人間は割と曖昧な答えをすると思う。プログラムでコンピュータとやり取りする場合は、北緯何度何分何秒、東経何度何分何秒だとか正確な表現が必要になる。例をあげると、GPSを利用して座標を得て、返答する。この問題解決のための手順をアルゴリズムと呼ぶ。何かを利用して、必要な情報を集めて、それを利用する。プログラマは、このアルゴリズムを短い手順で正確に扱える方法を考えたり、他人が書いたコードを読んで美しい考え方を身に着けていくことになる。 if文を使った条件分岐 if A == B: C else: D もしAがBと等しいことがTrue正しければ、Cを実行。False正しくなければDを実行。 get_pos_x()でx座標を得る get_pos_y()でy座標を得る if (get_pos_x()+get_pos_y())%2 == 0: harvest() get_pos_x()+get_pos_y() x座標とy座標を問い合わせて足す。 %2は2で割った余りを求める式。 == は左と右が等しいかどうか調べる命令 ここでは0を指定しているので、x座標とy座標を足したものが偶数の場合はGrassにしてx+yが奇数の場所はBushにする命令を書こうとしている。偶数か奇数かの判定に、x座標とy座標を問い合わせて、戻ってきた数値を足して、%2の計算で2で割った余りを求めると、偶数の場合は余りが0となり、if 0 == 0:となり、0と0は等しいのでif文がTrue正しいとなり、harvest()が実行される。奇数の場合は、2で割った余りが1なので、if 1 == 0:だから、1と0が等しいかどうかif文判定はFalse正しくないとなるので、harvest()は実行されない。 if (get_pos_y()+1) == get_world_size(): move(East) get_pos_y()+1はy座標に1を足す式だけど、プログラム上ではよくある処理で、数値が0から始まるか、1から始まるかの調整。get_world_size()で現在のマップサイズ3x3を問い合わせると3が戻ってくる。y座標は[0,1,2]の3つを取り、最大値(マップの端)は座標2+1で、3 == 3が正しくなるのでマップの端で東に行く命令。なぜ、わざわざややこしい表現をしているのかと言えば、get_world_size()で問い合わせる命令で処理しているので、アップグレードで大きな農場をアンロックしていっても、処理を書き換える必要が無い命令にしている。今が3x3の広さだから==3とコードを書くと、4x4に拡張したときに==4と書き換えなければ上手く動かず、将来どこに問題が出たのかデバッグさせられるコードになってしまう。 新しく+でコードウインドウを開いて、過去に書いたgrassとbushのコードを合体。 コードgrass+bush clear() while True: if (get_pos_x()+get_pos_y())%2 == 0: harvest() else: if can_harvest(): harvest() plant(Entities.Bush) if (get_pos_y()+1) == get_world_size(): move(East) move(North) ポイント もし、x座標とy座標を足して、2で割った余りが、0と等しいなら、grass用の座標として収穫しなさい。そうでなければ、収穫できるなら収穫し、Bush用の土地としてBushを植えなさい。もしy座標+1の値がマップサイズと等しければ(マップの北の端まで来たら)東に移動して、土地を有効活用しなさい。 carrot 木50でアンロック ニンジンは、till()で耕して植えないとダメ till()の命令文はドローンの下の土地が耕してないなら耕し、すでに耕していると耕していない状態に戻す。もちろん、新しい命令なのでコントローラに、 till() のコードを追加して、手動操作で動かして確認してほしい。 コードcarrot clear() while True: harvest() if get_ground_type() != Grounds.Soil: till() plant(Entities.Carrot) if (get_pos_y()+1) == get_world_size(): move(East) move(North) 収穫する。地面が耕されてなければ耕してニンジンを植える。北に動く。 if A != B: C AがBと一致しなければCする。 if A == B:がAとBが等しいことが正しいかどうかのif判定。 if A != B:がAとBが等しくないことが正しいかどうかのif判定。 !=は==の逆の命令になる。 このニンジン専用コードを実行して、変数a=2(ニンジンコスト35)とリスト[1,2,3](ニンジンコスト500)をアンロックする。結構時間がかかるから、grass+bushのコードにも切り替えて、grassの収穫量とニンジンの収穫量を強化しておきたい。また、キャロットの下の木を(コスト木50とニンジン70)でアンロックする。土地は広げなくてよい。 list list_p = [0, Entities.Bush, Entities.Carrot, Entities.Tree] plant(list_p[3]) このコードはlist_pのリストの0番目は空白、1番目にBush、2番目にCarrot、3番目にTreeのそれぞれEntities.xxxでplant()のカッコの中に入れる用の引数(ひきすう)として使うリストになる。これで、plant(list_p[3])と書けばplant(Entities.Tree)と書いたことになる。リストは1番目からではなく、0番目から始まることに注意。プログラムコードは0番目からといった考え方が多くあるので、今後かなり注意する。少しでも注意を怠ると、気づき難いバグになる。[]はキーボードのEnterキーのすぐ左側にあるキーで入力できる。 リストはそれだけで何かを与えてくれるコードではなく、リストを作れるようにするだけ。植えるもののリストを作れば、if文を多用して条件分岐をややこしく書かずに、Aならリストの0番目、Bならリストの1番目、Cならリストの3番目といった簡潔なコードを書けるようになる。 変数 変数自体は中学生の数学で習ったものとほとんど同じ扱いで使えるが、=イコールについては数学と全然意味が異なるので注意。 clear() count_h = 0 while True: harvest() count_h += 1 if count_h == 10: break move(North) count_hで収穫を行った回数を数えている。このコードでは、ifでカウントが10回になったらbreakでwhileループを脱出してプログラムが止まるコードを書いている。breakが実行された時は、即時退出するので、その下のwhileに所属したmove(North)は実行されない。追加で、whileの前にcount_h = 0を書いているので、whileループに入る前に1回だけcount_h = 0になる。whileの中にcount_h = 0を入れてしまうと、ループをする度にカウントが0に戻ってしまうのでループの外に書いていることに注意。 また、数学では、左辺と右辺を処理して簡潔な式にするが、プログラムでは数学と=イコールの扱いはまったく異なる。例えば、A=Bを数学的にとらえると、AとBは等しいといった式になるが、プログラムでは、ここでAをBにするといった代入宣言になる。A=2と書くと、数学ではAは2と等しい意味で、プログラムでは突然でずがAを2にしますといった意味になる。なので、A="猫"としてAを猫ちゃんにすることもできるし(やったー猫ちゃんかわいい)、この数学との違いを必ず深く理解する必要がある。 このコードでは count_h += 1と書いているが、もともとは、 count_h = count_h+1と書く 書き方は、 x = x+1と書くところを省略して、x += 1と書いている。 x = x+1を見ると数学と全然違う扱いだと理解できるだろう。 大事なことなので繰り返しになるが、プログラムで=イコールは、xにx+1を代入する命令になる。 x = 2 x = x+1と書くと、x = 2+1で、これからx = 3で扱う命令になる。 x = これまでのxに+1するといった理解。 tree treeはbushより多く木を産出するが、木と木が隣り合うと成長が著しく遅くなる特性を持つ。この特性とカボチャの下にある混植ボーナスを満たすために、ごちゃ混ぜのややこしい植え方を選んでコードを書いている。コントローラにtreeのコードボタンを追加し、手動で操作し試してみると、全面treeだけを植えるとかなり成長が遅いことが確認できる。 plant(Entities.Tree) ここで、listも使い、grass+bushのコードをgrass+bush+carrot+treeの4種混植のコードに書き換える。 clear() list_p = [0, Entities.Bush, Entities.Carrot, Entities.Tree] while True: sum_pos = get_pos_x()+get_pos_y() pl = sum_pos%4 if pl == 2: if get_ground_type() != Grounds.Soil: till() if can_harvest(): harvest() if pl != 0: plant(list_p[pl]) if (get_pos_y()+1) == get_world_size(): move(East) move(North) ポイント sum_posとplを変数として使っているのは、毎回get_pos_x()などを書くと、長くて読みづらいコードになるので使用している。listも同様に4種類同時に扱うので使用している。1種類の専用コードや短いコードの場合は、使うと逆に読みづらいコードになるので好きに使い分けるとよい。grass、bush、carrot、treeの4種類は混植ボーナスがあり、混植ボーナスは植えた植物がランダムで好きな植物を持ったり持たなかったりする。好きな植物があり、かつ好きな位置に植えてあった場合、最低で5倍の収穫ボーナスがかかる圧倒的なものなので、混植ボーナスを使わない選択肢はない。また、grass+bushのときは2種類混植だったため、%2で2で割った余りを求めて偶数か奇数かの判断で土地を2つに斑分割した。今度は4種なので、%4で4で割った余りを考え、4種類の混植に変更している。 pumpkin 木500とニンジン200でアンロック カボチャの説明文を読み、コントローラの手動操作でテスト栽培の動作確認を行い、もっと真面目に顧客ニーズをリスト化する。 カボチャはtill()で耕されている必要がある。 till()は耕されている土地に実行すると未耕地に戻す命令になる。 カボチャは20%の確率で成長失敗し枯れる。 収穫後や、植えなおす際に再度耕す必要はない。 失敗して枯れたカボチャの上では植える命令が通る。 上手く育ったものが並んでいるとカボチャは合体し、2x2の大きなサイズになり、3x3でさらに大きくなる。 土地を最大まで拡張した場合は、32x32の巨大カボチャとなり、収穫量が圧倒的。 真面目な検討リスト 未耕地のみtill()を実行する必要がある。 カボチャを植えて成長を待ち、枯れた場合は植えなおす必要がある。 巨大カボチャになったことを確認する必要がある。 土地の広さにより手順の最適解が異なるため、検討が必要。 clear() sum_p = 0 area_size = get_world_size() while True: while True: if get_ground_type() != Grounds.Soil: till() plant(Entities.Pumpkin) if can_harvest(): sum_p += 1 if sum_p == area_size: sum_p = 0 move(East) break else: sum_p = 0 plant(Entities.Pumpkin) move(North) if get_pos_x() == 0: harvest() ポイント 耕してなかったら耕す。 収穫できるならsum_p += 1をしてカウントする。 収穫できない場所があれば、植えなおし、sum_p = 0でカウントを0に戻す。 北へ移動しながら作業を繰り返して、植えなおしが発生せず、正常成長カウントがワールドサイズと同じになれば、1列全部正常に育った判断で東へ移動する。 1列ずつ全部正常に育ち、x座標が0まで戻ってきたら全列正常に育った判断で収穫する。農場が小さいときは、全面植えて、全面枯れたものを植えなおし、全面正常成長確認して、収穫する方が早い。しかし、農場が大きくなると列毎のチェックの方が早く逆転すると予想されるので、列毎のチェックを採用している。また、カボチャの状態を問い合わせmeasure()した戻り値である、神秘的な数値(個体識別番号)を得て、例えば土地の左端x=0のカボチャと32x32の巨大な土地の右端のカボチャの個体識別番号が一致していれば、同一個体の巨大カボチャであると判断する方法もある。measure()はカボチャの下のサボテンでアンロックされると思う。 また、この辺からアンロックコストが結構大きいので、4plantsのコードとpumpkinのコードを走らせながら、それぞれの収穫量と土地の拡張を行ってください。カボチャは土地を広げただけ、アホみたいに収穫量が増えるので32x32までいくと凄い威力になります。 関数 def f():をアンロック その下のrandom()をアンロック 関数が何かといえば、一番最初に実行したharvest()も関数。画面右上のiのアイコンからharvest関数の説明を読むと、どういった目的で作られているのか、どう動くかが書かれている。def f():で何ができるのかというと、この関数を自分で作れますよ、といった機能。これまでに書いた4plantsや、pumpkinを関数として定義すれば、 def f_4plants(): 4plantsの処理コードを書く def f_pumpkin(): pumpkinの処理コードを書く while True: for i in range(100): f_4plants() for i in range(100): f_pumpkin() こんな感じで、簡単に関数を呼び出して、使用することができる。もちろん関数を定義せず、長い命令文をコピペで2つ並べて書いてもいいけど、whileの外で関数を定義して、ループコード内は短い関数で書けば、すっきりとして、何をやろうとしているのか一目瞭然。また、順番を変えたりちょっとした変更が簡単にできるようになる。関数にした後に使用していれば、例えば4plantsの関数自体に不満がでたとき、4plantsの関数内部を調整すれば複数の関数を並べたコードは触らずに済むので、作業性が高い。 ここで使ったforループ for i in range(10): harvest() whileループは、いつ終わるかわからない繰り返しや無限に繰り返す際に使用して、forループは回数が決まっているときに主に使う。もちろん、これまで使用したwhileループ内でcount_xxxの変数とcount_xxx += 1を合わせて回数を数えて回数ループ処理を手書きすることもできるし、使いやすいと感じるコードをその都度考えて書くとよい。一般的には、forループでスクワット10回、forループでデッドリフト10回、forループでベンチプレス10回、その3つのループ全体をwhileループの下に入れれば、無限に強くなる感じ。パワー。 def f():のコード clear() def f_move_p(pos_x, pos_y): list_d = [North, South, East, West] move_d = 0 move_x = pos_x-get_pos_x() if move_x < 0: move_d = 3 move_x = abs(move_x) else: move_d = 2 for i in range(move_x): move(list_d[move_d]) move_y = pos_y-get_pos_y() if move_y < 0: move_d = 1 move_y= abs(move_y) else: move_d = 0 for i in range(move_y): move(list_d[move_d]) while True: f_move_p(1, 1) do_a_flip() f_move_p(2, 2) do_a_flip() f_move_p(0, 0) do_a_flip() f_move_p()の関数は、引数にx,y座標を指定して、その場所にドローンを移動するコードとして書いた。関数として書いておけば、その後自由に呼び出し再利用することができ、とても便利。使うときは、f_move_p(2, 2)で呼び出すと(2, 2)の座標にドローンを指定して移動することができる。 関数を作るときに、f(A, B)といった形で関数を作れば、関数が外からAとBを受け取って、そのAとBによって異なる動作をする設計で使うことができる。 コードの仕組みは、移動先として指定された座標と現在のドローンの場所から、移動方向と移動距離を計算し、移動する。新たに使ったabsはrandom()でアンロックされる絶対値を求める関数。 cactus 要求 サボテンはtill()を要求。 サボテンには身長みたいなものがありmeasure()で調べることができる。 サボテンをswap()で並べ替えることができる。 measure()とswap()は、ドローンのmeasure()真下とmeasure(North)、measure(South)、measure(East)、measure(West)しか目や手が届かない。 x方向に身長順、y方向にも身長順、すべて正しく並べると動作画面で緑に色づき、収穫量が増える。もう、まんま色々なソフトにあるソートの機能。そのソートのコードを手書きで作れな問題。しかも、人間の目や一般的なプログラムでソートを書くときは、すべてを見渡して、すべてに手が届いて並び替えができるけど、このゲームでは"ドローンの眼と手は短い"制約を受けるので、うんざりする注文。アラブの石油王が来店して、チャーハンやハンバーガーを両手を使わずに作ってくれと注文してる感じ。うんざりしすぎて美しいコードを考えようとする気力を奪う。 方向性の検討 サボテンを植える。 原点からy軸+方向にドローンを移動させ、手前より奥のサボテンの身長が低ければ、引っ張って入れ替え続ける。 繰り返せば、1列綺麗に並ぶはず。1列並ぶなら、すべての縦方向が並ぶはず。 その後x軸方向に切り替えて、同じように1行毎に処理し横方向も並ぶはず。 別方向を入れ替えた場合、再度並べ替えが必要な場合が極稀にあるので再チェック。 両軸方向が連続で入れ替えが1度も起こらなくなれば完成。 clear() area_size = get_world_size() global chk_right chk_right = 0 def f_plant_cactus(): while True: if get_ground_type() != Grounds.Soil: till() plant(Entities.Cactus) move(North) if get_pos_y() == 0: move(East) if get_pos_x() == 0: break def f_swap_cactus_y(): global chk_right while True: if measure(North) < measure(): swap(North) chk_right = 0 if get_pos_y() > 0: move(South) else: move(North) if (get_pos_y() + 1 ) == area_size: move(East) move(North) if get_pos_y() == 0: if get_pos_x() == 0: chk_right += 1 break def f_swap_cactus_x(): global chk_right while True: if measure(East) < measure(): swap(East) chk_right = 0 if get_pos_x() > 0: move(West) else: move(East) if (get_pos_x() + 1 ) == area_size: move(East) move(North) if get_pos_x() == 0: if get_pos_y() == 0: chk_right += 1 break while True: f_plant_cactus() while True: if chk_right != 2: f_swap_cactus_y() if chk_right !=2: f_swap_cactus_x() if chk_right == 2: harvest() chk_right = 0 break f_plant_cactus()はサボテンを植える関数 f_swap_cactus_y()はy軸方向の並べ替え関数 f_swap_cactus_x()はx軸方向の並べ替え関数 並べ替えの関数は、軸方向が違うだけで同じ処理を繰り返し書いている重複アホコードだけど、向き等の処理をまとめるとより汚くなり、初心者さんが読めないコードになるので、アホコード採用とした。そのため、x軸方向のコードを読む必要はない。 global chk_rightでglobal宣言をしているのは、2つの軸方向並べ替え関数と、全体制御で変数を共有する宣言。global扱いしないと関数内部の変数が、関数の外に出てこれないので使っている。10人でコードを書いている場合、global変数の宣言は、自分の担当関数部分だけにとどまらず、10人全員の変数認識共有が必要になったり、大規模なバグを発生させる原因になるので、可能な限り使いたくないコードになる。ここではchk_rightが、x軸とy軸の並び正常性確認を連続で通過し、2になったら収穫をする目的で使用している。極稀にしか必要ではないので、ほぼほぼ省いた方が早いが、一応再チェックでコードを書いた。 dino 要求 恐竜帽子をかぶるとスタートする。 リンゴを食べると成長する。 伸びすぎると、自分の体が邪魔で動きが制限される。 自分の体に邪魔されないルートを決めて、限界までリンゴを食べ続ける。 限界まで成長したら、帽子を変えて終了する必要がある。まんま、一筆書きしなさいな要求。一筆書きだから、マップの広さが3x3とか偶数でない場合は無理がでるが拡張すれば良いので考慮しない。 clear() area_size = get_world_size() change_hat(Hats.Dinosaur_Hat) def f_move_p(pos_x, pos_y): list_d = [North, South, East, West] move_d = 0 move_x = pos_x-get_pos_x() if move_x < 0: move_d = 3 move_x = abs(move_x) else: move_d = 2 for i in range(move_x): move(list_d[move_d]) move_y = pos_y-get_pos_y() if move_y < 0: move_d = 1 move_y= abs(move_y) else: move_d = 0 for i in range(move_y): move(list_d[move_d]) def f_checker(): if can_move(North) != True: if can_move(South) != True: if can_move(East) != True: if can_move(West) != True: change_hat(Hats.Straw_Hat) clear() change_hat(Hats.Dinosaur_Hat) while True: while True: for i in range(area_size/2-1): pos_y = get_pos_y() f_move_p(area_size-1, pos_y) move(North) pos_y = get_pos_y() f_move_p(1, pos_y) move(North) pos_y = get_pos_y() f_move_p(area_size-1, pos_y) move(North) pos_y = get_pos_y() f_move_p(0,pos_y) f_move_p(0, 0) f_checker() ポイント 関数のところで作ったドローンを指定した座標へ動かす関数を使い、土地全体を一筆書きで移動するコードを書いて、いつか身動き取れない限界まで成長する感じ。(0, 0)からx軸方向に東端まで移動し、1歩北に移動、x=0のy軸を帰路用に確保するために、1マス残し(1, 1)まで西へ戻り、北に移動といった感じで北の端まで処理して、最後はx=0のy軸を(0, 0)まで戻り1周終了。この単純処理を延々と繰り返せば限界まで成長できる。このゲームには明確なエラー処理がなさそうで、限界成長した後は処理が止まってしまう。このゲームのルール説明を色々読んでも体の長さを測ったり、りんごの存在の有無確認だとか、限界到達確認用の明確な関数が見つからなかったので、無理やりf_checker()に書いている通り、North, South, East, West, 全ての方向に動けない確認をして帽子の切り替えで曖昧によくわからないまま適当なコードで作業終了させた。スピードを競うには、リンゴを取った回数を細かく計測する方法を検討して、体が邪魔にならない限界までリンゴへ最短移動しながら次のリンゴへの移動にも邪魔にならない体の形を検討する必要がある。

sunflower 要求 ヒマワリはtill()が必要。 ヒマワリはmeasure()で調べると花びらの数が7 to 15。 花びらの数が多い順に収穫すると8倍ボーナス。 収穫した花びらは電池の様な扱いで、コードを停止しても維持される。 ヒマワリ専用のコードで超充電した後、別のコードで電池を使い、ドローンの動きを速めるとこができる。コードsunflower clear() while True: if get_ground_type() != Grounds.Soil: till() if can_harvest(): harvest() plant(Entities.Sunflower) if (get_pos_y()+1) == get_world_size(): move(East) move(North) 検討した結果、要求を却下してボーナスを求めない単純コードを書いた。 ボーナス利用コード while True: 全面植える 全面花びら15枚を収穫 全面花びら14枚を収穫 と繰り返し最後に7枚を収穫 要求通りのボーナス利用コードを書くと、植え付け全面移動と花びらのパターン9種類の全面移動回収とで、10回の全面移動を必要とする。つまり、8倍の効率を得るのに、10倍の非効率を要求されている。こんな馬鹿な要求は、開発部としては断固拒否するのであーる。プログラムとは、人間とコンピュータの間にあるもので、顧客、営業系SE、開発、プログラム、コンピュータと並んだやり取りの中間作業。顧客と営業系SEの間に未解決の問題があると、こんな要求をされる。アホくさってよくある話をdevは教えたいのかもしれない。結局のところ、プログラマは人間とコンピュータの通訳にすぎないので、コンピュータと話すスキル以上に、人間と話すスキルを求められる。もちろん、複数ドローンの導入で20%以上の改善がある場合は、逆転する可能性はある。 肥料と汚染 汚染は迷路作成の原料になる。 treeに肥料を使うコードを追加するだけ。if pl == 3: use_item(Items.Fertilizer) 4plantsのコードに上記コードを加えて、pl == 3で木を植え付けた場面で、Fertilizerの肥料を使えばよい。4種類で木が一番収穫量が多いからだ。 clear() list_p = [0, Entities.Bush, Entities.Carrot, Entities.Tree] while True: sum_pos = get_pos_x()+get_pos_y() pl = sum_pos%4 if pl == 2: if get_ground_type() != Grounds.Soil: till() if can_harvest(): harvest() if pl != 0: plant(list_p[pl]) if pl == 3: use_item(Items.Fertilizer) if (get_pos_y()+1) == get_world_size(): move(East) move(North) 実際に、4plantsのコードで、肥料をまく。肥料をまけば、次の迷路用のWeird_Substanceを収穫できる。また、わざわざ切り替えスイッチを作るほどの必要性があるリソースではないので、普段は下記の通りコードの前に#を追記して動かないようにしておき、必要に応じて、#を消して奇妙な物質を集めるとよいだろう。 #if pl == 3: #use_item(Items.Fertilizer) maze A Bushを植えて、BushにWeird_Substanceを使うと開始。 Weird_Substanceの使用量で作成される迷路の大きさが変わる。 宝箱はランダム配置。 宝がドローンの真下にあるあるとき、get_entity_type()は宝があると返す。 宝がドローンの真下にないときに、harvest()を使うと迷路が壊れる。 宝がドローンの真下にあるときに、harvest()を使うとゴールドを得られる。 宝がドローンの真下にあるときに、Weird_Substanceを使うとその迷路を再利用して、ランダム位置に宝箱が配置され、連続した宝さがしができる。 連続続行は300回まで可能で、迷路は再利用する度、新たな壁が作られたり、壁が壊れてなくなったりする。上記ルールを検討した結果、まずは迷路の基本アルゴリズムを考える。googleで"迷路 左手の法則"を検索してほしい。迷路の壁に左手をつけ、壁伝いに進み続けると、必ずゴールにたどり着ける有名なアルゴリズムがある。それをコード化する。 いきなりコード化すると初心者さんには難しいので、人間の言葉でコードを書く。 向きが北の場合 西を確認して壁がない場合、向きを西に変更 西がダメな場合、北を確認して壁がない、まっすぐ進む 北もダメな場合、東を確認して壁がない、向きを東に変更 全部壁の袋小路だった場合、振り返って元来た道を戻る この文章を4方向で考えコード化する必要がある。つまり、コード化を進めた文章にすると、 左手が離れたら、向きを-1 正面が壁なら、向きを+1 右も壁なら、向きを+2にして戻る この考え方に追加で、 list_d = [West, North, East, South, West, North, East] orient = 0 方向のリストを変える。方向を-1や+2する場合に、[North, East, South, West]の4リストだと、リスト範囲から外れるので使い難いからだ。色々な処理方法があるが、初心者にわかりやすいものとして、リストを追加して、西、北、東、南、西、北、東とループするリストを用意して、方向-1と+2のルート検索に必要な範囲分の方向リストを確保する。コードの末尾で方向がリストの端にいる場合に、中央の北、東、南、西のリスト中央に戻すコードを書く。 また、 substance = get_world_size() * 2**(num_unlocked(Unlocks.Mazes) - 1) は、現在作成可能で、一番大きなサイズの迷路を作るSubstanceの必要量を計算したコード。 コードmaze_lefty substance = get_world_size() * 2**(num_unlocked(Unlocks.Mazes) - 1) list_d = [West, North, East, South, West, North, East] orient = 1 while True: clear() plant(Entities.Bush) use_item(Items.Weird_Substance, substance) orient = 1 while True: if can_move(list_d[orient-1]): orient -=1 elif not can_move(list_d[orient]): if can_move(list_d[orient+1]): orient +=1 else: orient +=2 if orient == 0: orient += 4 if orient > 4: orient -= 4 move(list_d[orient]) if get_entity_type() == Entities.Treasure: harvest() break このコードはあくまで"迷路 左手の法則"のアルゴリズム用のコードなので、迷路の再利用はしていない。迷路を再利用すると、壁が消えたり、壁が作られたりして、少しだけ迷路の構造が変わる。つまり、再利用すると、壁と壁が離れている上級迷路が出現し、ゴールに到達することが不可能になる。そういった致命的なアルゴリズムを使っているので、迷路の再利用はせず、宝を回収した後は、初期化するループにしている。方向を数字で使うコード化すると読んで理解することが難しくなるが、人間の言葉で書いたコードに戻って、それをコンピュータ用の簡潔なコードにする部分を深く読んで理解してほしい。この、人間の言葉でアルゴリズムを考えて書き、実際のコンピュータ用の言語であるコードへ変更していく手順を考えることが重要だからだ。 maze B プログラムを書く流れは、まず要求が何なのかを簡潔な文章にしていき、次にそれを実現するアルゴリズムを検討する。あとは、そのアルゴリズムに基づき、コンピュータが処理しやすいコードを書く。この重要な手順を何度も説明することになってしまうが、AIが人間とコンピュータの間に入り、かつ日進月歩で変化する時代の中、重要になるのは明確な要求と、AIが処理しやすいアルゴリズムの文章化になっていくと考えられる。なので、色々なアルゴリズムを考えよう。 ポンコツでけがれた大人のアルゴリズム 全てのタイルにドローン置けば、一歩も動かなくて良い説 実現のため、print()、set_speed()、メガファームを最大までアンロック。 コードmaze_quick clear() set_world_size(5) substance = get_world_size() * 2**(num_unlocked(Unlocks.Mazes) - 1) area_size = get_world_size() def f_maze_d(): while True: if get_entity_type() == Entities.Treasure: use_item(Items.Weird_Substance, substance) while True: spawn_drone(f_maze_d) if get_pos_y()+1 == area_size: if get_pos_x()+1 == area_size: break move(East) move(North) plant(Entities.Bush) use_item(Items.Weird_Substance, substance) f_maze_d() コード化でドローンの仕様をテストしたが、結構使い難く制限だらけな感じで、普通の要求でも通らないようだ。人間の多様な創造性を形にできないドローンぽい。なので、300回再利用して、そのまま自動初期化するコードは書けなかった。

结束 算法思路 忍者 不重复利用 如果在岔路让无人机分身,应该就能必定选择正确的道路并以最短路径到达 在移动时遵循左手定则,同时在岔路分身并同时前进所有道路 不返回,在死胡同自毁 随机 重复利用 派出大量随机移动的无人机 仅随机移动的条件较弱,因此追加除死胡同外不返回的条件 即便如此条件仍较弱,所以当靠近宝物位置时会观察周围 虽然曾想过要这样做,但似乎spawn_drone()的规则是可以向无人机传递要执行的函数,但该函数无法带有参数。此外,取出后也无法控制无人机之间的操作。如果想通过传递参数来下达各种命令,由于这是被禁止的,因此需要要么编写规避规则的代码,在不传递参数的前提下通过准备多个传递给无人机的函数来模拟参数传递;要么在循环中定义要传递的函数并提前进行重写,在传递前创建函数副本,并在创建副本时将想要用作参数的部分分别嵌入其中,然后用生成的函数来生成无人机,以此来蒙混过关。这样下去就不是练习读写代码,而是变成针对这个游戏规则的特殊设定了,所以我在这里放弃。认真思考这部分内容也无助于学习编程。 到这里为止所写的内容是代码思维的基础部分,只是写法不同,其思维方式即使在过去的COBOL和FORTRAN中也是一样的,所以我认为对任何方面都有帮助。接下来,可以搜索【AND电路】【OR电路】【NOT电路】【逻辑电路】、【半导体】【NMOS】【PMOS】【CMOS】、【二进制】【十六进制】、【量子隧道效应与纳米工艺的极限】【通过堆叠实现伪细分】、【x86】【x64】【量子计算机的波函数利用】等内容稍作了解,就能掌握现代编程的基础。虽然不太清楚情况,但还是要加油哦。
2026-02-18 04:00:09 发布在
编程农场
说点好听的...
收藏
0
0
