+ محدودیت زمان: ۱ ثانیه
+ محدودیت حافظه: ۲۵۶ مگابایت
----------
در بازی گل یا پوچ سه نفر با هم، همتیمی میشوند. هر کدام دو دست دارند. دست چپ را با $L$ و دست راست را با $R$ نشان میدهیم. پس در مجموع شش دست در بازی هست. در یک دست گل و پنج دست دیگر پوچ است.
بازیکنها را با اعداد ۱ تا ۳ شمارهگذاری میکنیم. در ابتدا گل در دست $x$ بازیکن شمارهی $s$ است که مقدار $x$ برابر $L$ یا $R$ است. بازی شروع میشود و در حین بازی، بازیکنان $n$ حرکت انجام میدهند. حرکتها یکی از حالتهای زیر را دارد:
### خالی بازی $k$
در این حرکت بازیکن شمارهی $k$ محتوای دو دستش را جابهجا میکند. ($k = 1, 2, 3$)
### جابهجایی $k$ و $k+1$
در این حرکت بازیکن شمارهی $k$ محتوای دست $x$ خودش را با محتوای دست $y$ بازیکن $k+1$ جابهجا میکند. ($k = 1, 2$ و $x, y \in \{L, R\}$)
مشتی علی گزارش این $n$ حرکت را به ترتیب به شما میدهد. شما باید شمارهی بازیکنی که گل در دست آن است و اسم دست آن بازیکن را نشان میدهد.
# ورودی
در سطر اول ورودی، عدد صحیح و مثبت $n$ داده میشود.
$$1 \leq n \leq 100$$
در سطر دوم ورودی، عدد $s$ و کاراکتر $x$ داده میشود.
$$s \in \{1, 2, 3\}, \quad x \in \{L, R\}$$
در $n$ سطر بعدی در هر سطر یکی از حرکتها داده میشود.
حرکت نوع اول به صورت $1\ k$ است. که یعنی بازیکن $k$ام محتوای دو دستش را عوض میکند.
$$k \in \{1, 2, 3\}$$
حرکت نوع دوم به صورت $2\ k\ x\ y$ که یعنی بازیکن $k$ام محتوای دست $x$ را به دست $y$ بازیکن $k+1$ام میدهد.
$$k \in \{1, 2\}, \quad x, y \in \{L, R\}$$
# خروجی
در یک سطر، عدد $f$ و کاراکتر $y$ را چاپ کنید که شمارهی بازیکن و دستی که گل در آن است را نشان میدهد.
# مثالها
## ورودی نمونه ۱
```
5
2 L
2 2 R L
2 1 L L
1 1
1 2
1 3
```
## خروجی نمونه ۱
```
1 R
```
## ورودی نمونه ۲
```
2
3 R
1 1
2 1 R R
```
## خروجی نمونه ۲
```
3 R
```
گل یا پوچ ساده
+ محدودیت زمان: ۱ ثانیه
+ محدودیت حافظه: ۲۵۶ مگابایت
----------
باقر و علی میخواهند باهم دارت بازی کنند. تصویر دارت به صورت شکل زیر است:
![توضیح تصویر](https://quera.org/qbox/view/nCT3ZfHJ9E/Dart.svg)
در بازی دارت، قوانین امتیازدهی به این صورت است:
تخته دارت به ۲۰ بخش مساوی تقسیم شده که هر بخش عددی بین ۱ تا ۲۰ را نشان میدهد.
در مرکز تخته دارت یک بخش کوچک به نام «بولسآی» (*Bullseye*) وجود دارد که از دو بخش تشکیل شده است. حلقهی مرکزی کوچکتر، دایرهای با شعاع ۱ سانتیمتر با ۵۰ امتیاز و حلقهی مرکزی بزرگتر، دایرهای با شعاع ۲ سانتیمتر و ۲۵ امتیاز دارد.
اگر دارت به هر بخش از تخته بخورد، **امتیاز همان بخش به بازیکن تعلق میگیرد (یک برابر)**. در اطراف هر عدد، دو حلقه وجود دارد:
**حلقه خارجی (حلقه سهبرابر)**: اگر دارت به این حلقه برخورد کند، امتیاز آن بخش سه برابر میشود. اندازهی این بخش ۱ سانتیمتر است.
**حلقه داخلی (حلقه دوبرابر)**: اگر دارت به این حلقه برخورد کند، امتیاز آن بخش دو برابر میشود. اندازهی این بخش ۱ سانتیمتر است.
**تخته بیرونی (خارج از بخشهای امتیازی)**: دارت به تخته نخورده و امتیازی ندارد.
اندازهی شعاع دایرهی خارجی (با حلقه سهبرابر) ۱۰ سانتیمتر و اندازهی شعاع دایرهی داخلی (با حلقه دوبرابر) ۶ سانتیمتر است.
آنها دچار خطای ارزیابی هستند و اکنون پرتابهای خودشان را روی صفحه انجام دادهاند و سپس میخواهند ترتیب اعداد ۱ تا ۲۰ را طوری تغییر دهند که امتیاز باقر خیلی بیشتر از امتیاز علی شود. آنها نمیتوانند امتیاز بولسآی را تغییر دهند.
حال میدانیم باقر $n$ پرتاب کرده و علی $m$ پرتاب میخواهیم بدانیم در بین تمام عددگذاریهای مختلف در کدام حالت اختلاف امتیاز باقر از علی بیشتر است.
پرتابهای باقر و علی را به صورت $r$ و $\theta$ میدهیم یعنی در چه شعاع و زاویهای دارت پرتاب شده است. مقدار $r$ برحسب سانتیمتر و نشان دهندهی فاصله از مرکز دارت است. همچنین $\theta$ زاویهی نقطهی پرتاب شده از محور $x$ها را نشان میدهد. **برای مثال ناحیهی شمارهی ۱۳ در شکل، زاویهی ۹ تا ۲۷ درجه است.**
تضمین میشود هیچوقت پرتابی به ناحیهی مرزی نمیخورد.
# ورودی
در سطر اول ورودی، دو عدد صحیح و مثبت $n$ و $m$ داده میشود.
$$1 \leq n, m \leq 100$$
در $n+m$ سطر بعدی در هر سطر دو عدد $r$ و $\theta$ داده میشود که $n$ پرتاب اول برای باقر و $m$ تای بعدی برای علی است.
تضمین میشود هیچوقت پرتابی به ناحیهی مرزی نمیخورد.
# خروجی
یک عدد صحیح برابر بیشترین اختلاف امتیازی که میتواند باقر از علی پیدا کند.
# مثالها
## ورودی نمونه ۱
```
3 1
5.285 61.600
1.697 76.563
1.820 226.466
0.820 324.470
````
## خروجی نمونه ۱
```
40
````
در این حالت، باقر ۳ دارت و علی ۱ دارت پرتاب کردهاند. باقر پرتاب دوم و سومش به بولسآی ۲۵ امتیازی و پرتاب علی به بولسآی ۵۰ امتیازی برخورد کرده است. پرتاب اول باقر در حلقهی داخلی (دو برابر) خورده است. بنابراین اگر امتیازها را طوری تغییر دهیم که ۲۰ امتیاز روی آن قطعه قرار بگیرد، اختلاف امتیاز باقر و علی بیشینه و برابر است با:
$$2 \times 20 + 25 + 25 - 50 = 40$$
## ورودی نمونه ۲
```
2 2
1.790 119.791
9.260 178.282
0.850 166.297
9.538 31.585
````
## خروجی نمونه ۲
```
32
````
در این حالت، باقر و علی هر کدام ۲ دارت پرتاب کردهاند. پرتاب اول باقر به بولسای ۲۵ امتیازی و پرتاب اول علی به بولسآی ۵۰ امتیازی برخورد کرده است. پرتابهای دوم باقر و علی هر دو به حلقههای بیرونی (سه برابر) خورده است ولی در دو ناحیهی مختلف. اگر اعداد ۱ تا ۲۰ را طوری قرار دهیم که ناحیهی باقر ۲۰ امتیاز و ناحیهی علی ۱ امتیاز داشته باشد، اختلاف امتیاز باقر و علی بیشینه و برابر است با:
$$25 + 3 \times 20 - 50 - 3 \times 1 = 32$$
دارت بازی
+ محدودیت زمان: ۱ ثانیه
+ محدودیت حافظه: ۲۵۶ مگابایت
----------
در یک شرکت $n$ برنامهنویس مشغول به کار هستند. هر کدام از این $n$ نفر در برخی از زمینههای `Front-end`، `Back-end` یا `Product Mangement` تخصص دارد.
تخصصهای هر شخص را با یک رشته شامل حروف `B`، `F` و `P` به صورت مرتبشده الفبایی به ما داده شده است.
میخواهیم با داشتن این تخصصها، حداکثر تعدادی تیم کامل را تشکیل دهیم. منظور از یک تیم کامل تیمی است که در آن برای هر کدام از این سه زمینه حداقل یک متخصص وجود داشته باشد. هر شخص باید دقیقاً یک سمت را داشته باشد و نمیتواند بخاطر تخصصش در دو زمینه نیاز تیم را در هر دو زمینه برطرف کند. توجه کنید باید در این تیمبندی هر شخص در حداکثر یک تیم آمده باشد.
حال از شما میخواهیم برنامهای بنویسید که این بیشترین تعداد تیم را محاسبه کند.
# ورودی
در سطر اول ورودی، عدد صحیح و مثبت $t$ آمده که تعداد تستها را نشان میدهد.
$$1 \leq t \leq 10 \,000$$
در سطر اول هر تست، عدد صحیح و مثبت $n$ داده میشود که تعداد برنامهنویسها را نشان میدهد.
$$1 \leq n \leq 100$$
در $n$ سطر بعدی در هر سطر یک رشته داده میشود که رشتهی سطر $i$ام تخصص برنامهنویس $i$ام را نشان میدهد.
# خروجی
در تنها سطر خروجی، یک عدد صحیح برابر بیشترین تعداد تیم کامل را چاپ کنید.
# مثالها
## ورودی نمونه ۱
```
3
5
B F P BFP BF
6
BF BP FP B BFP P
2
B BFP
````
## خروجی نمونه ۱
```
1
2
0
````
در نمونهی اول تیمبندی میتواند به صورت زیر باشد:
$$\{B, F, P\}$$
در نمونهی دوم تیمبندی میتواند به صورت زیر باشد:
$$\{BF, BP, FP\} \quad \{B, BFP, P\}$$
در نمونهی سوم سه نفری وجود ندارد که بتوانند تیم تشکیل بدهند.
تیمهای توسعه منظم
**کد شما باید روی PostgreSQL قابل اجرا باشد.**
---
# جزئیات پایگاهداده
دیتابیسی که در این سوال به آن میپردازیم، متشکل از اطلاعات تعدادی کاربر، شرکت و محصولات شرکتها خواهد بود.
دادههای اولیه را از [این لینک](/contest/assignments/73612/download_problem_initial_project/253326/) دانلود کنید.
<details class="yellow">
<summary>
**ایمپورت کردن دادههای اولیه**
</summary>
از نصب بودن *PostgreSQL* روی سیستم خود اطمینان حاصل کنید.
برای ایمپورت کردن دادههای اولیه میتوانید از یکی از دو روش زیر اقدام کنید:
۱- با استفاده _CLI_ دستور زیر را وارد کنید تا دادههای اولیه ایمپورت شوند:
```shell
psql -U postgres -f /path/to/initial.sql
```
که در این دستور مسیر فایل `initial.sql` را به صورت مطلق یا نسبی میتوانید آدرسدهی کنید.
۲- اگر _GUI_ را ترجیح میدهید، پس از نصب دیتاگریپ و اتصال به _PostgreSQL_ با یوزر `postgres`، باید روی دیتاسورس و کانکشن `postgres` راستکلیک کنید و از منوی `SQL Scripts`، گزینهی `Run SQL Script` را انتخاب کنید. سپس فایل `initial.sql` را پیدا و تایید کنید. در انتها روی `Run` کلیک کنید تا اسکریپت اجرا شود و دادهها وارد دیتابیس شوند.
</details>
<details class="grey">
<summary>
**توضیحات جداول دیتاست**
</summary>
### جدول `address` (آدرسها)
این جدول اطلاعات مربوط به آدرسها را ذخیره میکند.
| نام ستون | نوع داده | توضیحات |
|----------------|----------------|------------------------------------|
| `id` | `integer` | شناسهی یکتا برای آدرس (کلید اصلی) |
| `city` | `varchar(100)` | شهر |
| `country` | `varchar(100)` | کشور |
| `country_code` | `varchar(100)` | کد کشور |
| `zip_code` | `integer` | کد پستی |
### جدول `company` (شرکتها)
این جدول اطلاعات مربوط به شرکتها را ذخیره میکند.
| نام ستون | نوع داده | توضیحات |
|--------------|----------------|---------------------------------------------------|
| `id` | `integer` | شناسهی یکتا برای شرکت (کلید اصلی) |
| `name` | `varchar(100)` | نام شرکت |
| `address_id` | `bigint` | شناسهی آدرس مرتبط (کلید خارجی به جدول `address`) |
### جدول `product` (محصولات)
این جدول اطلاعات مربوط به محصولات را ذخیره میکند.
| نام ستون | نوع داده | توضیحات |
|------------|----------------|-------------------------------------|
| `id` | `integer` | شناسهی یکتا برای محصول (کلید اصلی) |
| `name` | `varchar(100)` | نام محصول |
| `category` | `varchar(100)` | دستهبندی محصول |
| `price` | `integer` | قیمت محصول |
### جدول `product_company` (شرکت-محصول)
این جدول یک رابطهی چند به چند بین شرکتها و محصولات ایجاد میکند.
| نام ستون | نوع داده | توضیحات |
|--------------|-----------|----------------------------------------------|
| `id` | `integer` | شناسهی یکتا برای رابطه (کلید اصلی) |
| `company_id` | `bigint` | شناسهی شرکت (کلید خارجی به جدول `company`) |
| `product_id` | `bigint` | شناسهی محصول (کلید خارجی به جدول `product`) |
### جدول `user` (کاربران)
این جدول اطلاعات مربوط به کاربران را ذخیره میکند.
| نام ستون | نوع داده | توضیحات |
|--------------|-----------|---------------------------------------------------|
| `id` | `integer` | شناسهی یکتا برای کاربر (کلید اصلی) |
| `first_name` | `text` | نام کاربر |
| `last_name` | `text` | نام خانوادگی کاربر |
| `email` | `text` | ایمیل کاربر |
| `address_id` | `integer` | شناسهی آدرس مرتبط (کلید خارجی به جدول `address`) |
| `company_id` | `integer` | شناسهی شرکت مرتبط (کلید خارجی به جدول `company`) |
| `username` | `text` | نام کاربری |
این جداول دارای روابطی هستند که به کمک کلیدهای خارجی بین جداول ایجاد شدهاند. برای مثال، هر شرکت میتواند یک آدرس داشته باشد و هر کاربر نیز میتواند یک شرکت و یک آدرس داشته باشد.
</details>
# مطلوبات
کوئریهایی بنویسید که خروجیهای مطلوب زیر را بهدست آورد (توجه کنید که هر کوئری نمرهای جداگانه دارد و اگر کوئری قسمتی را نتوانستید بنویسید، کوئریهایی که حل کردید را بفرستید و کوئری آن قسمت را خالی بگذارید):
1. آیدی، نام کوچک، فامیلی و نام کاربری تمام کاربرانی که نام کوچک (`first_name`) آنها با حرف **s** و فامیلی (`last_name`) آنها با حرف **e** تمام میشود. کوچک یا بزرگ بودن حروف مهم نیست و رکوردها باید براساس آیدی به صورت صعودی مرتب شوند.
<details class="blue">
<summary>
*نمونه خروجی کوئری اول*
</summary>
ساختار نتیجهی کوئری و سطر اول آن، به شکل زیر است:
| id | first_name | last_name | username |
|:-----|:-----------|:----------|:----------|
| 6916 | Sarah | George | patrick32 |
</details>
2. نام شرکت و مجموعهای از محصولاتی که متعلق به آن شرکت هستند. رکوردها براساس تعداد محصولات شرکت به صورت نزولی مرتب میشوند، در صورت برابر بودن تعداد محصولات دو شرکت، ترتیب صعودی آیدی آنها اولویت دارد.
<details class="blue">
<summary>
*نمونه خروجی کوئری دوم*
</summary>
## نمونه خروجی کوئری دوم
ساختار نتیجهی کوئری و سطر اول آن، به شکل زیر است:
| company_name | product_list |
|:-------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Movies | {Hair Care Component,Fitness Equipment,Home Improvement Rig,Truck Item,Furniture Whatchamacallit,Music Widget,Party Gear,Mens Device,Aquarium Instrument,Movie Paraphernalia,Camera Attachment,Skin Care Implement,Makeup Gadget,Party Gadget,Personal Implement,Swimming Rig,Gardening Mechanism,Nutrition Component,Book Machine,Party Mechanism} |
</details>
3. در این کوئری باید آدرس شرکتی که کاربر در آن حضور دارد و نام کاربری او را برگردانید. در صورتی که کاربر در شرکتی حضور نداشت یا شرکتی که کاربر در آن حضور دارد، آدرسی نداشت، آدرسی را که در جدول کاربران برای کاربر مشخص شده است، برگردانید. خروجی باید به ترتیب صعودی آیدی کاربران مرتب شده باشد. ترتیب قرار گیری آدرس در ستون `user_address` به صورت روبرو است: ```Country, City, Zip Code```
<details class="blue">
<summary>
*نمونه خروجی کوئری سوم*
</summary>
ساختار نتیجهی کوئری و سه سطر اول خروجی به شکل زیر است:
| username | user_address |
|:------------|:-------------------------------|
| markbaker | Moenstead, Palestine, 4972 |
| garciaamy | Murphyton, French Guiana, 5765 |
| jonesandrea | Bauchland, Panama, 8125 |
</details>
4. در این کوئری از شما میخواهیم با جستوجو در جدول محصولات، یک جدول با فیلدهای زیر را برگردانید:
+ نام، قیمت و کتگوری محصول
+ نام و شهرِ شرکت محصول
+ در انتها یک فیلد که در آن اگر قیمت محصول از میانگین قیمت کل محصولات بیشتر بود، `expensive` و اگر قیمت آن از میانگین کل محصولات کمتر بود `not expensive` قرار میگیرد.
+ خروجی باید براساس آیدی محصول مرتب شده باشد.
<details class="blue">
<summary>
*نمونه خروجی کوئری چهارم*
</summary>
سه سطر ابتدایی خروجی به شکل زیر خواهد بود:
| product\_name | product\_price | product\_category | company\_name | company\_city | price\_comparison |
|:-------------------|:---------------|:------------------|:--------------|:--------------|:------------------|
| Bedding Attachment | 14 | Home | Shoes | Corkeryland | not expensive |
| Dining Contraption | 112 | Home | Grocery | Hartford | expensive |
| Truck Kit | 27 | Automotive | Tools | North Burley | not expensive |
</details>
# فایل نهایی
پس از پیادهسازی کوئریها، آن را در فایل `queries.sql`، وارد کرده و سپس این فایل را آپلود کنید. کد شما باید به صورت زیر
باشد:
```sql
-- Section1
Your first query here
-- Section2
Your second query here
-- Section3
Your third query here
-- Section4
Your fourth query here
```
اطلاعات کاربران
**برای این سوال، نسخهی داتنت شما باید ۷ باشد.**
----------
![اندیس](https://quera.org/qbox/view/7PlWCxxoTi/D.png)
شما به قبل سال `2000` برگشتهاید، زمانی که فناوری دیتابیسها به تازگی در حال ظهور است و مهندسان در تلاشند تا راهحلهای نوآورانهای برای جستجوی اطلاعات پیدا کنند. بسیاری از آنها از ایدههای جدید شگفتزده شده و دنیای فناوری اطلاعات در آستانهی تغییرات شگرفی است.
شما که از آینده خبر دارید، تصمیم گرفتهاید سیستم ابتدایی `Full-Text Search` را پیادهسازی کنید. با این اختراع، شما نه تنها دنیای جستجو را متحول میکنید بلکه تاریخ را نیز تحت تأثیر قرار خواهید داد و این اختراع را به نام خود ثبت خواهید کرد.
# جزئیات پروژه
پروژهی اولیه را از [این لینک](/contest/assignments/73612/download_problem_initial_project/253328/) دانلود کنید. ساختار فایلهای پروژه بهصورت زیر است:
```cs
└── SearchEngine
├── Document.cs
├── Index.cs
├── Program.cs
├── Query.cs
└── SearchEngine.csproj
```
شما باید سه کلاس `Document`، `Index` و `Query` را مطابق با مواردی که در ادامه مطرح میشود، کامل کنید.
## کلاس `Document`
اولین کلاسی که باید تکمیل کنید کلاس `Document` است. این کلاس بدنه اصلی داکیومنتهای شما را برای اندیس مشخص میکند و باید شامل ویژگیهای(property) زیر باشد:
| نام | نوع |
|:----------:|:------------------:|
| Id | `long` |
| Text | `string` |
| Date | `DateTime` |
## کلاس `Query`
این کلاس شامل ویژگیهای کوئری است که قصد دارید طبق این ویژگیها داکیومنتهایی را از درون اندیس بازیابی کنید. این کلاس شامل ویژگیهای زیر میشود:
| نام | نوع |
|:----------:|:------------------:|
| Text | `string` |
| Date | `DateTime` |
| EndDate | `DateTime` |
## کلاس `Index`
این کلاس اصلیترین کلاسی است که باید پیادهسازی کنید. این کلاس شامل داکیومنتها و اندیسها میشود. اندیسهای این کلاس در واقعا [اندیسهای معکوس](https://en.wikipedia.org/wiki/Inverted_index) (Inverted index) به هر داکیومنت هستند.
```cs Index.cs
namespace SearchEngine;
public class Index
{
private List<Document> documents = new();
private Dictionary<string, HashSet<long>> textIndex = new();
private SortedDictionary<DateOnly, HashSet<long>> dateIndex = new();
public Index() { }
public Index(string filePath)
{
throw new NotImplementedException();
}
public void IndexDocument(Document document)
{
throw new NotImplementedException();
}
public void SaveIndexToFile(string filePath)
{
throw new NotImplementedException();
}
public List<Document> Search(Query query)
{
throw new NotImplementedException();
}
}
```
همانطور که میبینید، دو اندیس `textIndex` و `dateIndex` وجود دارند که نحوه ساخت این اندیسها در ادامه آورده شده است. مطابق این فایل، شما در این کلاس باید یک کانستراکتور و سه متد که در ادامه جزئیات آنها ذکر میشود را پیادهسازی نمایید:
کانستراکتور `Index`: این کانستراکتور فایلی که در مسیر ورودی دریافت کرده را به صورت متن خوانده و اندیسهای گفته شده را باید به درستی مقداردهی کند.
متد `saveIndexToFile`: این متد یک مسیر را دریافت و کل کلاس `Index` را با تمام مقادیرش به صورت متن در این مسیر ذخیره میکند.
متد `indexDocument`: این متد یک داکیومنت را دریافت میکند و اندیسهای گفته شده را به صورت زیر ایجاد میکند:
+ برای ساخت `textIndex` باید ویژگی `text` هر داکیومنت براساس کاراکترهای غیر کلمهای (حرف، رقم یا `_`) شکسته شود و داکیومنتها اندیس شوند.
+ برای ساخت `dateIndex` هر داکیومنت براساس ویژگی `date` خودش اندیس میشود.
متد `search`: این متد وظیفه دارد تا داکیومنتهایی را براساس کوئری ورودی برگرداند. هر کدام از ویژگیهای کلاس `Query` میتواند نال باشند ولی در صورتی که هر کدام از مقادیر نال نبود باید داکیومنتهایی براساس اولویت زیر برگردانده شوند:
1. متن
2. بازه زمانی (این به این معنی است که اگر در کوئری بازه زمانی وارد شده بود، این بازه اولویت بیشتری دارد)
3. زمان دقیق
# مثال
مثالهایی به صورت تست نمونه در اختیار شما قرار داده شده است که میتوانید از آنها کمک بگیرید. به عنوان مثال به مورد زیر دقت کنید:
```cs
Index index = new Index();
index.IndexDocument(new Document(1, "Quera online coding contests", DateTime.Now));
index.IndexDocument(new Document(2, "Quera for programmers", DateTime.Now.AddDays(-4)));
index.IndexDocument(new Document(3, "Practice coding skills", DateTime.Now.AddMonths(-11)));
Query query = new Query("Quera", null, null);
List<Document> result = index.Search(query);
```
خروجی مثال بالا باید داکیومنتها با آیدی `1`و `2` را برگرداند.
# نکات
+ دو کلاس `Document` و `Query` باید شامل کانستراکتوری با همه ویژگیها باشند.
+ **تضمین میشود** داکیومنت با آیدی تکراری وارد نخواهد شد.
+ **دقت کنید** که ساختار ابتدایی کلاسها را تغییر ندهید.
+ **دقت کنید** که کلاسهای شما در صورت لزوم باید قابلیت سریالایز و دسریالایز شدن داشته باشند.
# آنچه باید آپلود کنید
پس از پیادهسازی موارد خواستهشده، فقط این سه کلاس را زیپ کرده و آپلود کنید.
```cs
[your-solution-file].zip
└── SearchEngine
├── Document.cs
├── Index.cs
├── Program.cs
├── Query.cs
└── SearchEngine.csproj
```
سفر در زمان (سیشارپ)
%align_right_start%
#### تعریف اولیه
شما مسئول توسعه یک سیستم بانکی ساده **تحت وب** هستید که شامل چندین قابلیت (Functionality) است. هدف اصلی شما ایجاد و پیادهسازی این قابلیت هاست که در ادامه توضیح داده خواهند شد. همچنین یک پروژه اولیه به شما داده شد است که باید تغییرات خود را بر روی آن اعمال نمایید. پروژه اولیه را از [این لینک](/contest/assignments/73612/download_problem_initial_project/253327/) دانلود کنید.
#### مدل دامنه
در این سیستم، شما چندین مدل مختلف دارید که برای مدیریت و نمایش اطلاعات بانکی استفاده میشوند. مدلهای اصلی شامل موارد زیر هستند:
+ **حساب (Account):** نمایانگر یک حساب بانکی است که شامل اطلاعاتی مانند شماره حساب، موجودی، شماره شبا و ... است.
+ **تراکنش (Transaction):** این مدل نمایانگر تراکنشهای انجام شده برای هر حساب است. اطلاعاتی مانند مبلغ تراکنش، نوع تراکنش (واریز یا برداشت)، تاریخ و ... مرتبط با تراکنش را شامل میشود.
> اطلاعات مربوط به مدل ها را می توانید در بخش **توضیحات ساختار دیتابیس** مطالعه بفرمایید
----------
#### قابلیت های سیستم
این سیستم بانکی شامل چندین قابلیت اصلی است که به کاربران امکان میدهد تا به اطلاعات حساب خود دسترسی پیدا کرده و تراکنشهای مختلفی را انجام دهند. هر یک از این قابلیتها **از طریق APIهای** مخصوص خود باید انجام شوند.
> واحد پولی این سیستم **تومان** است
#### **قابلیت ۱: مشاهده اطلاعات حساب**
سیستم شما باید قادر باشد اطلاعات یک حساب بانکی را نمایش دهد. کاربر با ارائه **کد حساب**، انتظار دارد اطلاعات مربوط به حساب مورد نظر را دریافت کند.
##### **قالب درخواست**
```bash
GET https://localhost:7229/api/account/12345
// 12345 --> Account Number
```
##### **در صورت موفقیت، پاسخ API به صورت زیر خواهد بود**
```json
{
"number": "12345",
"sheba": "IR300560611828005221576101",
"firstName": "علی",
"lastName": "محمدی",
"balance": 4880000,
"creationDate": "2024-10-13"
}
```
#### **قابلیت ۲: انجام تراکنش واریز**
با استفاده از این قابلیت، امکان انتقال پول از یک حساب مبدا به یک حساب مقصد فراهم می شود. این انتقال باید دارای شرایط زیر باشد:
+ ورودیها شامل شماره شبای مقصد، مبلغ واریز و شماره حساب مبدا است
+ مبلغ واریز نباید بزرگتر از موجودی حساب و همچنین سقف روزانه انتقال به مبلغ 200 میلیون تومان باشد در غیر این صورت باید خطایی با متن **"عدم رعایت سقف انتقال"** دریافت شود.
+ مبلغ تراکنش نمی تواند منفی باشد.
+ قالب داده ای شماره شبا مقصد باید صحیح باشد.
+ حساب مبدا و مقصد نمی تواند برابر باشد، یعنی کاربر نمی تواند از یک حساب، به شبای همان حساب پول واریز کند و در صورت چنین ورودیی باید خطای با متن **"حساب مبدا و مقصد نمی تواند یکی باشد"** دریافت شود.
+ به ازای هر درخواست واریز، دو تراکنش با **کد یکسان (Code)** در دیتابیس ذخیره میشود، یک تراکنش با تایپ واریز (_Deposit_) برای حساب مقصد که مبلغ به آن واریز میشود و دیگری یک تراکنش با تایپ برداشت (_Withdrawal_) برای حساب مبدا که مبلغ از آن کسر میشود.
+ بعد از ثبت تراکنش، باید اطلاعات موجودی حساب های مبدا و مقصد نیز بروزرسانی شود
<details class="green">
<summary>
**فرمت استاندارد شماره شبا**
</summary>
شماره شبا در ایران شامل پیشوند **IR** و سپس 24 رقم است (مانند: IR300564661822065022536289).
</details>
##### **قالب درخواست**
```bash
POST https://localhost:7229/api/account/12345/deposit
{
"targetSheba": "IR300560611828005221576101",
"amount": 120000
}
// 12345 --> Account Number
```
##### **در صورت موفقیت، پاسخ API به صورت زیر خواهد بود**
```json
{
"status": "success",
"newBalance": 10360000,
"code": "42a74b17-36c4-497a-913e-e675cd13d5e1"
}
```
#### **قابلیت ۳: مشاهده لیست تراکنشها**
این قابلیت لیستی از تراکنشهای انجام شده هر حساب را بصورت مرتب شده نزولی بر اساس زمان تراکنش نمایش می دهد. اطلاعات شامل کد تراکنش، مبلغ تراکنش، تاریخ، موجودی بعد از تراکنش، شماره شبای بر روی تراکنش، و نوع تراکنش (واریز یا برداشت) میباشد.
##### **قالب درخواست**
```bash
GET https://localhost:7229/api/account/12345/transactions
// 12345 --> Account Number
```
##### **در صورت موفقیت، پاسخ API به صورت زیر خواهد بود**
```json
[
{
"code": "42a74b17-36c4-497a-913e-e675cd13d5e1",
"amount": 120000,
"date": "2024-10-13 12:53",
"relatedSheba": "IR300564661822065022536289",
"postBalance": 4880000,
"type": "Withdrawal"
}
]
```
### نکات
+ در توسعه API های سیستم اصول REST را رعایت بفرمایید
+ ورودی ها را ارزیابی کرده و در صورت نامعتبر بودن داده ها خطای مناسب را برگردانید.
+ وضعیت های مشخصی برای هر خطا وجود دارد که توقع می رود در پاسخ درخواست در نظر بگیرید.
+ بررسی داده های ورودی و مسائل بیزینسی *400 (Bad Request)*
+ عدم وجود منابع مربوط به داده های ارائه شده *404 (Not Found)*
<details class="purple">
<summary>
**توضیحات ساختار دیتابیس**
</summary>
جدول `Accounts`:
| عنوان | نوع | توضیحات |
| ------------ | ---------------- | ------------------------------------------- |
| Number | `TEXT` (string) | شماره حساب منحصر به فرد هر کاربر |
| Sheba | `TEXT` (string) | شماره شبا مرتبط با حساب که منحصر به فرد است |
| FirstName | `TEXT` (string) | نام صاحب حساب |
| LastName | `TEXT` (string) | نام خانوادگی صاحب حساب |
| Balance | `REAL` (decimal) | موجودی حساب |
| CreationDate | `TEXT` (DateTime) | تاریخ ایجاد حساب |
جدول `Transactions`:
| عنوان | نوع | توضیحات |
| ------------------ | ---------------- | ------------------------------- |
| Id | `INTEGER` (int) | شناسه منحصر به فرد هر تراکنش |
| Amount | `REAL` (decimal) | مبلغ تراکنش |
| Code | `TEXT` (string) | کد منحصر به فرد تراکنش های مرتبط |
| Date | `TEXT` (string) | تاریخ انجام تراکنش |
| PostBalance | `REAL` (decimal) | موجودی حساب بعد از انجام تراکنش |
| BaseAccountNumber | `TEXT` (string) | شماره حساب مبدا تراکنش |
| SubAccountNumber | `TEXT` (string) | شماره حساب مقصد تراکنش |
| Type | `TEXT` (TransactionType) | نوع تراکنش (واریز یا برداشت) |
</details>
<details class="yellow">
<summary>
**اطلاعات اولیه دیتابیس**
</summary>
به صورت پیشفرض کاربران زیر در دیتابیس تعریف کنید؛ تا برای تست عملکرد برنامه از آنها استفاده کنید.
**فرد اول:**
- **نام**: علی محمدی
- **شماره حساب**: 12345
- **شماره شبا**: IR300560611828005221576101
- **موجودی اولیه**: 5,000,000 ریال
**فرد دوم:**
- **نام**: محمد سلطانی
- **شماره حساب**: 32312
- **شماره شبا**: IR300564661822065022536289
- **موجودی اولیه**: 10,000,000 ریال
</details>
<details class="red">
<summary>
**آنچه باید آپلود کنید**
</summary>
پاسخ ارسالی شما باید یک فایل _zip_ به همان فرمت پروژه اولیه باشد.
در نظر بگیرید که فایل _zip_ شما باید این ساختار فایل را داشته باشد.
```
├── Banking
│ ├── Banking.csproj
│ ├── Controllers
│ │ └── AccountController.cs
│ ├── Data
│ │ ├── BankingDbContext.cs
│ │ ├── Entities
│ │ │ ├── Account.cs
│ │ │ └── Transaction.cs
│ │ ├── Enums
│ │ │ └── TransactionType.cs
│ │ └── Migrations
│ │ ├── YOUR-MIGRATION-CLASS-HERE
│ │ └── BankingDbContextModelSnapshot.cs
│ ├── Program.cs
│ ├── ViewModels
│ │ ├── AccountResponseVm.cs
│ │ ├── DepositRequestVm.cs
│ │ ├── DepositResponseVm.cs
│ │ └── TransactionResponseVm.cs
│ └── banking.db
└── dotnet-tests.sln
```
در نظر داشته باشید که حتما برای دیتابیس بعد از کانفیگ کردن مدل های خود یک Migration اضافه کنید.
- مایگریشن ها باید در آدرس : `/Data/Migrations` قرار گیرد.
</details>
%align_end%