مسیرها
/
Rust
Rust
/
تمرین‌ها
/
بازی جاسازی‌شده‌ی کم‌مصرف
بازی جاسازی‌شده‌ی کم‌مصرف

بازی جاسازی‌شده‌ی کم‌مصرف

تمرین یادگیری

مقدمه

«تاپل» روشی سبک برای گروه‌کردن مجموعه‌ای ثابت از انواع دلخواه داده در کنار هم است. تاپل اسم خاصی ندارد؛ وقتی به یک ساختار داده اسم می‌دهید، به struct تبدیل می‌شود. فیلدهای تاپل هم اسم ندارند؛ به آن‌ها از طریق «تجزیه» یا بر اساس موقعیت دسترسی پیدا می‌کنید.

نحوه‌ی نگارش

ساخت

تاپل‌ها همیشه با یک عبارت تاپل ساخته می‌شوند:

// pointless but legal
let unit = ();
// single element
let single_element = ("note the comma",);
// two element
let two_element = (123, "elements can be of differing types");

تاپل‌ها می‌توانند تعداد دلخواهی عنصر داشته باشند.

دسترسی با تجزیه

می‌توان با تجزیه به عنصرهای یک تاپل دسترسی پیدا کرد. این یعنی نام متغیرهایی به تک‌تک عنصرهای تاپل نسبت می‌دهیم و در این فرآیند تاپل مصرف می‌شود.

let (elem1, _elem2) = two_element;
assert_eq!(elem1, 123);

دسترسی بر اساس موقعیت

با اندیس موقعیتی عددی هم می‌توان به عنصرهای یک تاپل دسترسی پیدا کرد. اندیس‌گذاری، مثل همیشه، از ۰ شروع می‌شود.

let notation = single_element.0;
assert_eq!(notation, "note the comma");

ساختارهای تاپلی

از شما خواسته می‌شود با ساختارهای تاپلی هم کار کنید. این‌ها مثل ساختارهای معمولی نوع‌های نام‌دار هستند؛ اما برخلاف ساختارهای معمولی، فیلدهای بی‌نام دارند. نحوه‌ی نگارششان بسیار شبیه به نحوه‌ی نگارش تاپل‌های معمولی است. استفاده از هر دو روش تجزیه و دسترسی موقعیتی مجاز است.

struct TupleStruct(u8, i32);
let my_tuple_struct = TupleStruct(123, -321);
let neg = my_tuple_struct.1;
let TupleStruct(byte, _) = my_tuple_struct;
assert_eq!(neg, -321);
assert_eq!(byte, 123);

دیدپذیری فیلدها

همه‌ی فیلدهای تاپل‌های بی‌نام همیشه عمومی هستند. اما فیلدهای ساختارهای تاپلی هرکدام دیدپذیری جداگانه‌ای دارند که به‌طور پیش‌فرض خصوصی است، درست مثل فیلدهای ساختارهای استاندارد. می‌توانید فیلدها را مثل یک ساختار استاندارد با اصلاح‌کننده‌ی pub عمومی کنید.

// fails due to private fields
mod tuple { pub struct TupleStruct(u8, i32); }
fn main() { let _my_tuple_struct = tuple::TupleStruct(123, -321); }
// succeeds: fields are public
mod tuple { pub struct TupleStruct(pub u8, pub i32); }
fn main() { let _my_tuple_struct = tuple::TupleStruct(123, -321); }

دستورالعمل‌ها

شما روی یک بازی کار می‌کنید که برای یک سیستم توکار کم‌مصرف طراحی شده است و باید چندین تابع کمکی بنویسید که بخش‌های دیگر بازی از آن‌ها استفاده خواهند کرد.

1. خارج‌قسمت و باقیمانده‌ی یک تقسیم را محاسبه کنید

خارج‌قسمت، خروجی یک تقسیم است.

fn divmod(dividend: i16, divisor: i16) -> (i16, i16)

مثال:

assert_eq!(divmod(10, 3), (3, 1));

2. عنصرهای واقع در موقعیت‌های زوج را از یک تکرارگر انتخاب کنید

رئیس‌تان قول می‌دهد که این کار برای فعال کردن یک بهینه‌سازی روی بافر صفحه به کارتان می‌آید.

تکرارگرها عنصرهایی هستند که متدهای تعریف‌شده توسط trait Iterator را در اختیار شما می‌گذارند. آن مستندات نسبتاً مفصل است، چون متدهای زیادی ارائه می‌دهند؛ در ادامه مهم‌ترین ویژگی‌هایشان را می‌بینید:

  • یک تکرارگر، جریانی از عنصرها با طول دلخواه است
  • متدی به نام enumerate دارند که برای هر مقدار یک تاپل (i, val) برمی‌گرداند
  • متدی به نام filter دارند که از یک کلوژر استفاده می‌کند تا تعیین کند آیا عنصری از تکرارگر بازگردانده شود یا نه
  • متدی به نام map دارند که از یک کلوژر برای تغییر دادن عنصرهای تکرارگر استفاده می‌کند

چون تابع شما می‌تواند روی هر نوع تکرارگری اجرا شود، از impl استفاده می‌کند تا نشان دهد این یک نمونه‌ی trait است و نه یک مورد ساده. به همین ترتیب، نحوه‌ی نگارش <Item=T> فقط یعنی اینکه مهم نیست تکرارگر چه نوع عنصری تولید می‌کند؛ تابع شما می‌تواند عنصرهای زوج هر تکرارگری را تولید کند.

fn evens<T>(iter: impl Iterator<Item=T>) -> impl Iterator<Item=T>

مثال‌ها:

let mut even_ints = evens(0_u8..);
assert_eq!(even_ints.next(), Some(0));
assert_eq!(even_ints.next(), Some(2));
assert_eq!(even_ints.next(), Some(4));
assert_eq!(even_ints.next(), Some(6));
let mut evens_from_odds = evens(1_i16..);
assert_eq!(evens_from_odds.next(), Some(1));
assert_eq!(evens_from_odds.next(), Some(3));
assert_eq!(evens_from_odds.next(), Some(5));
assert_eq!(evens_from_odds.next(), Some(7));

3. فاصله‌ی منهتن یک موقعیت از مبدأ را محاسبه کنید

برای راحتی کار با نقشه، یک struct تاپلی به اسم Position دارید:

struct Position(i16, i16);

باید متدی به نام manhattan روی Position پیاده‌سازی کنید که فاصله‌ی منهتن آن موقعیت از مبدأ (Position(0, 0)) را برمی‌گرداند.

impl Position {
    fn manhattan(&self) -> i16
}

مثال:

assert_eq!(Position(3, 4).manhattan(), 7);
ویرایش از طریق GitHub این لینک در پنجره یا زبانه‌ی جدیدی باز می‌شود
Rust Exercism

آماده‌اید بازی جاسازی‌شده‌ی کم‌مصرف را شروع کنید؟

در Exercism ثبت‌نام کنید تا Rust را همراه با 99 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.