+ محدودیت زمان: ۴ ثانیه (جاوا)
+ محدودیت حافظه: ۲۵۶ مگابایت
----------
*شما قصد دارید تحلیلی برای ارزش سهام رایانکد انجام دهید. برای محاسبهی ارزش سهام در یک روز، تعداد تکرار نام این شرکت در یک کانال تلگرامی را بهعنوان شاخص در نظر میگیرید.*
![توضیح تصویر](https://quera.org/qbox/view/doD4tuwMKG/A.svg)
حال، از شما خواسته شده است برنامهای بنویسید که تعداد دفعات تکرار عبارت `RayanCode` (بدون در نظر گرفتن بزرگ یا کوچک بودن حروف) را در میان $n$ رشتهای که در ورودی دریافت میکنید، محاسبه کند.
# ورودی
در سطر اول ورودی، عدد صحیح و مثبت $n$ آمده است که تعداد رشتهها را نشان میدهد.
$$1 \leq n \leq 1000$$
در $n$ سطر بعدی، هر خط شامل یک رشته از حروف کوچک و بزرگ انگلیسی است که طول آن حداکثر $100$ کاراکتر است.
# خروجی
در تنها سطر خروجی، ارزش سهام رایانکد را حساب کنید.
## ورودی نمونه ۱
```
6
RayanCode
RayanCup
JavaRayan
rayanCode
RAYANCODE
rayancode
````
## خروجی نمونه ۱
```
4
````
رشتههای اول (`RayanCode`)، چهارم (`rayanCode`)، پنجم (`RAYANCODE`) و ششم (`rayancode`) باید شمارش شوند. بنابراین پاسخ $4$ است.
## ورودی نمونه ۲
```
10
R
Ra
Ray
Raya
Rayan
RayanC
RayanCo
RayanCod
RayanCode
RayanCodes
````
## خروجی نمونه ۲
```
1
````
فقط رشتهی `RayanCode` باید شمارش شود. بنابراین پاسخ $1$ است.
ارزش سهام در روز
+ محدودیت زمان: ۴ ثانیه (جاوا)
+ محدودیت حافظه: ۲۵۶ مگابایت
----------
*حال که ارزش سهام در هر روز را بدست آوردهایم میخواهیم با استفاده از یک روش، نوسانهای کوتاه مدت را کم کنیم تا بتوانیم تحلیل درستی از بازار داشته باشیم.*
![توضیح تصویر](https://quera.org/qbox/view/AEbH85iddF/B.svg)
فرض کنید ارزش سهام رایانکد در شهر رایان در $n$ روز مختلف بهترتیب $a_1, a_2, \dots, a_n$ باشد. همچنین عدد صحیح و مثبت $k$ بهعنوان بازهی زمانی مشخص شده است.
برای هر $k$ روز متوالی به ترتیب میانگین ورزندار ارزش سهام در آن $k$ روز را حساب میکنیم. برای وزندادن به ترتیب از اعداد $1$ تا $k$ برای روزها استفاده میکنیم و وزنها را بهترتیب صعودی برای ارزش سهامها از قدیم به جدید در نظر میگیریم.
برای مثال اگر $n = 7$ و $k = 4$ و ارزش سهامها بهصورت زیر باشد:
$$[100, 200, 100, 100, 300, 200, 500]$$
میانگین وزندار متحرک برای بازهی زمانی اول بهصورت زیر محاسبه میشود.
$$\frac{1 \times 100 + 2 \times 200 + 3 \times 100 + 4 \times 100}{1 + 2 + 3 + 4} = 120$$
حال از شما میخواهیم برنامهای بنویسید که با دریافت اعداد $n$، $k$ و ارزش سهامها در $n$ روز متوالی، میانگین وزندار متحرک را برای همهی بازههای زمانی به ترتیب محاسبه کند.
# ورودی
در سطر اول، دو عدد صحیح مثبت $n$ و $k$ داده میشود که تعداد روزها و بازه زمانی را مشخص میکند.
$$1 \leq k \leq n \leq 100 \, 000$$
در سطر دوم ورودی، $n$ عدد صحیح که با یک فاصله از هم جداشدهاند آمده و عدد $i$ام نشان دهندهی ارزش سهام در روز $i$ام است.
$$1 \leq a_i \leq 1000 \, 000$$
# خروجی
در $n - k + 1$ سطر، مقادیر میانگین وزندار متحرک برای هر بازه زمانی چاپ کنید. پاسخ شما زمانی پذیرفته میشود که اختلافش با جواب صحیح، حداکثر $10^{-3}$ باشد.
## ورودی نمونه ۱
```
7 4
100 200 100 100 300 200 500
````
## خروجی نمونه ۱
```
120.000000000
190.000000000
200.000000000
330.000000000
````
## ورودی نمونه ۲
```
3 1
1 2 3
````
## خروجی نمونه ۲
```
1.000000000
2.000000000
3.000000000
````
## ورودی نمونه ۳
```
4 2
8 3 6 3
````
## خروجی نمونه ۳
```
4.666666667
5.000000000
4.000000000
````
## ورودی نمونه ۴
```
3 3
1 2 3
````
## خروجی نمونه ۴
```
2.333333333
````
میانگین وزندار متحرک
+ محدودیت زمان: ۴ ثانیه (جاوا)
+ محدودیت حافظه: ۲۵۶ مگابایت
----------
*حال که توانستیم با روش میانگین وزندار متحرک، نوسانهای کوتاه مدت را تعدیل کنیم وقت تحلیل کردن است.*
![توضیح تصویر](https://quera.org/qbox/view/xQ9szKMe5L/C.svg)
شرکت رایان همافزا میخواهد یک سیستم ساده برای تحلیل معاملات پیادهسازی کند. شما باید در این سیستم از روی قیمت روزهای قبل و قیمت امروز، دربارهی خرید یا فروش و یا دست نگه داشتن، تصمیمگیری کنید.
بهطور دقیقتر فرض کنید در روز $k$ام هستیم و ارزش سهام در روزهای $1, 2, \dots, k$ را میدانیم. میخوهیم از روی ارزشها برای روز $k$ام تصمیم بگیریم.
مقدار $avg\_max\_half$ را برابر میانگین $\lceil\frac{k}{2}\rceil$ بزرگترین اعداد بین $a_1, a_2, \dots, a_k$ است.
مقدار $avg\_min\_half$ را برابر میانگین $\lceil\frac{k}{2}\rceil$ کوچکترین اعداد بین $a_1, a_2, \dots, a_k$ است.
برای تصمیم گیری در روز $k$ام اگر
+ مقدار $a_k$ بزرگتر اکید از $avg\_max\_half$ بود، این سهام را میخریم.
+ مقدار $a_k$ کوچکتر اکید از $avg\_min\_half$ بود، این سهام را میفروشیم.
+ هیچکدام از دو حالت بالا نبود دست نگه میداریم.
حال از شما میخواهیم برنامهای بنویسید که تصمیم ما در روزهای $k = 1, 2, \dots, n$ را مشخص کند.
# ورودی
در سطر اول ورودی، عدد صحیح $n$ آمده که تعداد روزها را نشان میدهد.
$$1 \leq n \leq 100 \, 000$$
در سطر دوم ورودی، $n$ عدد صحیح که با یک فاصله از هم جدا شدهاند، آمده که عدد $i$ام قیمت سهام در روز $i$ام را نشان میدهد.
$$1 \leq a_i \leq 10^9$$
# خروجی
برای هر روز یک رشته برابر `HOLD`، `SELL` یا `BUY` را چاپ کنید.
## ورودی نمونه ۱
```
4
71 35 89 12
````
## خروجی نمونه ۱
```
HOLD
HOLD
BUY
SELL
````
## ورودی نمونه ۲
```
8
70 50 20 40 80 60 10 30
````
## خروجی نمونه ۲
```
HOLD
HOLD
SELL
HOLD
BUY
HOLD
SELL
HOLD
````
تحلیل ارزش سهام
*بعد از تلاشهای بسیار و حل چالشهای قبلی، شما به شرکت رایان همافزار پیوستهاید!*
![توضیح تصویر](https://quera.org/qbox/view/0tbk999rWu/D.svg)
از شما خواسته شده است تا سیستم پرداختهای مختلفی را که مشتریان استفاده میکنند، طراحی کنید. این سیستم باید بهطور کامل پرداختهای مختلف از جمله پرداخت با کارت اعتباری، کیف پول دیجیتال و نقدی را مدیریت کند. جزئیات این تسک بهشرح زیر است.
هدف شما این است که سیستم پرداختهای مختلف را در یک محیط شبیهسازی کنید که از حسابهای بانکی مختلف برای انجام تراکنشها استفاده کند. پرداختها باید به حساب مقصد منتقل شوند و موجودی حسابها بهروزرسانی گردد. در صورت بروز هرگونه کمبود موجودی، باید پیغام خطای مناسب نمایش داده شود.
# پروژه اولیه
پروژه شما باید شامل چند کلاس اصلی باشد که سیستم پرداختها را مدیریت کنند. ساختار فایلهای پروژه بهصورت زیر است:
پروژهی اولیهی این سؤال را میتوانید از [این لینک](/contest/assignments/77534/download_problem_initial_project/268781/) دانلود کنید.
```
init.zip
├── Account.java
├── Payment.java
├── CreditCardPayment.java
├── DigitalWalletPayment.java
├── CashPayment.java
└── Main.java
```
در این ساختار، شما با چندین کلاس مختلف برای مدیریت پرداختها سر و کار دارید. `Account` نمایانگر حسابهای بانکی است که هر حساب میتواند یک موجودی داشته باشد. `Payment` کلاس پایهای است که پرداختها را مدیریت میکند. شما باید از این کلاس برای ساخت انواع مختلف پرداختها استفاده کنید.
# کلاس `Account`
کلاس `Account` نمایانگر یک حساب بانکی است. هر حساب دارای نام و موجودی است. همچنین، میتوان موجودی حساب را بررسی کرده و واریز یا برداشت از آن انجام داد. در این کلاس باید امکان برداشت از حسابها و مدیریت موجودی را داشته باشد. همچنین، در صورت تلاش برای برداشت بیشتر از موجودی، خطای کمبود موجودی به کاربر نمایش داده میشود.
# کلاس `Payment`
کلاس `Payment` یک کلاس انتزاعی است که روشهای پرداخت مختلف از جمله پرداخت با کارت اعتباری، کیف پول دیجیتال و پرداخت نقدی از آن ارث میبرند. این کلاس متدی به نام `processPayment()` دارد که فرایند هر پرداخت را انجام میدهد.
# پرداختها
شما باید سه روش پرداخت مختلف را پیادهسازی کنید:
+ پرداخت با کارت اعتباری (`CreditCardPayment`): این کلاس باید اطلاعات مربوط به کارت اعتباری را نگهداری کرده و عملیات برداشت از حساب و واریز به حساب مقصد را انجام دهد.
+ پرداخت با کیف پول دیجیتال (`DigitalWalletPayment`): این کلاس باید اطلاعات مربوط به کیف پول دیجیتال و ایمیل صاحب کیف پول را نگهداری کرده و مانند پرداخت کارت اعتباری، عملیات مالی را انجام دهد.
+ پرداخت نقدی (`CashPayment`): این کلاس باید میزان مبلغ نقدی را مشخص کرده و مشابه دو نوع دیگر، پرداخت را انجام دهد.
جزئیات پیادهسازی این سه کلاس در ادامه آورده شده است.
<details class="blue">
<summary>
**توضیحات کلاس `CreditCardPayment`**
</summary>
----------
پرداخت با کارت اعتباری باید شامل ویژگیها و متدهای زیر باشد:
+ `sourceAccount`: حساب مبدا که پرداخت از آن انجام میشود.
+ `destinationAccount`: حساب مقصد که پرداخت به آن انجام میشود.
+ `amount`: مبلغ پرداخت.
سازنده این کلاس بهصورت زیر است:
```java
public CreditCardPayment(Account sourceAccount, Account destinationAccount, int amount)
```
این سازنده باید ویژگیهای کلاس را مقداردهی کند.
متد `processPayment()` باید بررسی کند که حساب مبدا موجودی کافی برای پرداخت دارد. اگر موجودی کافی بود، مبلغ مشخصشده را از حساب مبدا کم کند و مبلغ را به حساب مقصد واریز کند.
در صورت موفقیتآمیز بودن پرداخت، پیام
```
Credit card payment processed: {amount}
```
برگردانده شود که در آن `{amount}`، یک عدد است که مقدار تراکنش را نشان میدهد.
همچنین اگر موجودی کافی نبود، پیغام خطای زیر را برگرداند:
```
Insufficient funds in account: {accountName}
```
</details>
<details class="blue">
<summary>
**توضیحات کلاس `DigitalWalletPayment`**
</summary>
----------
پرداخت با کیف پول دیجیتال باید شامل ویژگیها و متدهای زیر باشد:
+ `sourceAccount`: حساب مبدا که پرداخت از آن انجام میشود.
+ `destinationAccount`: حساب مقصد که پرداخت به آن انجام میشود.
+ `walletName`: نام کیف پول دیجیتال.
+ `email`: ایمیل صاحب کیف پول دیجیتال.
+ `amount`: مبلغ پرداخت.
سازنده این کلاس بهصورت زیر است:
```java
public DigitalWalletPayment(Account sourceAccount, Account destinationAccount, String walletName, String email, int amount)
```
این سازنده باید ویژگیهای کلاس را مقداردهی کند.
متد `processPayment()` باید بررسی کند که حساب مبدا موجودی کافی برای پرداخت دارد. اگر موجودی کافی بود مبلغ مشخصشده را از حساب مبدا کم کند و مبلغ را به حساب مقصد واریز کند. سپس یک پیام موفقیت به صورت زیر برگرداند:
```
Payment of {amount} processed via {walletName} for {email}.
```
و اگر موجودی کافی نبود، پیغام خطای زیر را برگرداند:
```
Insufficient funds in account: {accountName}
```
</details>
<details class="blue">
<summary>
**توضیحات کلاس `CashPayment`**
</summary>
----------
پرداخت نقدی باید شامل ویژگیها و متدهای زیر باشد:
+ `sourceAccount`: حساب مبدا که پرداخت از آن انجام میشود.
+ `destinationAccount`: حساب مقصد که پرداخت به آن انجام میشود.
+ `amount`: مبلغ پرداخت.
سازنده این کلاس بهصورت زیر است:
```java
public CashPayment(Account sourceAccount, Account destinationAccount, int amount)
```
این سازنده باید ویژگیهای کلاس را مقداردهی کند.
متد `processPayment()` باید بررسی کند که حساب مبدا موجودی کافی برای پرداخت دارد.
اگر موجودی کافی بود، مبلغ مشخصشده را از حساب مبدا کم کند، مبلغ را به حساب مقصد واریز کند و یک پیام موفقیت به صورت زیر برگرداند:
```
Cash payment of {amount} completed.
```
اگر موجودی کافی نبود، پیغام خطای زیر را برگرداند:
```
Insufficient funds in account: {accountName}
```
پس از پیادهسازی کامل، مطمئن شوید که برنامه شما تست میشود و تمامی سناریوها (مانند موفقیت در پرداخت یا خطای کمبود موجودی) به درستی مدیریت شدهاند.
</details>
# نکات
+ کد شما باید از **اصول شیگرایی و مدیریت خطا** برای پیادهسازی انواع مختلف پرداختها و حسابها استفاده کند.
+ برای هر کلاس متدهای `get` و `set` برای دسترسی به ویژگیهای آنها ایجاد کنید.
+ در صورتی که کاربر سعی کند مبلغی بیشتر از موجودی خود برداشت کند، باید پیغام خطای مناسب چاپ شود.
+ از طراحی کد بهگونهای استفاده کنید که بهراحتی بتوانید انواع جدید پرداختها را به سیستم اضافه کنید.
+ تمام این کلاسهای پرداخت باید از کلاس انتزاعی `Payment` ارثبری کنند و متد `processPayment()` را پیادهسازی نمایند.
+ برای مدیریت حسابها، از متدهای موجود در کلاس `Account` برای برداشت و واریز استفاده کنید.
# نمونه
در زیر نمونهای از نحوه استفاده از کلاسها برای انجام پرداختها آورده شده است:
```java Main.java
package org.example.solution;
public class Main {
public static void main(String[] args) {
Account account1 = new Account("Ali", 1000);
Account account2 = new Account("Sara", 2000);
System.out.println(account1.logBalance());
System.out.println(account2.logBalance());
Payment[] payments = new Payment[]{
new CreditCardPayment(account1, account2, 500),
new DigitalWalletPayment(account2, account1, "wallet1", "email@email.com", 300),
new CashPayment(account1, account2, 900) // این پرداخت باید خطای کمبود موجودی بدهد
};
for (Payment payment : payments) {
System.out.println(payment.processPayment());
}
System.out.println(account1.logBalance());
System.out.println(account2.logBalance());
}
}
```
در این مثال، حسابها مقدار اولیهای دارند و پرداختها بهصورت مختلف پردازش میشوند. خروجی باید بهصورت زیر باشد:
```
Account: Ali, Balance: 1000
Account: Sara, Balance: 2000
Credit card payment processed: 500
Payment of 300 processed via wallet1 for email@email.com.
Insufficient funds in account: Ali
Account: Ali, Balance: 800
Account: Sara, Balance: 2200
```
# آنچه باید ارسال کنید
پس از پیادهسازی سیستم، تنها فایلهای کلاسهای پیادهسازیشده را در قالب یک فایل فشرده ارسال کنید. از درج کردن `package` در فایلها پرهیز کنید. انتظار میرود باقی فایلها را تغییر ندهید و میتوانید فرض کنید که همین فایلها به همین شکل در زمان اجرای پروژه نیز در کنار برنامهی شما موجودند.
```
[your-solution-files-name].zip
├── CreditCardPayment.java
├── DigitalWalletPayment.java
└── CashPayment.java
```
پرداختها و حسابهای بانکی
در آستانهی زمستان، از شما میخواهیم سیستم الکترونیکی یک بخاری برقی را طراحی کنید که در حالتهای مختلف میتواند عمل کند و در شرایط همروند (*concurrent*) عملکرد مناسبی دارد!
![توضیح تصویر](https://quera.org/qbox/view/GwFmuC3FB4/E.svg)
این بخاری تنها یک دکمه دارد که قابل کلیک کردن توسط کاربر است و به واسطهی آن کاربر میتواند آن را روشن کند (*ON*)، خاموش کند (*OFF*) و یا به حالت کم مصرف ببرد (*DIM*). با کلیک کردن بر روی دکمهی بخاری، بخاری به حالت بعدی میرود. هر بخاری در زمان ساخت لیستی از حالتهای عملکردی را در قالب یک آرایه دریافت میکند و در زمان کلیک شدن بر روی دکمه به حالت بعدی میرود.
برای کلیک کردن روی دکمه، دو حالت خاص وجود دارد.
+ حالت خاص اول حالتی است که کاربر با فاصلهی بسیار کم از کلیک کردن قبلی مجدد کلیک کند. این حالت از این نظر حائز اهمیت است که دکمهی بخاری به گونهای طراحی شده که با نگه داشتن آن سیگنال کلیک چندین بار به برد اصلی ارسال میشود. در این حالت باید تنها اولین کلیک در نظر گرفته شود و باقی کلیکها در نظر گرفته نشوند.
+ حالت خاص دوم زمانی است که کاربر در زمان روشن (*ON* و یا *DIM*) پس از مدت خیلی زیادی اقدام به کلیک کردن دکمه کند. در این حالت فرض میشود که کاربر به سادگی میخواهد بخاری را خاموش کند و نمیخواهد حالت آن را تغییر دهد. برای این حالت، مطلوب این است که بخاری به حالت خاموش برود.
این بخاری برای تامین انرژی خود به یک منبع تغذیه نیاز دارد که این منبع تغذیه قابلیت تامین انرژی با توانهای متفاوت را دارد و تنها کافی است که بخاری مقدار توان مورد نیاز خود را به آن اعلام کند. بخاری به ازای هر حالت میداند که به چه توانی نیاز دارد و به همین ترتیب میتواند بر اساس حالت کنونیاش مقدار توان مورد نیاز خود را به منبع تغذیه اعلام کند.
پس از ساخت مدار بخاری، برای ارزیابی آن در حالتهای خاص شما متوجه میشوید که به یک ابزار کمکی نیاز دارید تا سناریوهای متفاوت را بتواند به راحتی شبیهسازی کند. هدف اصلی این شبیهساز، بررسی صحت جا به جا شدن بین حالتهای مختلف با وارد کردن تعداد کلیکهای همزمان در زمانهای مختلف است. مثلا یک سناریو میتواند به این شکل باشد که: ۳ کلیک در زمان $t=100ms$ و سپس ۱۰ کلیک در زمان $t=400ms$ که انتظار داریم کلیکهای اول از حالت خاموش به روشن و کلیکهای دوم بخاری را از حالت روشن به حالت کم مصرف تغییر حالت دهند.
# کلاسها
پیادهسازی این سوال در قالب چندین کلاس انجام میشود که شما باید آنها را پیادهسازی کنید. در این قسمت هر کلاس به شکل جداگانه توضیح داده میشود.
## کلاس *Heater*
```java
import java.time.Duration;
public class Heater {
private final Mode[] modes;
private final Duration timeout;
private final Duration closeThreshold;
private final PowerSource powerSource;
public Heater(Mode[] modes, Duration timeout, Duration closeThreshold, PowerSource powerSource) {
// TODO
}
public void click() {
// TODO
}
public Mode getCurrentMode() {
// TODO
}
}
```
این کلاس اولین کلاسی است که باید پیادهسازی کنید. برای پیادهسازی این کلاس لازم است سه متد شامل «سازنده»، «کلیک» و «گرفتن وضعیت فعلی» را پیادهسازی کنید.
+ سازنده: این کلاس تنها یک سازنده دارد که در آن باید معتبر بودن آرایهی *modes* را بررسی کنید و ویژگیهای کلاس را مطابق نیاز مقداردهی کنید.
+ کلیک: متد کلیک وظیفه اعمال سیگنال کلیک را بر عهده دارد. در نتیجهی اجرای این تابع باید (در صورت نیاز) حالت کنونی بخاری عوض شود و این موضوع به منبع تغذیه هم اعلام شود. همچنین مهم است که این متد به شکل ترد-سیف پیادهسازی شود چرا که ممکن است تعداد زیادی سیگنال کلیک به شکل همروند دریافت شوند.
### اعتبارسنجی حالتها
آرایهای که در ورودی سازنده دریافت میشود باید اعتبارسنجی شود تا اطمینان حاصل شود که ویژگیهای زیر را دارد. اگر هر یک از ویژگیهای گفته شده را نداشت باید یک استثنا از نوع `InvalidModesException` پرتاب شود.
+ همهی اعضای آرایه باید غیر `null` باشند.
+ عضو تکراری مجاز است اما دو عضو پشت سر هم نباید تکراری باشند.
+ وضعیت `OFF` تنها یک بار و آن هم دقیقا در اول آرایه مجاز است.
+ طول آرایه باید حداقل ۲ باشد. (یک حالت روشن یا نیمه روشن و یک حالت خاموش)
## اینام *Mode*
برای بازنمایی حالتهای مختلف کارکردی بخاری از یک اینام استفاده شده است. این اینام سه حالت متفاوت دارد که شامل روشن و خاموش و کممصرف هستند. با استفاده از متد `getPowerConsumption` میتوانید به توان مصرفی بخاری در هر یک از حالتها دست پیدا کنید که برای تنظیم منبع تغذیه ضروری است.
```java
public enum Mode {
OFF("Heater is off", 0),
ON("Heater is on", 100),
DIM("Heater is dimmed", 50);
private final String description;
private final int powerConsumption;
Mode(String description, int powerConsumption) {
this.description = description;
this.powerConsumption = powerConsumption;
}
public String getDescription() {
return this.description;
}
public int getPowerConsumption() {
return this.powerConsumption;
}
}
```
## اینترفیس *PowerSource*
```java
public interface PowerSource {
void set(int amount);
}
```
این اینترفیس یک متد دارد که مقدار توان مصرفی را دریافت میکند. این اینترفیس پیادهسازیهای مختلفی بسته به تست دارد که برای اطمینان از کارکرد صحیح بخاری استفاده میشوند. همچنین یک پیادهسازی سادهی آن نیز همراه با تستهای نمونه در اختیار شما قرار گرفته است.
نکته قابل توجه این است که نباید با مقدار تکراری متد`set` صدا زده شود و تنها زمانی مجاز به صدا کردن این متد هستید که یک مقدار (`amount`) جدید (متفاوت با قبلی) برای تنظیم کردن داشته باشید.
## کلاس *Simulator*
```java
import java.time.*;
import java.util.*;
public class Simulator {
public static record Event(Instant time, int clickCount, Mode oldMode, Mode newMode) {}
public static enum Strategy {
THREAD_POOL,
THREAD,
SEQUENTIAL;
}
private final Heater heater;
private final List<Event> events;
private final Strategy strategy;
public Simulator(Heater heater, Strategy strategy, List<Event> events) {
// TODO
}
public boolean run() {
// TODO
}
}
```
این کلاس همانطور که توضیح داده شد، وظیفه اعمال کلیک در تعدادها و زمانهای مختلف بر روی بخاری مورد تست را دارد. همانطور که مشخص است در سازندهی خود یک بخاری برای اعمال تستها دریافت میکند که در ادامه متد کلیک آن صدا زده میشود.
### رکورد `Event`
این رکورد برای نگهداری یک رویداد کلیک کردن استفاده میشود. یک رویداد شامل یک زمان است که با یک شی از نوع `Instant` نگهداری میشود. همچنین یک عدد شامل تعداد کلیکهای همزمان نیز دریافت میشود که مشخص میکند در زمان معین چه تعداد بار باید متد کلیک صدا زده شود.
در ادامه دو حالت وضعیت نیز دریافت میشود که وضعیت قبل از کلیک و وضعیت بعد از کلیک را مشخص میکند. این وضعیتها در زمان اجرای شبیهسازی باید با وضعیت واقعی (*actual*) بخاری تطبیق داده شوند تا دقیقا برابر هم باشند.
### اینام `Strategy`
در این برنامه، شبیهساز قادر به انجام شبیهسازی با سه مکانیسم متفاوت است.
+ سادهترین مکانیسم به شکل `SEQUENTIAL` است که در این حالت هیچ ترد جدیدی ساخته نمیشود و همهی عملیات در همان ترد `main` انجام میشود.
+ مکانیسم بعدی با کمک `THREAD`هاست که برای هر عملیات کلیک یک ترد مجزا ساخته میشود تا در زمان معین متد کلیک را اجرا کند.
+ در نهایت مکانیسم آخر با کمک `THREAD_POOL` است. در این روش با کمک یک تردپول، تسکهای مورد نظر ساخته و سابمیت میشوند. در این روش تعداد تردهای تردپول را برابر عدد ۵ (به شکل ثابت) بگذارید تا بیشتر از این ترد ساخته نشود.
توجه داشته باشید که برای پیادهسازی شبیهساز، باید تمام استراتژیها پیادهسازی شوند و قابل استفاده باشند در غیر این صورت به تناسب استراتژیهای درست پیادهسازی شده نمره دریافت میشود. انتخاب استراتژی نیز بر اساس استراتژی انتخاب شده در سازندهی شبیهسازی انجام میشود.
### متد `run`
این متد، متد اصلی شبیهساز است که شبیهسازی را بسته به استراتژی انتخاب شده اجرا می کند. این متد یک خروجی از نوع `boolean` دارد که نشان میدهد آیا شبیهسازی مطابق انتظار پیش رفت یا خیر. به بیان دیگر اگر همهی فرضیات «حالت قدیمی» و «حالت جدید»ها درست از آن در آمده باشند (که به معنی پیادهسازی صحیح بخاری است) مقدار `true` و در غیر این صورت مقدار `false` برمیگردد.
# پروژه اولیه
پروژهی اولیهی این سؤال را میتوانید از [این لینک](/contest/assignments/77534/download_problem_initial_project/268782/) دانلود کنید. این پروژه ساختاری مشابه زیر دارد:
```
initial.zip
├── Heater.java
├── InvalidModesException.java
├── Mode.java
├── PowerSource.java
├── SampleTest.java
└── Simulator.java
```
# آنچه باید آپلود کنید.
پس از پیادهسازی و اجرای تست نمونه (موجود در فایل `SampleTest.java`)، فایل های `Heater.java` و `Simulator.java` را در قالب یک فایل زیپ آپلود کنید. انتظار میرود باقی فایلها را تغییر ندهید و میتوانید فرض کنید که همین فایلها به همین شکل در زمان اجرای پروژه نیز در کنار برنامهی شما موجودند.