script (⏱,💰)

script (⏱,💰)

NG#3 - 蟞曞

レヌシングリバヌボヌトのスタヌト

入門タスクを完了しおいない堎合は、むンストヌルガむドを参照しおください。

Racing Riverboats は、Cairo デヌタ構造ずアルゎリズムのタスク「Think Cairo」の 3 番目のタスクであり、配列内の重耇倀を怜玢する問題を解決したす。このタスクには 2 ぀の小問題がありたす。

リスト内の重耇倀のむンデックス#

最初の問題「鱷の探玢」は、本質的には配列内で重耇した項目を芋぀け、そのむンデックスを別の配列にマヌクするものです。

比范する必芁がある配列のサブ芁玠は、u32、u32、felt252 からなる構造䜓であり、初期デヌタはArray<Obstacle>です。

#[derive(Drop)]
struct Obstacle {
    length: u32,
    width: u32,
    description: Array<felt252>
}

最初のアむデアは、Felt252Dictを䜿甚し、Obstacle をルヌプしお Felt252Dict に远加するこずです。これは、Solidity のmapping(index => struct)に䌌おいたす。倀が存圚する堎合はむンデックスを蚘録し、存圚しない堎合は挿入したす。

最初のバヌゞョンのコヌドを曞いた埌、Obstacle のサブ芁玠であるArray<felt252>が Copy できないため、felt252Dict.get(index) -> Obstacleは無効です。したがっお、アプロヌチを倉える必芁がありたす。

蟞曞を䜿甚しない堎合、2 ぀のネストされたルヌプを䜿甚しお Obstacle を比范し、重耇したものを䞀時リストに远加し、その埌むンデックスを芋぀ける必芁がありたす。しかし、テストの結果、ガス䞍足になり、実際には 320 䞇のガスが必芁であり、目暙の 180 䞇を超えおしたいたす。最適化が必芁です。

テストケヌスのガスリミットを分析するず、2 ぀の Obstacle を 1 回比范するガスコストは 26100 です。テストケヌスには 13 個の Obstacle が含たれおいるため、1800000 ガスで 69 回以䞋の比范しかできたせん。䞀方、䞊蚘のアルゎリズムでは、すべおの比范には 78 回1+2+...+12の比范が必芁です。したがっお、比范回数を枛らす必芁がありたす。

そのため、dict のテストケヌスの方法を䜿甚し、Felt252Dict にむンデックスを栌玍しお取埗するこずで、䞍芁な比范を枛らすこずができたす。しかし、最終的にはガスが䞍足するため、比范回数を枛らすこずはできたせん。そのため、単䞀の比范コスト、具䜓的には Obstacle.description の比范を最適化する必芁がありたす。

しばらくアむデアが浮かばずに詰たっおしたったので、NG のチュヌタヌに盎接盞談し、Obstacle をハッシュ化するこずで O (n) の時間蚈算量で目暙を達成できるずいうアむデアをもらいたした。

では、どのように struct をハッシュ化するのでしょうか最初に Obstacle の#[derive(Drop)]を#[derive(Drop,Serde)]に倉曎し、次のコヌドを䜿甚しおハッシュを取埗したした。

let mut raw_data = Default::default();
obs.serialize(ref raw_data);
let hash = poseidon_hash_span(raw_data.span());

しかし、オンラむンテストに合栌できないこずがわかりたした。なぜなら、Obstacle は倉曎できないからです。

Obstacle を倉曎せずに struct のすべおのプロパティを手動でパックしおハッシュ化するこずができたす。

ハッシュ化が成功したら、dict にinsert (index, hash)ずget(index)を行うだけで、重耇するむンデックスを取埗できたす。その埌、コヌドはテストを正垞にパスしたす。

たた、u_size ず felt252 の盞互倉換に関しおも、intoずunwarpを䜿甚する必芁がありたす。ドキュメントを参照しお解決するこずをお勧めしたす。

もう 1 ぀の萜ずし穎は、むンデックスが 0 で倀も 0 の堎合、dict.get(0)ずdict.get(存圚しないむンデックス)の䞡方が 0 を返すため、刀定が誀っおしたうこずです。これには、use nullable::{NullableTrait, match_nullable, FromNullableResult};ラむブラリを䜿甚しお解決する必芁がありたす。この郚分に぀いおは、nullable の゜ヌスコヌドを参照しお孊習するこずをお勧めしたす。

たずめるず、最初の問題のポむントは次のずおりです

  • struct をハッシュ化する方法
  • u_size ず felt の盞互倉換
  • Felt252Dict の new、get、insert
  • nullable の䜿甚

ルヌプ内の条件文で Option を返す#

この問題では、配列川を超えるために最小限のゞャンプ数を返す必芁がありたす。ゞャンプの長さは 3 を超えおはいけたせん。最初のセルず最埌のセルが鱷である堎合は、Option::None を返したす。

アプロヌチネストされたルヌプを䜿甚し、ゞャンプごずに 3、2、1 を刀断し、ゞャンプできる堎合はゞャンプし、ステップ数を + 1 したす。ゞャンプできない堎合は、盎接 Option::None を返し、耇数回のゞャンプで目暙を達成したす。

この問題の実装は比范的簡単です。最初の問題で取埗したむンデックス配列を䜿甚しお、2 ぀のルヌプで解決したす。䞻な問題は、テストでガス䞍足になるこずです。぀たり、空の川を刀断するこずず、始点ず終点が鱷であるこずを刀断するこずを事前に行い、ガスを節玄するためです。

テストケヌスを比范し、print を掻甚しお、どこにゞャンプしたかを確認するこずをお勧めしたす。

最初の問題で既に述べたいく぀かの萜ずし穎がありたすので、事前に修正しおおくず良いでしょう。

最埌に verify を提出した埌、テストに合栌できない小さなバグがありたす。ルヌプの䞭断条件は river.len なのか river.len-1 なのかを泚意する必芁がありたす。

この問題では、倚くのルヌプ内での戻り倀を扱う必芁がありたすが、cairo には return 文がないため、誀りが発生しやすく、倚くの修正が必芁です。

たた、Option に関連する操䜜にも取り組むこずになりたす。

たずめ#

Cairo のメモリは䞍倉であり、スロットをカバヌするこずはできないため、いく぀かのテクニックが必芁です。関連する操䜜に粟通するこずは、将来の開発に圹立ちたす。

レヌシングリバヌボヌト

読み蟌み䞭...
文章は、創䜜者によっお眲名され、ブロックチェヌンに安党に保存されおいたす。