یک دسترسی خیلی ساده


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

جزئیات پروژه🔗

پروژه‌ی اولیه را از این لینک دانلود کنید.

بله دو تابع GetUserPermissions‍ و SetUserPermissions را برای مدیریت دسترسی‌ها در فایل main.go در نظر گرفته است:

  • تابع GetUserPermissions‍ یک ورودی از نوع ‍int8 می‌پذیرد که هر بیت آن عدد نشان‌دهنده‌ی هر یک از دسترسی‌ها است و به‌عنوان خروجی، یک ساختار به نام Permissons را بر می‌گرداند که شامل دسترسی‌های مختلف از نوع ‍bool است.
  • تابع SetUserPermissions یک ساختار Permissions را به‌عنوان ورودی دریافت کرده و یک عدد از نوع int8 را برمی‌گرداند.

بله برای این کار ۶ دسترسی در نظر گرفته که به‌ترتیب از کم‌ارزش‌ترین بیت به پرارزش‌ترین بیت در زیر آمده‌اند:

canSeeMessages (کم‌ارزش‌ترین بیت)
‍canDeleteMessages
canEditMessages
canKickMembers
canMakeMembersAdmin
canAddMembers
Plain text

حال، او از شما خواسته تا این دو تابع را پیاده‌سازی کنید تا او بتواند بهتر از گذشته کانال‌هایش را مدیریت کند.

آن‌چه باید آپلود کنید🔗

پس از پیاده‌سازی توابع، فایل main.go را آپلود کنید. در صورتی که از dependency خاصی استفاده کرده‌اید، فایل‌های go.mod و go.sum را به‌همراه فایل main.go زیپ کرده و آن را آپلود کنید.

بله یا خیر؟


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

پس از جلسات متعدد تیم در این زمینه، به این نتیجه رسیدند که کل نیازهایشان با دو ساختار شرطی و حلقه برطرف می‌شود و باقی موارد اضافی هستند آن‌ها و از زبان خود حذف کردند. هم‌چنین، به نظر آن ها کل کد را می‌توان در یک خط نوشت.

به همین خاطر، آن‌ها تصمیم گرفتند به جای کلیدواژه‌ی if از کلیدواژه‌ی ‍‍‍bale استفاده کنند و پایان آن را با kheir نشان دهند. هم‌چنین، آن‌ها تصمیم گرفتند به‌جای کلیدواژه‌ی for از کلیدواژه‌ی areh استفاده کنند و پایان آن را با na نمایش دهند. آن‌ها پس از طراحی زبان موردنظر خود، نیاز به یک مترجم برای زبان خود داشتند که بگوید آیا زبانشان قابل ترجمه هست یا خیر، اما با توجه به وقت کم و کار بسیارشان، از شما کمک خواستند تا این کار را برایشان انجام دهید.

ورودی🔗

در یک خط از ورودی استاندارد، یک رشته به‌عنوان کدی که شما باید آن را ترجمه کنید وارد می‌شود. ترجمه به این‌صورت است که هر bale باید حتماً با kheir و هر areh با na تمام شود و این کلید واژه‌ها باید به صورت متوازن در کد قرار گرفته باشند.

تضمین می‌شود که در کد ورودی، کاراکتر whitespace وجود ندارد.

خروجی🔗

اگر زبان قابل ترجمه بود، در خروجی استاندارد YES و در غیر این‌صورت، ‍NO را چاپ کنید.

برای درک بهتر سؤال، به مثال‌ها توجه کنید.

مثال🔗

ورودی نمونه ۱🔗

balex==1arehy==1y++nakheir
Plain text

خروجی نمونه ۱🔗

‍‍‍YES
Plain text

ورودی نمونه ۲🔗

baleball==1na
Plain text

خروجی نمونه ۲🔗

NO
Plain text

ورودی نمونه ۳🔗

balearehkheirna
Plain text

خروجی نمونه ۳🔗

NO
Plain text

نکات🔗

  • امکان استفاده از کتاب‌خانه‌هایی که به‌صورت پیش‌فرض در Go موجود نیستند وجود ندارد.
  • کد شما باید در پکیج main باشد.

آن‌چه باید آپلود کنید🔗

پس از پیاده‌سازی موارد خواسته‌شده، یک فایل با پسوند .go آپلود کنید.

پیام‌رسان ساده‌ی بله


در این سؤال، شما باید Bale را پیاده‌سازی کنید!

جزئیات پروژه🔗

پروژه‌ی اولیه را از این لینک دانلود کنید.

متدهایی که باید پیاده‌سازی کنید به شرح زیر هستند:

  • متدAddUser: این متد یک کاربر جدید ایجاد می‌کند. این متد دو مقدار ورودی می‌گیرد. اولین مقدار، نام کاربری و دومین مقدار، مشخص‌کننده‌ی نوع کاربر است. نام کاربری مقداری یکتا است و باید دارای طول بیش‌تر از ۳ باشد. هم‌چنین، نام کاربری باید هم شامل حروف انگلیسی و هم ارقام باشد. اگر هر یک از این شرایط برقرار نبود، این متد خطا با پیام invalid username را برمی‌گرداند. در حالتی که خطایی وجود نداشته باشد، این تابع خطا برابر با nil و آی‌دی کاربر را برمی‌گرداند. آی‌دی کاربران از عدد ۱ شروع شده و در هر ایجاد کاربر جدید، یک واحد به آن افزوده می‌شود.

  • متد AddChat: این متد یک چت جدید ایجاد می‌کند. این متد چهار ورودی دارد. اولین ورودی، نام چت است. دومین ورودی، نوع چت را مشخص می‌کند که می تواند از نوع کانال یا گروه باشد. سومین ورودی، آی‌دی سازنده‌ی چت است. در نهایت، آخرین ورودی آرایه‌ای از آی‌دی‌هاست که نشان‌دهنده‌ی ادمین‌های چت است. تضمین می‌شود که آی‌دی سازنده حتماً در این آرایه وجود دارد. سازنده‌ی چت نمی‌تواند بات باشد و در این حالت، متد ارور با پیام could not create chat را برمی‌گرداند. در صورت موفقیت‌آمیز بودن عملیات، این متد آی‌دی چت را برمی‌گرداند. آی‌دی چت‌ها نیز مانند آی‌دی کاربران ایجاد می‌شود.

  • متد SendMessage: از این متد برای ارسال پیام به یک چت استفاده می‌شود. اولین ورودی این تابع، کاربری است که می‌خواهد این پیام را ارسال کند. دومین ورودی، آی‌دی چتی است که پیام در آن ارسال می‌شود. آخرین ورودی، متن پیام است. در چت‌هایی که از نوع کانال هستند، تنها ادمینهای کانال می توانند پیام ارسال کنند و اگر کاربری که در کانالی ادمین نیست بخواهد در آن کانال پیام ارسال کند، این متد یک ارور با پیام user could not send message برمی‌گرداند. در صورت موفقیت‌آمیز بودن عملیات، این متد باید آی‌دی پیام را برگرداند. آی‌دی پیام‌ها نیز مانند آی‌دی کاربران ایجاد می‌شود.

  • متدSendLike: این متد برای لایک کردن یک پیام خاص کاربرد دارد. هر کاربر هر پیام را تنها یک بار می‌تواند لایک کند. اگر کاربری بخواهد یک پیام را بیش از یک بار لایک کند، باید ارور با پیام ‍this user has liked this message before را برگردانید. اگر پیام وجود نداشت،‌ این متد ارور با پیام ‍message not found را برمی‌گرداند.

  • متد GetNumberOfLikes: این متد، تعداد لایک‌های یک پیام را برمی‌گرداند. مقدار ارور خروجی باید nil باشد. تضمین می‌شود که پیامی با آی‌دی ورودی در بین پیام‌ها موجود است.

  • متدSetChatAdmin: این متد یک کاربر مشخص را تبدیل به ادمین در یک چت مشخص می‌کند. اگر کاربر در حال حاضر ادمین آن چت باشد،‌ این متد یک ارور با پیام user is already admin را برمی‌گرداند.

  • متد GetLastMessage: این متد، متن پیام و آی‌دی آخرین پیام در چت مشخص شده را برمی‌گرداند.

  • متدGetLastUserMessage: این متد، متن پیام و آیدی آخرین پیامی که کاربر مشخص‌شده ارسال کرده است را برمی‌گرداند.

نکات🔗

  • داده ساختارهای موردنیاز خود را در BaleImpl تعریف کنید.
  • برای ساخت یک ‍Bale جدید، از ‍NewBaleImpl استفاده می‌شود. مقداردهی اولیه‌ی داده ساختارهای خود را در این تابع قرار دهید.

آن‌چه باید آپلود کنید🔗

پس از پیاده‌سازی موارد خواسته شده، فایل main.go را آپلود کنید. در صورتی که از dependency خاصی استفاده کرده‌اید، فایل‌های go.mod و go.sum را به‌همراه فایل main.go زیپ کرده و آن را آپلود کنید.

بازوهای بله


بازوها در بله برای این که بتوانند درخواست‌هایشان را مطرح کنند از JSON استفاده می‌کنند، اما درخواست‌هایشان از قاعده‌ی خاصی پیروی نمی‌کند. بله که از این وضعیت خسته شده، از شما خواسته تا این درخواست‌ها را برایش ترجمه کنید و در قالب یک ساختار مشخص به او بدهید.

جزئیات پروژه🔗

پروژه‌ی اولیه را از این لینک دانلود کنید.

در این سؤال شما باید یک فایل JSON را که در کنار فایل اجرایی قرار دارد بخوانید و آن را تبدیل به ساختار ‍SendMessage کنید.

فیلدهای JSON ورودی به‌شرح زیر هستند:

  • فیلد chat_id : این فیلد یک عدد صحیح ۶۴ بیتی است که در ورودی می‌تواند به‌صورت عدد یا رشته داده شود. در ساختار خروجی، این فیلد باید دارای نوع رشته باشد. برای مثال در ورودی، این فیلد می‌تواند به صورت 123 و یا "123" داده شود، و مقداری که در ساختار برای این فیلد ذخیره می‌شود به‌صورت "123" است. این فیلد حتماً باید در فایل ورودی وجود داشته باشد و در غیر این‌صورت، باید ارور با پیام chat_id is empty برگردانید.

  • فیلد text: این فیلد مشخص‌کننده‌ی متن پیام بوده و از نوع رشته است. این فیلد نیز حتماً باید در ورودی وجود داشته باشد و رشته‌ی خالی نباشد. در غیر این‌صورت، باید ارور با پیام ‍text is empty را برگردانید.

  • فیلدparse_mode: این فیلد از نوع رشته است، اما می‌تواند در JSON ورودی نباشد (فیلدی ضروری نیست).

  • فیلد reply_markup: این فیلد از نوع ReplyMarkup بوده و فیلدی ضروری نیست و می‌تواند در ورودی نباشد. مقدار این فیلد، خود یک object است که حالت‌های زیر را می‌تواند داشته باشد:

{
        "keyboard" : [[{"text" : string, "request_contact" : bool, "request_location" : bool}]]
        "resize_keyboard" : bool
        "one_time_keyboard" : bool
        "selective" : bool
}
JSON

در این حالت، سه مقدار resize_keyboard و one_time_keyboard و selective از نوع bool هستند و فیلدهای ضروری نیستند. keyboard در این حالت فیلدی ضروری است و مقدار آن آرایه‌ای از آرایه‌هایی است که هر عنصر آن یک object با سه فیلد text و request_contact و request_location است. فیلدهای request_location و request_contact از نوع bool بوده و اجباری نیستند.

{
     "keyboard" : [[string, string]]
     "resize_keyboard" : bool
     "one_time_keyboard" : bool
     "selective" : bool
 }
JSON

تفاوت این حالت با حالت قبلی، تنها در این است که در این حالت، مقدار keyboard به صورت آرایه‌ای از آرایه‌هایی است که هر عنصر آن یک رشته است. در این حالت، هر رشته باید به‌عنوان مقدار برای کلید text درنظر گرفته شود.

{
   "inline_keyboard" : [[{"text" : string, "callback_data" : string, "url" : string}]]
}
JSON

در این حالت، یک فیلد ضروری inline_keyboard داده می‌شود که آرایه‌ای از آرایه‌هایی است که هر عنصر آن یک object است که در آن سه فیلد text و callback_data و url قرار دارد. دو فیلد callback_data و url ضروری نیستند.

{
   "inline_keyboard" : [[string, string]]
}
JSON

تفاوت این حالت با حالت قبلی، تنها در این است که در این حالت، مقدار inline_keyboard به‌صورت آرایه‌ای از آرایه‌هایی است که هر عنصر آن یک رشته است. در این حالت، هر رشته باید به‌عنوان مقدار برای کلید text در نظر گرفته شود.

توجه داشته باشید که هر یک از حالت‌های بالا می‌توانند در JSON ورودی به صورت رشته باشد. برای مثال، حالت دوم می تواند در فایل ورودی به‌صورت زیر باشد‌:

"{\"keyboard\" : [[\"string\",\"string\"], [\"string\", \"string\"]]}"
JSON

تابع ‍ReadSendMessageRequest(fileName string) را به‌گونه‌ای پیاده کنید که نام فایل را به‌عنوان ورودی دریافت کرده و JSON درون فایل را به ساختار SendMessage تبدیل کند. اگر خطایی وجود نداشت (تنها دو خطای گفته‌شده با متن خطای مشخص‌شده ممکن است رخ دهد و خطای دیگری وجود ندارد)، یک اشاره‌گر به این ساختار برگردانید و مقدار ارور را نیز nil برگردانید. در صورت وجود خطا، مقدار اشاره‌گر را nil و مقدار ارور را با خطای مناسب برگردانید.

آن‌چه باید آپلود کنید🔗

پس از پیاده‌سازی موارد خواسته شده، فایل main.go را آپلود کنید. در صورتی که از dependency خاصی استفاده کرده‌اید، فایل‌های go.mod و go.sum را به‌همراه فایل main.go زیپ کرده و آن را آپلود کنید.

کانال‌های یک‌بارمصرف


بله می‌خواهد به همه‌ی کانال‌های خود یک پیام واحد ارسال کند، اما متأسفانه بعضی از کانال‌ها بسته شده‌اند و دیگر پیامی نمی‌پذیرند. هم‌چنین، بعضی از کانال‌ها وضعیت نامشخصی دارند و بله نمی‌تواند تشخیص دهد که این کانال‌ها در چه زمانی باز و در چه زمانی بسته هستند.

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

جزئیات پروژه🔗

پروژه‌ی اولیه را از این لینک دانلود کنید.

در این سؤال، شما باید تابع ‍Solution را پیاده‌سازی کنید. این تابع سعی می‌کند که در d ثانیه، پیام مشخص‌شده را در کانال‌های ورودی باز بریزد. دقت کنید که پیام در کانال‌ها باید حداکثر یک بار نوشته شود. هم‌چنین، ممکن است که در این مدت، حالت کانال‌ها تغییر کند. در نهایت، شما باید یک عدد برگردانید که نشان‌دهنده‌ی تعداد کانال‌هایی است که توانسته‌اید پیام را در آن‌ها قرار دهید.

آن‌چه باید آپلود کنید🔗

پس از پیاده‌سازی موارد خواسته شده، فایل main.go را آپلود کنید. در صورتی که از dependency خاصی استفاده کرده‌اید، فایل‌های go.mod و go.sum را به‌همراه فایل main.go زیپ کرده و آن را آپلود کنید.

علی کنجکاو - دیتابیس


کد شما باید روی نسخه‌ی استاندارد PostgreSQL قابل اجرا باشد.


علی پسر کنجکاوی است. او پس از این که دور‌ی کارآموزی‌اش را گذرانده و در بله ماندگار شده، دلش می‌خواهد کمی اطلاعات از الگوهای رفتاری کاربران به‌دست آورد.

تعدادی سؤال در ذهن علی پیش آمده و علی می‌خواهد به پاسخ این سؤالات برسد. به همین دلیل، باید تعدادی کوئری در دیتابیس اجرا کند. به علی کمک کنید تا به کنجکاوی‌اش برسد :)

جزئیات پروژه🔗

ساختار جداول به‌صورت زیر است:

  1. اطلاعات کاربران (users):
نام ستون نوع تعریف ملاحضات
id INTEGER شناسه‌ی کاربر PRIMARY KEY
name VARCHAR(255) نام
nick VARCHAR(32) نام کاربری
  1. وضعیت بلاک بودن کاربران توسط یکدیگر (relations):
نام ستون نوع تعریف ملاحظات
from_user_id INTEGER شناسه‌ی کاربری که می‌تواند بلاک کند
to_user_id INTEGER شناسه‌ی کاربری که می‌تواند بلاک شود
blocked BOOLEAN وضعیت بلاک بودن کاربر DEFAULT FALSE
blocked_at TIMESTAMP زمان بلاک شدن کاربر DEFAULT NULL
  1. پیام‌ها (messages):
نام ستون نوع تعریف ملاحظات
id INTEGER شناسه‌ی پیام PRIMARY KEY
from_user_id INTEGER شناسه‌ی کاربر ارسال‌کننده‌ی پیام
to_user_id INTEGER شناسه‌ی کاربر دریافت‌کننده‌ی پیام
body BYTEA متن پیام
created_at TIMESTAMP زمان ارسال شدن پیام
edited_at TIMESTAMP زمان آخرین ویرایش پیام (در صورت ویرایش شدن)
deleted_at TIMESTAMP زمان حذف پیام (در صورت حذف شدن)

سؤالات ذهن آشفته‌ی علی به‌شرح زیر هستند:

  1. شناسه‌ی کاربرانی که نام کاربری (nick) آن‌ها با am شروع می‌شود به‌ترتیب صعودی
  2. شناسه‌ی کاربرانی که حداقل یک کاربر را بلاک کرده‌اند به‌ترتیب صعودی
  3. شناسه‌ی پیام‌هایی که کاربران در چت‌های خصوصی بلاک‌نشده ارسال کرده‌اند (یعنی در حال حاضر کاربر ارسال‌کننده، کاربر دریافت‌کننده را بلاک نکرده باشد) و قبل از حذف شدن ویرایش شده‌اند به‌ترتیب صعودی (اگر شخص پس از ارسال پیام بلاک شده باشد، پیام‌ها نباید در خروجی موجود باشند.)

نکته: نام ستون خروجی مهم نیست.

آن‌چه باید آپلود کنید🔗

کوئری‌های خود را در قالب زیر، در یک فایل با پسوند .sql قرار داده و آن را ارسال کنید (فایل را زیپ نکنید).

-- Section1
   your 1st query here
-- Section2
   your 2nd query here
-- Section3
   your 3rd query here
SQL